summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/miniport
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/miniport')
-rw-r--r--private/ntos/miniport/aha154x/aha154x.c4421
-rw-r--r--private/ntos/miniport/aha154x/aha154x.h472
-rw-r--r--private/ntos/miniport/aha154x/aha154x.rc90
-rw-r--r--private/ntos/miniport/aha154x/aha154x.sys0
-rw-r--r--private/ntos/miniport/aha154x/makefile7
-rw-r--r--private/ntos/miniport/aha154x/sources40
-rw-r--r--private/ntos/miniport/aha174x/aha174x.c2005
-rw-r--r--private/ntos/miniport/aha174x/aha174x.h270
-rw-r--r--private/ntos/miniport/aha174x/aha174x.rc12
-rw-r--r--private/ntos/miniport/aha174x/makefile6
-rw-r--r--private/ntos/miniport/aha174x/sources35
-rw-r--r--private/ntos/miniport/always/33c93.c827
-rw-r--r--private/ntos/miniport/always/33c93.h145
-rw-r--r--private/ntos/miniport/always/33c93s.h26
-rw-r--r--private/ntos/miniport/always/adapters.c94
-rw-r--r--private/ntos/miniport/always/adapters.h63
-rw-r--r--private/ntos/miniport/always/always.rc12
-rw-r--r--private/ntos/miniport/always/api.h76
-rw-r--r--private/ntos/miniport/always/apiscsi.h170
-rw-r--r--private/ntos/miniport/always/debug.h25
-rw-r--r--private/ntos/miniport/always/environ.h89
-rw-r--r--private/ntos/miniport/always/envlib.h184
-rw-r--r--private/ntos/miniport/always/in2000.c801
-rw-r--r--private/ntos/miniport/always/in2000.h31
-rw-r--r--private/ntos/miniport/always/in2000s.h28
-rw-r--r--private/ntos/miniport/always/intrlreq.c359
-rw-r--r--private/ntos/miniport/always/intsrb.h100
-rw-r--r--private/ntos/miniport/always/makefile6
-rw-r--r--private/ntos/miniport/always/ntenv.c80
-rw-r--r--private/ntos/miniport/always/ntenv.h119
-rw-r--r--private/ntos/miniport/always/ntmgr.c547
-rw-r--r--private/ntos/miniport/always/rqm.c569
-rw-r--r--private/ntos/miniport/always/rqm.h330
-rw-r--r--private/ntos/miniport/always/scsi.c400
-rw-r--r--private/ntos/miniport/always/sources36
-rw-r--r--private/ntos/miniport/atapi/atapi.c7983
-rw-r--r--private/ntos/miniport/atapi/atapi.h857
-rw-r--r--private/ntos/miniport/atapi/atapi.rc12
-rw-r--r--private/ntos/miniport/atapi/intel.c37
-rw-r--r--private/ntos/miniport/atapi/intel.h10
-rw-r--r--private/ntos/miniport/atapi/makefile6
-rw-r--r--private/ntos/miniport/atapi/sources42
-rw-r--r--private/ntos/miniport/buslogic/buslogic.c3181
-rw-r--r--private/ntos/miniport/buslogic/buslogic.h435
-rw-r--r--private/ntos/miniport/buslogic/buslogic.rc12
-rw-r--r--private/ntos/miniport/buslogic/makefile6
-rw-r--r--private/ntos/miniport/buslogic/sources35
-rw-r--r--private/ntos/miniport/compaq/cpqarray.c3819
-rw-r--r--private/ntos/miniport/compaq/cpqarray.h412
-rw-r--r--private/ntos/miniport/compaq/cpqarray.rc13
-rw-r--r--private/ntos/miniport/compaq/cpqsczmp.h211
-rw-r--r--private/ntos/miniport/compaq/cpqsmngr.h509
-rw-r--r--private/ntos/miniport/compaq/makefile6
-rw-r--r--private/ntos/miniport/compaq/pcibios.h27
-rw-r--r--private/ntos/miniport/compaq/scsireg.h223
-rw-r--r--private/ntos/miniport/compaq/sources39
-rw-r--r--private/ntos/miniport/dell/delldsa.c1767
-rw-r--r--private/ntos/miniport/dell/delldsa.h210
-rw-r--r--private/ntos/miniport/dell/delldsa.rc12
-rw-r--r--private/ntos/miniport/dell/makefile6
-rw-r--r--private/ntos/miniport/dell/sources40
-rw-r--r--private/ntos/miniport/dirs56
-rw-r--r--private/ntos/miniport/dtc/dtc329x.c2588
-rw-r--r--private/ntos/miniport/dtc/dtc329x.h399
-rw-r--r--private/ntos/miniport/dtc/dtc329x.rc12
-rw-r--r--private/ntos/miniport/dtc/makefile6
-rw-r--r--private/ntos/miniport/dtc/sources9
-rw-r--r--private/ntos/miniport/mitsumi/makefile6
-rw-r--r--private/ntos/miniport/mitsumi/mitsumi.c3365
-rw-r--r--private/ntos/miniport/mitsumi/mitsumi.h145
-rw-r--r--private/ntos/miniport/mitsumi/mitsumi.rc12
-rw-r--r--private/ntos/miniport/mitsumi/sources19
-rw-r--r--private/ntos/miniport/mylex/dac960/d960api.h56
-rw-r--r--private/ntos/miniport/mylex/dac960/dac960nt.c4152
-rw-r--r--private/ntos/miniport/mylex/dac960/dac960nt.h428
-rw-r--r--private/ntos/miniport/mylex/dac960/dac960nt.rc38
-rw-r--r--private/ntos/miniport/mylex/dac960/dacioctl.c525
-rw-r--r--private/ntos/miniport/mylex/dac960/dmc960nt.h87
-rw-r--r--private/ntos/miniport/mylex/dac960/makefile6
-rw-r--r--private/ntos/miniport/mylex/dac960/raidapi.h277
-rw-r--r--private/ntos/miniport/mylex/dac960/raiddefs.h34
-rw-r--r--private/ntos/miniport/mylex/dac960/sources13
-rw-r--r--private/ntos/miniport/mylex/dce376/dce376nt.c2741
-rw-r--r--private/ntos/miniport/mylex/dce376/dce376nt.h383
-rw-r--r--private/ntos/miniport/mylex/dce376/dce376nt.rc12
-rw-r--r--private/ntos/miniport/mylex/dce376/makefile6
-rw-r--r--private/ntos/miniport/mylex/dce376/sources12
-rw-r--r--private/ntos/miniport/mylex/dirs25
-rw-r--r--private/ntos/miniport/mylex/dmc960/dac960nt.c2093
-rw-r--r--private/ntos/miniport/mylex/dmc960/dac960nt.h371
-rw-r--r--private/ntos/miniport/mylex/dmc960/dac960nt.rc12
-rw-r--r--private/ntos/miniport/mylex/dmc960/makefile6
-rw-r--r--private/ntos/miniport/mylex/dmc960/sources42
-rw-r--r--private/ntos/miniport/ncr53c94/i386/ncr53c94.c37
-rw-r--r--private/ntos/miniport/ncr53c94/makefile6
-rw-r--r--private/ntos/miniport/ncr53c94/mcadefs.h78
-rw-r--r--private/ntos/miniport/ncr53c94/ncr53c9x.c5616
-rw-r--r--private/ntos/miniport/ncr53c94/ncr53c9x.h430
-rw-r--r--private/ntos/miniport/ncr53c94/ncr53c9x.rc12
-rw-r--r--private/ntos/miniport/ncr53c94/sources36
-rw-r--r--private/ntos/miniport/oliscsi/makefile6
-rw-r--r--private/ntos/miniport/oliscsi/oliesc1.c2364
-rw-r--r--private/ntos/miniport/oliscsi/oliesc1.h363
-rw-r--r--private/ntos/miniport/oliscsi/oliesc2.c6108
-rw-r--r--private/ntos/miniport/oliscsi/oliesc2.h1400
-rw-r--r--private/ntos/miniport/oliscsi/oliscsi.rc12
-rw-r--r--private/ntos/miniport/oliscsi/sources35
-rw-r--r--private/ntos/miniport/qlogic/isp_fw.c1245
-rw-r--r--private/ntos/miniport/qlogic/makedsk.bat4
-rw-r--r--private/ntos/miniport/qlogic/makefile7
-rw-r--r--private/ntos/miniport/qlogic/oemsetup.inf571
-rw-r--r--private/ntos/miniport/qlogic/qlisp.c3050
-rw-r--r--private/ntos/miniport/qlogic/qlisp.h608
-rw-r--r--private/ntos/miniport/qlogic/qlisp.rc12
-rw-r--r--private/ntos/miniport/qlogic/sources41
-rw-r--r--private/ntos/miniport/qlogic/txtsetup.oem97
-rw-r--r--private/ntos/miniport/scsiwdl/dirs25
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/cam.h309
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/camcore.h140
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/camglbls.h59
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/intercam.h71
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/makefile6
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.c1640
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.h109
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.rc12
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/sources36
-rw-r--r--private/ntos/miniport/scsiwdl/ncrcam/typedefs.h30
-rw-r--r--private/ntos/miniport/spock/makefile6
-rw-r--r--private/ntos/miniport/spock/mca.h245
-rw-r--r--private/ntos/miniport/spock/sources36
-rw-r--r--private/ntos/miniport/spock/spock.c2150
-rw-r--r--private/ntos/miniport/spock/spock.rc12
-rw-r--r--private/ntos/miniport/symbios/dirs26
-rw-r--r--private/ntos/miniport/symbios/symc810/makefile6
-rw-r--r--private/ntos/miniport/symbios/symc810/scrpt810.asm667
-rw-r--r--private/ntos/miniport/symbios/symc810/scrpt810.h273
-rw-r--r--private/ntos/miniport/symbios/symc810/sources39
-rw-r--r--private/ntos/miniport/symbios/symc810/symc810.c9200
-rw-r--r--private/ntos/miniport/symbios/symc810/symc810.h101
-rw-r--r--private/ntos/miniport/symbios/symc810/symc810.rc41
-rw-r--r--private/ntos/miniport/symbios/symc810/symnvm.h325
-rw-r--r--private/ntos/miniport/symbios/symc810/symscam.h107
-rw-r--r--private/ntos/miniport/symbios/symc810/symsiop.h452
-rw-r--r--private/ntos/miniport/trantor/dirs25
-rw-r--r--private/ntos/miniport/trantor/include/card.h58
-rw-r--r--private/ntos/miniport/trantor/include/cardlib.h29
-rw-r--r--private/ntos/miniport/trantor/include/cardt128.h108
-rw-r--r--private/ntos/miniport/trantor/include/cardt13b.h149
-rw-r--r--private/ntos/miniport/trantor/include/cardt160.h133
-rw-r--r--private/ntos/miniport/trantor/include/cardt338.h84
-rw-r--r--private/ntos/miniport/trantor/include/cardt348.h94
-rw-r--r--private/ntos/miniport/trantor/include/cardt358.h115
-rw-r--r--private/ntos/miniport/trantor/include/cardtmv1.h112
-rw-r--r--private/ntos/miniport/trantor/include/cardtype.h48
-rw-r--r--private/ntos/miniport/trantor/include/ep3c.h78
-rw-r--r--private/ntos/miniport/trantor/include/findpas.h319
-rw-r--r--private/ntos/miniport/trantor/include/mv101.h62
-rw-r--r--private/ntos/miniport/trantor/include/n5380.h148
-rw-r--r--private/ntos/miniport/trantor/include/n53c400.h59
-rw-r--r--private/ntos/miniport/trantor/include/p3c.h75
-rw-r--r--private/ntos/miniport/trantor/include/parallel.h43
-rw-r--r--private/ntos/miniport/trantor/include/pc9010.h92
-rw-r--r--private/ntos/miniport/trantor/include/port.h21
-rw-r--r--private/ntos/miniport/trantor/include/portio.h36
-rw-r--r--private/ntos/miniport/trantor/include/portmem.h25
-rw-r--r--private/ntos/miniport/trantor/include/scsifnc.h42
-rw-r--r--private/ntos/miniport/trantor/include/scsiport.h40
-rw-r--r--private/ntos/miniport/trantor/include/sl386.h202
-rw-r--r--private/ntos/miniport/trantor/include/status.h58
-rw-r--r--private/ntos/miniport/trantor/include/t128.h79
-rw-r--r--private/ntos/miniport/trantor/include/t338.h68
-rw-r--r--private/ntos/miniport/trantor/include/trantor.h28
-rw-r--r--private/ntos/miniport/trantor/include/typedefs.h274
-rw-r--r--private/ntos/miniport/trantor/source/cardt128.c377
-rw-r--r--private/ntos/miniport/trantor/source/cardt13b.c299
-rw-r--r--private/ntos/miniport/trantor/source/cardt160.c273
-rw-r--r--private/ntos/miniport/trantor/source/cardt338.c246
-rw-r--r--private/ntos/miniport/trantor/source/cardt348.c220
-rw-r--r--private/ntos/miniport/trantor/source/cardtmv1.c266
-rw-r--r--private/ntos/miniport/trantor/source/cardutil.c110
-rw-r--r--private/ntos/miniport/trantor/source/ep3c.c1418
-rw-r--r--private/ntos/miniport/trantor/source/ep3c2.asm526
-rw-r--r--private/ntos/miniport/trantor/source/findpas.c303
-rw-r--r--private/ntos/miniport/trantor/source/mv101.c617
-rw-r--r--private/ntos/miniport/trantor/source/n5380.c970
-rw-r--r--private/ntos/miniport/trantor/source/n53c400.c525
-rw-r--r--private/ntos/miniport/trantor/source/p3c.c1069
-rw-r--r--private/ntos/miniport/trantor/source/parallel.c86
-rw-r--r--private/ntos/miniport/trantor/source/pc9010.c851
-rw-r--r--private/ntos/miniport/trantor/source/port.c62
-rw-r--r--private/ntos/miniport/trantor/source/portio.c87
-rw-r--r--private/ntos/miniport/trantor/source/portmem.c67
-rw-r--r--private/ntos/miniport/trantor/source/scsifnc.c586
-rw-r--r--private/ntos/miniport/trantor/source/scsiport.c181
-rw-r--r--private/ntos/miniport/trantor/source/sl386.c285
-rw-r--r--private/ntos/miniport/trantor/source/t128.c483
-rw-r--r--private/ntos/miniport/trantor/source/t338.c763
-rw-r--r--private/ntos/miniport/trantor/winnt/dirs27
-rw-r--r--private/ntos/miniport/trantor/winnt/include/osdefs.h15
-rw-r--r--private/ntos/miniport/trantor/winnt/source/trantor.c1556
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/card.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/card.h1
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/cardutil.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/makefile6
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/n5380.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/port.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/portmem.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/scsifnc.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/sources35
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/t128.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/t128.rc12
-rw-r--r--private/ntos/miniport/trantor/winnt/t128/trantor.c2
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/card.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/card.h1
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/cardutil.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/makefile6
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/n5380.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/n53c400.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/portio.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/scsifnc.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/sources35
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/t13b.rc12
-rw-r--r--private/ntos/miniport/trantor/winnt/t13b/trantor.c2
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/card.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/card.h1
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/cardutil.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/makefile6
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/n5380.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/pc9010.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/portio.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/scsifnc.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/sources39
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/t160.rc12
-rw-r--r--private/ntos/miniport/trantor/winnt/t160/trantor.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/card.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/card.h1
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/cardutil.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/makefile6
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/n5380.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/p3c.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/parallel.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/portio.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/scsifnc.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/sources39
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/t338.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/t338.rc12
-rw-r--r--private/ntos/miniport/trantor/winnt/t338/trantor.c2
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/card.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/card.h1
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/cardutil.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/makefile6
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/n5380.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/p3c.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/parallel.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/portio.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/scsifnc.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/sources39
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/t348.rc12
-rw-r--r--private/ntos/miniport/trantor/winnt/t348/trantor.c2
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/card.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/cardutil.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/ep3c.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/makefile6
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/n5380.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/n53c400.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/parallel.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/portio.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/scsifnc.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/sl386.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/sources40
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/t358.rc12
-rw-r--r--private/ntos/miniport/trantor/winnt/t358/trantor.c1
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/card.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/card.h1
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/cardutil.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/findpas.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/makefile6
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/mv101.c4
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/n5380.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/port.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/portio.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/scsifnc.c3
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/sources35
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/tmv1.rc12
-rw-r--r--private/ntos/miniport/trantor/winnt/tmv1/trantor.c2
-rw-r--r--private/ntos/miniport/ultra124/makefile6
-rw-r--r--private/ntos/miniport/ultra124/sources35
-rw-r--r--private/ntos/miniport/ultra124/ultra124.c1617
-rw-r--r--private/ntos/miniport/ultra124/ultra124.h396
-rw-r--r--private/ntos/miniport/ultra124/ultra124.rc11
-rw-r--r--private/ntos/miniport/ultra14f/makefile6
-rw-r--r--private/ntos/miniport/ultra14f/sources35
-rw-r--r--private/ntos/miniport/ultra14f/ultra14f.c1561
-rw-r--r--private/ntos/miniport/ultra14f/ultra14f.h223
-rw-r--r--private/ntos/miniport/ultra14f/ultra14f.rc12
-rw-r--r--private/ntos/miniport/ultra24f/makefile6
-rw-r--r--private/ntos/miniport/ultra24f/sources35
-rw-r--r--private/ntos/miniport/ultra24f/ultra24f.c1401
-rw-r--r--private/ntos/miniport/ultra24f/ultra24f.h222
-rw-r--r--private/ntos/miniport/ultra24f/ultra24f.rc12
-rw-r--r--private/ntos/miniport/wd33c93/makefile6
-rw-r--r--private/ntos/miniport/wd33c93/maynard.h173
-rw-r--r--private/ntos/miniport/wd33c93/s3scsi.h145
-rw-r--r--private/ntos/miniport/wd33c93/sources37
-rw-r--r--private/ntos/miniport/wd33c93/vendor.h26
-rw-r--r--private/ntos/miniport/wd33c93/wd33c93.c5946
-rw-r--r--private/ntos/miniport/wd33c93/wd33c93.h305
-rw-r--r--private/ntos/miniport/wd33c93/wd33c93.rc12
-rw-r--r--private/ntos/miniport/wd7000ex/makefile6
-rw-r--r--private/ntos/miniport/wd7000ex/sources35
-rw-r--r--private/ntos/miniport/wd7000ex/wd7000ex.c1684
-rw-r--r--private/ntos/miniport/wd7000ex/wd7000ex.h218
-rw-r--r--private/ntos/miniport/wd7000ex/wd7000ex.rc12
313 files changed, 118283 insertions, 0 deletions
diff --git a/private/ntos/miniport/aha154x/aha154x.c b/private/ntos/miniport/aha154x/aha154x.c
new file mode 100644
index 000000000..952d5a104
--- /dev/null
+++ b/private/ntos/miniport/aha154x/aha154x.c
@@ -0,0 +1,4421 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ aha154x.c
+
+Abstract:
+
+ This is the port driver for the Adaptec 1540B SCSI Adapter.
+
+Author:
+
+ Mike Glass
+ Tuong Hoang (Adaptec)
+ Renato Maranon (Adaptec)
+ Bill Williams (Adaptec)
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "aha154x.h" // includes scsi.h
+
+//
+// This conditionally compiles in the code to force the DMA transfer speed
+// to 5.0.
+//
+
+#define FORCE_DMA_SPEED 1
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+
+typedef struct _NONCACHED_EXTENSION {
+
+ //
+ // Physical base address of mailboxes
+ //
+
+ ULONG MailboxPA;
+
+ //
+ // Mailboxes
+ //
+
+ MBO Mbo[MB_COUNT];
+ MBI Mbi[MB_COUNT];
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ //
+ // NonCached extension
+ //
+
+ PNONCACHED_EXTENSION NoncachedExtension;
+
+ //
+ // Adapter parameters
+ //
+
+ PBASE_REGISTER BaseIoAddress;
+
+ //
+ // Host Target id.
+ //
+
+ UCHAR HostTargetId;
+
+ //
+ // Old in\out box indexes.
+ //
+
+ UCHAR MboIndex;
+
+ UCHAR MbiIndex;
+
+ //
+ // Pending request.
+ //
+
+ BOOLEAN PendingRequest;
+
+ //
+ // Bus on time to use.
+ //
+
+ UCHAR BusOnTime;
+
+ //
+ // Scatter gather command
+ //
+
+ UCHAR CcbScatterGatherCommand;
+
+ //
+ // Non scatter gather command
+ //
+
+ UCHAR CcbInitiatorCommand;
+
+ //
+ // Don't send CDB's longer than this to any device on the bus
+ // Ignored if the value is 0
+ //
+
+ UCHAR MaxCdbLength;
+
+ //
+ // Real Mode adapter config info
+ //
+
+ RM_CFG RMSaveState;
+
+ #if defined(_SCAM_ENABLED)
+ //
+ // SCAM boolean, set to TRUE if miniport must control SCAM operation.
+ //
+ BOOLEAN PerformScam;
+ #endif
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+//
+// Logical unit extension
+//
+
+typedef struct _HW_LU_EXTENSION {
+ PSCSI_REQUEST_BLOCK CurrentSrb;
+} HW_LU_EXTENSION, *PHW_LU_EXTENSION;
+
+
+//
+// Function declarations
+//
+// Functions that start with 'A154x' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+A154xDetermineInstalled(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PSCAN_CONTEXT Context,
+ OUT PBOOLEAN Again
+ );
+
+
+VOID
+A154xClaimBIOSSpace(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN PBASE_REGISTER baseIoAddress,
+ IN PSCAN_CONTEXT Context,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ );
+
+ULONG
+A154xFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PSCAN_CONTEXT Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+
+BOOLEAN
+A154xAdapterState(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN BOOLEAN SaveState
+ );
+
+
+BOOLEAN
+A154xHwInitialize(
+ IN PVOID DeviceExtension
+ );
+
+#if defined(_SCAM_ENABLED)
+//
+// Issues SCAM command to HA
+//
+BOOLEAN
+PerformScamProtocol(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+#endif
+
+BOOLEAN
+A154xStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+A154xInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+A154xResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+VOID
+GetHostAdapterBoardId (
+ IN PVOID HwDeviceExtension,
+ OUT PUCHAR BoardId
+ );
+
+//
+// This function is called from A154xStartIo.
+//
+
+VOID
+BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BuildCcb.
+//
+
+VOID
+BuildSdl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from A154xInitialize.
+//
+
+BOOLEAN
+AdapterPresent(
+ IN PVOID HwDeviceExtension
+ );
+
+//
+// This function is called from A154xInterrupt.
+//
+
+UCHAR
+MapError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCCB Ccb
+ );
+
+BOOLEAN
+ReadCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR DataByte,
+ IN BOOLEAN TimeOutFlag
+ );
+
+BOOLEAN
+WriteCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR AdapterCommand,
+ IN BOOLEAN LogError
+ );
+
+BOOLEAN
+WriteDataRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR DataByte
+ );
+
+BOOLEAN
+ScatterGatherSupported (
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension
+ );
+
+BOOLEAN
+SpinForInterrupt(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN TimeOutFlag
+ );
+
+BOOLEAN SendUnlockCommand(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR locktype
+ );
+
+BOOLEAN UnlockMailBoxes(
+ IN PVOID HwDeviceExtension
+ );
+
+ULONG
+AhaParseArgumentString(
+ IN PCHAR String,
+ IN PCHAR KeyWord
+ );
+
+//
+// This function determines whether adapter is an AMI
+//
+BOOLEAN
+A4448IsAmi(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ ULONG portNumber
+ );
+
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ SCAN_CONTEXT context;
+ ULONG isaStatus;
+ ULONG mcaStatus;
+ ULONG i;
+
+ DebugPrint((1,"\n\nSCSI Adaptec 154X MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = A154xHwInitialize;
+ hwInitializationData.HwResetBus = A154xResetBus;
+ hwInitializationData.HwStartIo = A154xStartIo;
+ hwInitializationData.HwInterrupt = A154xInterrupt;
+ hwInitializationData.HwFindAdapter = A154xFindAdapter;
+ hwInitializationData.HwAdapterState = A154xAdapterState;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
+
+ //
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Isa;
+ hwInitializationData.NumberOfAccessRanges = 2;
+
+ //
+ // Ask for SRB extensions for CCBs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(CCB);
+
+ //
+ // The adapter count is used by the find adapter routine to track how
+ // which adapter addresses have been tested.
+ //
+
+ context.adapterCount = 0;
+ context.biosScanStart = 0;
+
+ isaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &context);
+
+ //
+ // Now try to configure for the Mca bus.
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = MicroChannel;
+ context.adapterCount = 0;
+ context.biosScanStart = 0;
+ mcaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &context);
+
+ //
+ // Return the smaller status.
+ //
+
+ return(mcaStatus < isaStatus ? mcaStatus : isaStatus);
+
+} // end A154xEntry()
+
+
+ULONG
+A154xFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PSCAN_CONTEXT Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - Register base address
+ ConfigInfo - Configuration information structure describing HBA
+ This structure is defined in PORT.H.
+
+Return Value:
+
+ ULONG
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG length;
+ ULONG status;
+ UCHAR adapterTid;
+ UCHAR dmaChannel;
+ UCHAR irq;
+ UCHAR bit;
+ UCHAR hostAdapterId[4];
+
+#if defined(_SCAM_ENABLED)
+ UCHAR temp, i;
+ UCHAR BoardID;
+ UCHAR EepromData;
+#endif
+
+ //
+ // Determine if there are any adapters installed. Determine installed
+ // will initialize the BaseIoAddress if an adapter is found.
+ //
+
+ status = A154xDetermineInstalled(deviceExtension,
+ ConfigInfo,
+ Context,
+ Again);
+
+ //
+ // If there are no adapters found then return.
+ //
+
+ if (status != SP_RETURN_FOUND) {
+ return(status);
+ }
+
+ //
+ // Issue adapter command to get IRQ, DMA channel, and adapter SCSI ID.
+ // But first, check for PnP non-default values. If any of these values
+ // are default, then we do 'em all to save code space, since the same
+ // command is used.
+ //
+ // Returns 3 data bytes:
+ //
+ // Byte 0 Dma Channel
+ //
+ // Byte 1 Interrupt Channel
+ //
+ // Byte 2 Adapter SCSI ID
+ //
+
+ if (((ConfigInfo->DmaChannel+1) == 0) || // default DMA channel ?
+ (ConfigInfo->BusInterruptLevel == 0) || // default IRQ ?
+ ((ConfigInfo->InitiatorBusId[0]+1) == 0) // default adapter ID ?
+ ) {
+
+
+
+ if (!WriteCommandRegister(deviceExtension, AC_RET_CONFIGURATION_DATA, TRUE)) {
+ DebugPrint((1,"A154xFindAdapter: Get configuration data command failed\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Determine DMA channel.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&dmaChannel,TRUE)) {
+ DebugPrint((1,"A154xFindAdapter: Can't read dma channel\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ if (ConfigInfo->AdapterInterfaceType != MicroChannel) {
+
+ WHICH_BIT(dmaChannel,bit);
+
+ ConfigInfo->DmaChannel = bit;
+
+ DebugPrint((2,"A154xFindAdapter: DMA channel is %x\n",
+ ConfigInfo->DmaChannel));
+
+ } else {
+ ConfigInfo->InterruptMode = LevelSensitive;
+ }
+
+ //
+ // Determine hardware interrupt vector.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&irq,TRUE)) {
+ DebugPrint((1,"A154xFindAdapter: Can't read adapter irq\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ WHICH_BIT(irq, bit);
+
+ ConfigInfo->BusInterruptLevel = (UCHAR) 9 + bit;
+
+ //
+ // Determine what SCSI bus id the adapter is on.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&adapterTid,TRUE)) {
+ DebugPrint((1,"A154xFindAdapter: Can't read adapter SCSI id\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Wait for HACC interrupt.
+ //
+
+ SpinForInterrupt(deviceExtension,FALSE); // eddy
+
+ //
+ // Use PnP fields
+ //
+ } else {
+ adapterTid = ConfigInfo->InitiatorBusId[0];
+ }
+
+ //
+ // Set number of buses.
+ //
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InitiatorBusId[0] = adapterTid;
+ deviceExtension->HostTargetId = adapterTid;
+
+ //
+ // Set default CCB command to scatter/gather with residual counts.
+ // If the adapter rejects this command, then set the command
+ // to scatter/gather without residual.
+ //
+
+ deviceExtension->CcbScatterGatherCommand = SCATTER_GATHER_COMMAND;
+
+ if ((ConfigInfo->MaximumTransferLength+1) == 0)
+ ConfigInfo->MaximumTransferLength = MAX_TRANSFER_SIZE;
+
+ //
+ // NumberOfPhysicalBreaks incorrectly defined.
+ // Must be set to MAX_SG_DESCRIPTORS.
+ //
+
+ if ((ConfigInfo->NumberOfPhysicalBreaks+1) == 0)
+ ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_DESCRIPTORS;
+ //ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_DESCRIPTORS - 1;
+
+ if (!ConfigInfo->ScatterGather)
+ ConfigInfo->ScatterGather = ScatterGatherSupported(HwDeviceExtension);
+
+ if (!ConfigInfo->ScatterGather) {
+ //ConfigInfo->NumberOfPhysicalBreaks = 1;
+ DebugPrint((1,"Aha154x: Scatter/Gather not supported!\n"));
+ }
+
+ ConfigInfo->Master = TRUE;
+
+ //
+ // Allocate a Noncached Extension to use for mail boxes.
+ //
+
+ deviceExtension->NoncachedExtension =
+ ScsiPortGetUncachedExtension(deviceExtension,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ if (deviceExtension->NoncachedExtension == NULL) {
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 7 << 8);
+
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // Convert virtual to physical mailbox address.
+ //
+
+ deviceExtension->NoncachedExtension->MailboxPA =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension->Mbo,
+ &length));
+
+ //
+ // Set default bus on time. Then check for an override parameter.
+ //
+
+ deviceExtension->BusOnTime = 0x07;
+ if (ArgumentString != NULL) {
+
+ length = AhaParseArgumentString(ArgumentString, "BUSONTIME");
+
+ //
+ // Validate that the new bus on time is reasonable before attempting
+ // to set it.
+ //
+
+ if (length >= 2 && length <= 15) {
+
+ deviceExtension->BusOnTime = (UCHAR) length;
+ DebugPrint((1,"A154xFindAdapter: Setting bus on time: %ld\n", length));
+ }
+ }
+
+ //
+ // Set maximum cdb length to zero unless the user has overridden the value
+ //
+
+ if( ArgumentString != NULL) {
+
+ length = AhaParseArgumentString(ArgumentString, "MAXCDBLENGTH");
+
+ //
+ // Validate the maximum cdb length before attempting to set it
+ //
+
+ if (length >= 6 && length <= 20) {
+
+ deviceExtension->MaxCdbLength = (UCHAR) length;
+ DebugPrint((1, "A154xFindAdapter: Setting maximum cdb length: %ld\n", length));
+ }
+
+ } else {
+
+ GetHostAdapterBoardId(HwDeviceExtension,&hostAdapterId[0]);
+
+ if(hostAdapterId[BOARD_ID] < 'E') {
+
+ deviceExtension->MaxCdbLength = 10;
+ DebugPrint((1, "A154xFindAdapter: Old firmware - Setting maximum cdb length: %ld\n", length));
+
+ } else {
+
+ length = deviceExtension->MaxCdbLength = 0;
+ DebugPrint((1, "A154xFindAdapter: Setting maximum cdb length: %ld\n", length));
+
+ }
+
+ }
+
+#if defined(_SCAM_ENABLED)
+ //
+ // Get info to determine if miniport must issues SCAM command.
+ //
+ DebugPrint((1,"A154x => Start SCAM enabled determination.", length));
+
+ deviceExtension->PerformScam = FALSE;
+
+ do {
+ //
+ // Fall through do loop if a command fails.
+ //
+ if (!WriteCommandRegister(deviceExtension,AC_ADAPTER_INQUIRY,FALSE)) {
+ break;
+ }
+
+ if ((ReadCommandRegister(deviceExtension,&BoardID,TRUE)) == FALSE) {
+ break;
+ }
+
+ //
+ // Don't care about three other bytes
+ //
+ for (i=0; i < 0x3; i++) {
+ if ((ReadCommandRegister(deviceExtension,&temp,TRUE)) == FALSE) {
+ break;
+ }
+ }
+
+ SpinForInterrupt(HwDeviceExtension,FALSE);
+
+ //
+ // Check to see that three 'extra bytes' were read.
+ //
+ if (i != 0x3)
+ break;
+
+ if (BoardID >= 'F') {
+
+ if (!WriteCommandRegister(deviceExtension,AC_RETURN_EEPROM,FALSE)) {
+ break;
+ }
+
+ //
+ // Flag Byte => set returns configured options
+ //
+ if (!WriteCommandRegister(deviceExtension,0x01,FALSE)) {
+ break;
+ }
+ //
+ // Data length => reading one byte.
+ //
+ if (!WriteCommandRegister(deviceExtension,0x01,FALSE)) {
+ break;
+
+ }
+ //
+ // Data offset => read SCSI_BUS_CONTROL_FLAG
+ //
+ if (!WriteCommandRegister(deviceExtension,SCSI_BUS_CONTROL_FLAG,FALSE)) {
+ break;
+ }
+
+ //
+ // Read it!
+ //
+ if ((ReadCommandRegister(deviceExtension,&EepromData,TRUE)) == FALSE) {
+ break;
+ }
+
+ SpinForInterrupt(HwDeviceExtension,FALSE);
+
+ //
+ // SCAM only if it's enabled in SCSISelect.
+ //
+ if (EepromData | SCAM_ENABLED) {
+ DebugPrint((1,"A154x => SCAM Enabled\n"));
+ deviceExtension->PerformScam = TRUE;
+ }
+ }
+ } while (FALSE);
+
+#endif
+
+ DebugPrint((3,"A154xFindAdapter: Configuration completed\n"));
+ return SP_RETURN_FOUND;
+} // end A154xFindAdapter()
+
+
+
+BOOLEAN
+A154xAdapterState(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN BOOLEAN SaveState
+ )
+/*++
+
+Routine Description:
+
+ This function is called after FindAdapter with SaveState set to TRUE,
+ inidicating that the adapter state should be saved. Before Chicago
+ exits, this function is again called with SaveState set to FALSE,
+ indicating the adapter should be restored to the same state it was
+ when this function was first called. By saving its real mode state
+ and restoring it during protected mode exit will give the adapter
+ a higher chance of working back in real mode.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - Register base address
+ SaveState - Flag to indicate whether to perform SAVE or RESTORE.
+ TRUE == SAVE, FALSE == RESTORE.
+
+Return Value:
+
+ TRUE SAVE/RESTORE operation was successful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR idx;
+ UCHAR cfgsz = sizeof(RM_CFG);
+ PRM_CFG SaveCfg;
+
+ deviceExtension = HwDeviceExtension;
+ SaveCfg = &deviceExtension->RMSaveState;
+
+ //
+ // SAVE real mode state
+ //
+ if (SaveState) {
+ //
+ // Read off config data from AHA154X...
+ //
+ if (!WriteCommandRegister(deviceExtension, AC_RETURN_SETUP_DATA, TRUE))
+ return FALSE;
+
+ if (!WriteDataRegister(deviceExtension, cfgsz))
+ return FALSE;
+
+ for (idx=0;idx<cfgsz;idx++) {
+ if (!(ReadCommandRegister(HwDeviceExtension,(PUCHAR)(SaveCfg),TRUE)))
+ return FALSE;
+ ((PUCHAR)SaveCfg)++;
+ }
+
+ //
+ // ...and wait for interrupt
+ //
+
+ if (!SpinForInterrupt(deviceExtension,TRUE))
+ return FALSE;
+
+ //
+ // RESTORE state to real mode
+ //
+ } else {
+ //
+ // If mailbox count was not zero, re-initialize mailbox addresses
+ // saved from real mode
+ //
+
+ if (SaveCfg->NumMailBoxes) {
+
+ if (!WriteCommandRegister(deviceExtension, AC_MAILBOX_INITIALIZATION, TRUE))
+ return FALSE;
+ if (!WriteDataRegister(deviceExtension, SaveCfg->NumMailBoxes))
+ return FALSE;
+ if (!WriteDataRegister(deviceExtension, SaveCfg->MBAddrHiByte))
+ return FALSE;
+ if (!WriteDataRegister(deviceExtension, SaveCfg->MBAddrMiByte))
+ return FALSE;
+ if (!WriteDataRegister(deviceExtension, SaveCfg->MBAddrLoByte))
+ return FALSE;
+
+ //
+ // ... and wait for interrupt.
+ //
+
+ if (!SpinForInterrupt(deviceExtension,TRUE))
+ return FALSE;
+
+ }
+
+ //
+ // Restore transfer speed gotten from real mode...
+ //
+
+ if (!WriteCommandRegister(deviceExtension, AC_SET_TRANSFER_SPEED, TRUE))
+ return FALSE;
+
+ if (!WriteDataRegister(deviceExtension, SaveCfg->TxSpeed))
+ return FALSE;
+
+ //
+ // ... and wait for interrupt.
+ //
+
+ if (!SpinForInterrupt(deviceExtension,TRUE))
+ return FALSE;
+
+ //
+ // Restore setting for bus on time from real mode...
+ //
+
+ if (!WriteCommandRegister(deviceExtension, AC_SET_BUS_ON_TIME, TRUE))
+ return FALSE;
+
+ if (!WriteDataRegister(deviceExtension, SaveCfg->BusOnTime))
+ return FALSE;
+
+ //
+ // ...and wait for interrupt
+ //
+ if (!SpinForInterrupt(deviceExtension,TRUE))
+ return FALSE;
+
+ //
+ // Restore setting for bus off time from real mode...
+ //
+
+ if (!WriteCommandRegister(deviceExtension, AC_SET_BUS_OFF_TIME, TRUE))
+ return FALSE;
+
+ if (!WriteDataRegister(deviceExtension, SaveCfg->BusOffTime))
+ return FALSE;
+
+ //
+ // ...and wait for interrupt
+ //
+ if (!SpinForInterrupt(deviceExtension,TRUE))
+ return FALSE;
+
+ //
+ // Reset any pending interrupts
+ //
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ }
+ return TRUE;
+
+} // end A154xAdapterState()
+
+
+BOOLEAN
+AdaptecAdapter(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN ULONG IoPort,
+ IN BOOLEAN Mca
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the Special Options byte of the Adapter Inquiry
+ command to see if it is one of the two values returned by Adaptec
+ Adapters. This avoids claiming adapters from BusLogic and DTC.
+
+Arguments:
+
+ HwDeviceExtension - miniport driver's adapter extension.
+
+Return Values:
+
+ TRUE if the adapter looks like an Adaptec.
+ FALSE if not.
+
+--*/
+
+{
+ UCHAR byte;
+ UCHAR specialOptions;
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+
+ if (Mca == TRUE) {
+ INIT_DATA initData;
+ LONG slot;
+ LONG i;
+
+ for (slot = 0; slot < NUMBER_POS_SLOTS; slot++) {
+ i = ScsiPortGetBusData(HwDeviceExtension,
+ Pos,
+ 0,
+ slot,
+ &initData.PosData[slot],
+ sizeof(POS_DATA));
+ if (i < (sizeof(POS_DATA))) {
+ initData.PosData[slot].AdapterId = 0xffff;
+ }
+ }
+
+ for (slot = 0; slot < NUMBER_POS_SLOTS; slot++) {
+ if (initData.PosData[slot].AdapterId == POS_IDENTIFIER) {
+ switch (initData.PosData[slot].IoPortInformation & POS_PORT_MASK) {
+ case POS_PORT_130:
+ if (IoPort == 0x0130) {
+ return TRUE;
+ }
+ break;
+ case POS_PORT_134:
+ if (IoPort == 0x0134) {
+ return TRUE;
+ }
+ break;
+ case POS_PORT_230:
+ if (IoPort == 0x0230) {
+ return TRUE;
+ }
+ break;
+ case POS_PORT_234:
+ if (IoPort == 0x234) {
+ return TRUE;
+ }
+ break;
+ case POS_PORT_330:
+ if (IoPort == 0x330) {
+ return TRUE;
+ }
+ break;
+ case POS_PORT_334:
+ if (IoPort == 0x334) {
+ return TRUE;
+ }
+ break;
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
+ IOP_INTERRUPT_RESET);
+
+ if (!WriteCommandRegister(HwDeviceExtension,AC_ADAPTER_INQUIRY,FALSE)) {
+ return FALSE;
+ }
+
+ //
+ // Byte 0.
+ //
+
+ if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Get the special options byte.
+ //
+
+ if ((ReadCommandRegister(HwDeviceExtension,&specialOptions,TRUE)) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Get the last two bytes and clear the interrupt.
+ //
+
+ if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
+ return FALSE;
+ }
+
+ if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Wait for HACC interrupt.
+ //
+
+ SpinForInterrupt(HwDeviceExtension,FALSE); // eddy
+
+
+ if ((specialOptions == 0x30) || (specialOptions == 0x42)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+ULONG
+A154xDetermineInstalled(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PSCAN_CONTEXT Context,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if Adaptec 154X SCSI adapter is installed in system
+ by reading the status register as each base I/O address
+ and looking for a pattern. If an adapter is found, the BaseIoAddres is
+ initialized.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+ ConfigInfo - Supplies the known configuraiton information.
+
+ AdapterCount - Supplies the count of adapter slots which have been tested.
+
+ Again - Returns whehter the OS specific driver should call again.
+
+Return Value:
+
+ Returns a status indicating whether a driver is present or not.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress;
+ PUCHAR ioSpace;
+ UCHAR portValue;
+ ULONG ioPort;
+
+ //
+ // The following table specifies the ports to be checked when searching for
+ // an adapter. A zero entry terminates the search.
+ //
+
+ CONST ULONG AdapterAddresses[7] = {0X330, 0X334, 0X234, 0X134, 0X130, 0X230, 0};
+
+ //
+ // Get the system physical address for this card. The card uses I/O space.
+ //
+
+ ioSpace =
+ ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0),
+ 0x400,
+ TRUE);
+
+ //
+ // Check for configuration information passed in from system.
+ //
+
+ if ((*ConfigInfo->AccessRanges)[0].RangeLength != 0) {
+
+ ioPort = ScsiPortConvertPhysicalAddressToUlong
+ ((*ConfigInfo->AccessRanges)[0].RangeStart);
+ baseIoAddress = (PBASE_REGISTER)(ioSpace + ioPort);
+
+ HwDeviceExtension->BaseIoAddress = baseIoAddress;
+
+ *Again = FALSE;
+
+ return (ULONG)SP_RETURN_FOUND;
+
+ } else {
+
+ //
+ // Scan possible base addresses looking for adapters.
+ //
+
+ while (AdapterAddresses[Context->adapterCount] != 0) {
+
+ //
+ // Get next base address.
+ //
+
+ baseIoAddress = (PBASE_REGISTER)(ioSpace + AdapterAddresses[Context->adapterCount]);
+ HwDeviceExtension->BaseIoAddress = baseIoAddress;
+ ioPort = AdapterAddresses[Context->adapterCount];
+
+ //
+ // Update the Adapter count
+ //
+
+ (Context->adapterCount)++;
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ portValue = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ //
+ // Check for Adaptec adapter.
+ // The mask (0x29) are bits that may or may not be set.
+ // The bit 0x10 (IOP_SCSI_HBA_IDLE) should be set.
+ //
+
+ if ((portValue & ~0x29) == IOP_SCSI_HBA_IDLE) {
+
+ if (!AdaptecAdapter(HwDeviceExtension, ioPort,
+ (BOOLEAN)(ConfigInfo->AdapterInterfaceType == MicroChannel ? TRUE : FALSE))) {
+
+ DebugPrint((1,"A154xDetermineInstalled: Clone command completed successfully - \n not our board;"));
+ continue;
+
+ //
+ // Run AMI4448 detection code.
+ //
+
+ } else if (A4448IsAmi(HwDeviceExtension,
+ ConfigInfo,
+ AdapterAddresses[(Context->adapterCount) - 1])) {
+
+ DebugPrint ((1,
+ "A154xDetermineInstalled: Detected AMI4448\n"));
+ continue;
+ }
+
+ //
+ // An adapter has been found. Request another call.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ AdapterAddresses[Context->adapterCount - 1]);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = 4;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ //
+ // Check if BIOS is enabled and claim that memory range.
+ //
+
+ A154xClaimBIOSSpace(HwDeviceExtension,
+ baseIoAddress,
+ Context,
+ ConfigInfo);
+
+ return (ULONG)SP_RETURN_FOUND;
+ }
+ }
+ }
+
+ //
+ // The entire table has been searched and no adapters have been found.
+ // There is no need to call again and the device base can now be freed.
+ // Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ Context->adapterCount = 0;
+ Context->biosScanStart = 0;
+
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ ioSpace);
+
+ return SP_RETURN_NOT_FOUND;
+
+} // end A154xDetermineInstalled()
+
+VOID
+A154xClaimBIOSSpace(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN PBASE_REGISTER BaseIoAddress,
+ IN OUT PSCAN_CONTEXT Context,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from A154xDetermineInstalled to find
+ and claim BIOS space.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ BaseIoAddress - IO address of adapter
+ ConfigInfo - Miniport configuration information
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UCHAR inboundData, byte;
+ ULONG baseBIOSAddress;
+ ULONG i, j;
+ PUCHAR biosSpace, biosPtr;
+ UCHAR aha154xBSignature[16] =
+ { 0x06, 0x73, 0x01, 0xC3, 0x8A, 0xE7, 0xC6, 0x06,
+ 0x42, 0x00, 0x00, 0xF9, 0xC3, 0x88, 0x26, 0x42 };
+
+ //
+ // Reset interrupt just in case.
+ //
+
+ ScsiPortWritePortUchar(&BaseIoAddress->StatusRegister,
+ IOP_INTERRUPT_RESET);
+
+ //
+ // The Adapter Inquiry command will return 4 bytes describing
+ // the firmware revision level.
+ //
+
+ if (WriteCommandRegister(HwDeviceExtension,
+ AC_ADAPTER_INQUIRY,TRUE) == FALSE) {
+ return;
+ }
+
+ if ((ReadCommandRegister(HwDeviceExtension,
+ &inboundData,TRUE)) == FALSE) {
+ return;
+ }
+
+ if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
+ return;
+ }
+
+ if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
+ return;
+ }
+
+ if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
+ return;
+ }
+
+ //
+ // Wait for HACC by hand.
+ //
+
+ SpinForInterrupt(HwDeviceExtension, FALSE);
+
+ //
+ // If the 1st bytethe adapter inquiry command is 0x41,
+ // then the adapter is an AHA154XB; if 0x44 or 0x45 then
+ // it is an AHA154XC or CF respectively
+ //
+ // if we've already checked all the possible locations for
+ // an AHA154XB bios don't waste time mapping the ports
+ //
+
+ if ((inboundData == 0x41)&&(Context->biosScanStart < 6)) {
+
+ //
+ // Get the system physical address for this BIOS section.
+ //
+
+ biosSpace =
+ ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0xC8000),
+ 0x18000,
+ FALSE);
+
+ //
+ // Loop through all BIOS base possibilities. Use the context information
+ // to pick up where we left off the last time around.
+ //
+
+ for (i = Context->biosScanStart; i < 6; i ++) {
+
+ biosPtr = biosSpace + i * 0x4000 + 16;
+
+ //
+ // Compare the second 16 bytes to BIOS header
+
+ for (j = 0; j < 16; j++) {
+
+ if (aha154xBSignature[j] != ScsiPortReadRegisterUchar(biosPtr)) {
+ break;
+ }
+
+ biosPtr++;
+ }
+
+ if (j == 16) {
+
+ //
+ // Found the BIOS. Set up ConfigInfo->AccessRanges
+ //
+
+ (*ConfigInfo->AccessRanges)[1].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0xC8000 + i * 0x4000);
+ (*ConfigInfo->AccessRanges)[1].RangeLength = 0x4000;
+ (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE;
+
+ DebugPrint((1,
+ "A154xClaimBiosSpace: 154XB BIOS address = %lX\n",
+ 0xC8000 + i * 0x4000 ));
+ break;
+ }
+ }
+
+ Context->biosScanStart = i + 1;
+ ScsiPortFreeDeviceBase(HwDeviceExtension, (PVOID)biosSpace);
+
+ } else {
+
+ if ((inboundData == 0x44) || (inboundData == 0x45)) {
+
+ //
+ // Fill in BIOS address information
+ //
+
+ ScsiPortWritePortUchar(&BaseIoAddress->StatusRegister,
+ IOP_INTERRUPT_RESET);
+
+ if (WriteCommandRegister(HwDeviceExtension,
+ AC_RETURN_SETUP_DATA,TRUE) == FALSE) {
+ return;
+ }
+
+ //
+ // Send length of incoming transfer for the Return Setup Data
+ //
+
+ if (WriteDataRegister(HwDeviceExtension,0x27) == FALSE) {
+ return;
+ }
+
+ //
+ // Magic Adaptec C rev byte.
+ //
+
+ for (i = 0; i < 0x27; i++) {
+ if ((ReadCommandRegister(HwDeviceExtension,
+ &inboundData,TRUE)) == FALSE) {
+ return;
+ }
+ }
+
+ //
+ // Interrupt handler is not yet installed so wait for HACC by hand.
+ //
+
+ SpinForInterrupt(HwDeviceExtension, FALSE);
+
+ inboundData >>= 4;
+ inboundData &= 0x07; // Filter BIOS bits out
+ baseBIOSAddress = 0xC8000;
+
+ if (inboundData != 0x07 && inboundData != 0x06) {
+
+ baseBIOSAddress +=
+ (ULONG)((~inboundData & 0x07) - 2) * 0x4000;
+
+ (*ConfigInfo->AccessRanges)[1].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(baseBIOSAddress);
+ (*ConfigInfo->AccessRanges)[1].RangeLength = 0x4000;
+ (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE;
+
+ DebugPrint((1,
+ "A154xClaimBiosSpace: 154XC BIOS address = %lX\n",
+ baseBIOSAddress));
+ }
+ }
+ }
+
+ return;
+}
+
+
+
+BOOLEAN
+A154xHwInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from ScsiPortInitialize
+ to set up the adapter so that it is ready to service requests.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR status;
+ ULONG i;
+
+ DebugPrint((2,"A154xHwInitialize: Reset aha154X and SCSI bus\n"));
+
+ //
+ // Reset SCSI chip.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
+
+ //
+ // Inform the port driver that the bus has been reset.
+ //
+
+ ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
+
+ ScsiPortStallExecution(500*1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+ }
+
+ //
+ // Check if reset failed or succeeded.
+ //
+
+ if (!(status & IOP_SCSI_HBA_IDLE) || !(status & IOP_MAILBOX_INIT_REQUIRED)) {
+ DebugPrint((1,"A154xInitialize: Reset SCSI bus failed\n"));
+ return FALSE;
+ }
+
+ //
+ // Unlock mailboxes in case the adapter is a 1540B with 1Gb support
+ // or 1540C with extended translation enabled.
+ //
+
+ status = UnlockMailBoxes(deviceExtension);
+ (VOID) SpinForInterrupt(deviceExtension,FALSE); // eddy
+
+ //
+ // Zero out mailboxes.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+
+ mailboxIn = &noncachedExtension->Mbi[i];
+ mailboxOut = &noncachedExtension->Mbo[i];
+
+ mailboxOut->Command = mailboxIn->Status = 0;
+ }
+
+ //
+ // Zero preivous indexes.
+ //
+
+ deviceExtension->MboIndex = 0;
+ deviceExtension->MbiIndex = 0;
+
+ DebugPrint((3,"A154xHwInitialize: Initialize mailbox\n"));
+
+ if (!WriteCommandRegister(deviceExtension,AC_MAILBOX_INITIALIZATION, TRUE)) {
+ DebugPrint((1,"A154xHwInitialize: Can't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteDataRegister(deviceExtension, MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteDataRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the middle byte of the mailbox physical address.
+ //
+
+ if (!WriteDataRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteDataRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+#ifdef FORCE_DMA_SPEED
+ //
+ // Set the DMA transfer speed to 5.0 MB/second. This is because
+ // faster transfer speeds cause data corruption on 486/33 machines.
+ // This overrides the card jumper setting.
+ //
+
+ if (!WriteCommandRegister(deviceExtension, AC_SET_TRANSFER_SPEED, TRUE)) {
+
+ DebugPrint((1,"Can't set dma transfer speed\n"));
+
+ } else if (!WriteDataRegister(deviceExtension, DMA_SPEED_50_MBS)) {
+
+ DebugPrint((1,"Can't set dma transfer speed\n"));
+ }
+
+ //
+ // Wait for interrupt.
+ //
+
+ if (!SpinForInterrupt(deviceExtension,TRUE)) {
+ DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
+ return TRUE;
+ }
+#endif
+
+ //
+ // Override default setting for bus on time. This makes floppy
+ // drives work better with this adapter.
+ //
+
+ if (!WriteCommandRegister(deviceExtension, AC_SET_BUS_ON_TIME, TRUE)) {
+
+ DebugPrint((1,"Can't set bus on time\n"));
+
+ } else if (!WriteDataRegister(deviceExtension, deviceExtension->BusOnTime)) {
+
+ DebugPrint((1,"Can't set bus on time\n"));
+ }
+
+ //
+ // Wait for interrupt.
+ //
+
+ if (!SpinForInterrupt(deviceExtension,TRUE)) {
+ DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
+ return TRUE;
+ }
+
+
+ //
+ // Override the default CCB timeout of 250 mseconds to 500 (0x1F4).
+ //
+
+ if (!WriteCommandRegister(deviceExtension, AC_SET_SELECTION_TIMEOUT, TRUE)) {
+ DebugPrint((1,"A154xHwInitialize: Can't set CCB timeout\n"));
+ }
+ else {
+ if (!WriteDataRegister(deviceExtension,0x01)) {
+ DebugPrint((1,"A154xHwInitialize: Can't set timeout selection enable\n"));
+ }
+
+ if (!WriteDataRegister(deviceExtension,0x00)) {
+ DebugPrint((1,"A154xHwInitialize: Can't set second byte\n"));
+ }
+
+ if (!WriteDataRegister(deviceExtension,0x01)) {
+ DebugPrint((1,"A154xHwInitialize: Can't set MSB\n"));
+ }
+
+ if (!WriteDataRegister(deviceExtension,0xF4)) {
+ DebugPrint((1,"A154xHwInitialize: Can't set LSB\n"));
+ }
+ }
+
+
+ //
+ // Wait for interrupt.
+ //
+
+ if (!SpinForInterrupt(deviceExtension,TRUE)) {
+ DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
+ return TRUE;
+ }
+
+#if defined(_SCAM_ENABLED)
+ //
+ // SCAM because A154xHwInitialize reset's the SCSI bus.
+ //
+
+ PerformScamProtocol(deviceExtension);
+#endif
+
+ return TRUE;
+
+} // end A154xHwInitialize()
+
+#if defined(_SCAM_ENABLED)
+
+BOOLEAN
+PerformScamProtocol(
+ IN PHW_DEVICE_EXTENSION deviceExtension
+ )
+
+{
+
+ if (deviceExtension->PerformScam) {
+
+ DebugPrint((1,"AHA154x => Starting SCAM operation.\n"));
+
+ if (!WriteCommandRegister(deviceExtension, AC_PERFORM_SCAM, TRUE)) {
+
+ DebugPrint((0,"AHA154x => Adapter time out, SCAM command failure.\n"));
+
+ ScsiPortLogError(deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 0xA << 8);
+ return FALSE;
+
+ } else {
+
+ DebugPrint((1,"AHA154x => SCAM Performed OK.\n"));
+ return TRUE;
+ }
+ } else {
+
+ DebugPrint((1,"AHA154x => SCAM not performed, non-SCAM adapter.\n"));
+ return FALSE;
+ }
+
+} //End PerformScamProtocol
+#endif
+
+
+BOOLEAN
+A154xStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel. The mailboxes are scanned for an empty one and
+ the CCB is written to it. Then the doorbell is rung and the
+ OS port driver is notified that the adapter can take
+ another request, if any are available.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PMBO mailboxOut;
+ PCCB ccb;
+ PHW_LU_EXTENSION luExtension;
+
+ ULONG i = deviceExtension->MboIndex;
+ ULONG physicalCcb;
+ ULONG length;
+
+ DebugPrint((3,"A154xStartIo: Enter routine\n"));
+
+ //
+ // Check if command is an ABORT request.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (!luExtension->CurrentSrb) {
+
+ DebugPrint((1, "A154xStartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get CCB to abort.
+ //
+
+ ccb = Srb->NextSrb->SrbExtension;
+
+ //
+ // Set abort SRB for completion.
+ //
+
+ ccb->AbortSrb = Srb;
+
+ } else {
+
+ ccb = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in CCB.
+ //
+
+ ccb->SrbAddress = Srb;
+ }
+
+ //
+ // Make sure that this request isn't too long for the adapter. If so
+ // bounce it back as an invalid request
+ //
+
+ if ((deviceExtension->MaxCdbLength) &&
+ (deviceExtension->MaxCdbLength < Srb->CdbLength)) {
+
+ DebugPrint((1,"A154xStartIo: Srb->CdbLength [%d] > MaxCdbLength [%d]. Invalid request\n",
+ Srb->CdbLength,
+ deviceExtension->MaxCdbLength
+ ));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get CCB physical address.
+ //
+
+ physicalCcb = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, ccb, &length));
+
+ //
+ // Find free mailboxOut.
+ //
+
+ do {
+
+ mailboxOut = &noncachedExtension->Mbo[i % MB_COUNT];
+ i++;
+
+ } while (mailboxOut->Command != MBO_FREE);
+
+ //
+ // Save the next free location.
+ //
+
+ deviceExtension->MboIndex = (UCHAR) (i % MB_COUNT);
+
+ DebugPrint((3,"A154xStartIo: MBO address %lx, Loop count = %d\n", mailboxOut, i));
+
+ //
+ // Write CCB to mailbox.
+ //
+
+ FOUR_TO_THREE(&mailboxOut->Address,
+ (PFOUR_BYTE)&physicalCcb);
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1, "A154xStartIo: Abort request received\n"));
+
+ //
+ // Race condition (what if CCB to be aborted
+ // completes after setting new SrbAddress?)
+ //
+
+ mailboxOut->Command = MBO_ABORT;
+
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset aha154x and SCSI bus.
+ //
+
+ DebugPrint((1, "A154xStartIo: Reset bus request received\n"));
+
+ if (!A154xResetBus(
+ deviceExtension,
+ Srb->PathId
+ )) {
+
+ DebugPrint((1,"A154xStartIo: Reset bus failed\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ //
+ // Move SRB to logical unit extension.
+ //
+
+ luExtension->CurrentSrb = Srb;
+
+ //
+ // Build CCB.
+ //
+
+ BuildCcb(deviceExtension, Srb);
+
+ mailboxOut->Command = MBO_START;
+
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ DebugPrint((1,"A154xStartIo: Reset device not supported\n"));
+
+ //
+ // Drop through to default.
+ //
+
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // Tell 154xb a CCB is available now.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,AC_START_SCSI_COMMAND, FALSE)) {
+
+ //
+ // Let request time out and fail.
+ //
+
+ DebugPrint((1,"A154xStartIo: Can't write command to adapter\n"));
+
+ deviceExtension->PendingRequest = TRUE;
+
+ } else {
+
+ //
+ // Command(s) submitted. Clear pending request flag.
+ //
+
+ deviceExtension->PendingRequest = FALSE;
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ }
+
+ return TRUE;
+
+} // end A154xStartIo()
+
+
+BOOLEAN
+A154xInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the adaptec 154x SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the CCB is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PCCB ccb;
+ PSCSI_REQUEST_BLOCK srb;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ PMBI mailboxIn;
+ ULONG physicalCcb;
+ PHW_LU_EXTENSION luExtension;
+ ULONG residualBytes;
+ ULONG i;
+
+ UCHAR InterruptFlags;
+
+ InterruptFlags = ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister);
+
+ //
+ // Determine cause of interrupt.
+ //
+
+ if ((InterruptFlags ^ IOP_ANY_INTERRUPT) == 0) {
+
+ DebugPrint((4,"A154xInterrupt: Spurious interrupt\n"));
+
+ return FALSE;
+ }
+
+ if (InterruptFlags & IOP_COMMAND_COMPLETE) {
+
+ //
+ // Adapter command completed.
+ //
+
+ DebugPrint((2,"A154xInterrupt: Adapter Command complete\n"));
+ DebugPrint((3,"A154xInterrupt: Interrupt flags %x\n", InterruptFlags));
+ DebugPrint((3,"A154xInterrupt: Status %x\n",
+ ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ return TRUE;
+
+ } else if (InterruptFlags & IOP_MBI_FULL) {
+
+ DebugPrint((3,"A154xInterrupt: MBI Full\n"));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ } else if (InterruptFlags & IOP_SCSI_RESET_DETECTED) {
+
+ DebugPrint((1,"A154xInterrupt: SCSI Reset detected\n"));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ //
+ // Notify of reset.
+ //
+
+ ScsiPortNotification(ResetDetected,
+ deviceExtension,
+ NULL);
+
+#if defined(_SCAM_ENABLED)
+ //
+ // Interrupt handler where reset is detected
+ //
+ PerformScamProtocol(deviceExtension);
+#endif
+
+ return TRUE;
+
+ }
+
+ //
+ // Determine which MailboxIn location contains the CCB.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ mailboxIn = &noncachedExtension->Mbi[deviceExtension->MbiIndex];
+
+ //
+ // Look for a mailbox entry with a legitimate status.
+ //
+
+ if (mailboxIn->Status != MBI_FREE) {
+
+ //
+ // Point to the next in box.
+ //
+
+ deviceExtension->MbiIndex = (deviceExtension->MbiIndex + 1) % MB_COUNT;
+
+ //
+ // MBI found. Convert CCB to big endian.
+ //
+
+ THREE_TO_FOUR((PFOUR_BYTE)&physicalCcb,
+ &mailboxIn->Address);
+
+ DebugPrint((3, "A154xInterrupt: Physical CCB %lx\n", physicalCcb));
+
+ //
+ // Check if physical CCB is zero.
+ // This is done to cover for hardware errors.
+ //
+
+ if (!physicalCcb) {
+
+ DebugPrint((1,"A154xInterrupt: Physical CCB address is 0\n"));
+
+ //
+ // Indicate MBI is available.
+ //
+
+ mailboxIn->Status = MBI_FREE;
+
+ continue;
+ }
+
+ //
+ // Convert Physical CCB to Virtual.
+ //
+
+ ccb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalCcb));
+
+
+ DebugPrint((3, "A154xInterrupt: Virtual CCB %lx\n", ccb));
+
+ //
+ // Make sure the virtual address was found.
+ //
+
+ if (ccb == NULL) {
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 5 << 8
+ );
+
+ //
+ // Indicate MBI is available.
+ //
+
+ mailboxIn->Status = MBI_FREE;
+
+ continue;
+ }
+
+ //
+ // Get SRB from CCB.
+ //
+
+ srb = ccb->SrbAddress;
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun);
+
+ //
+ // Make sure the luExtension was found and it has a current request.
+ //
+
+ if (luExtension == NULL || (luExtension->CurrentSrb == NULL &&
+ mailboxIn->Status != MBI_NOT_FOUND)) {
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (6 << 8) | mailboxIn->Status
+ );
+
+ //
+ // Indicate MBI is available.
+ //
+
+ mailboxIn->Status = MBI_FREE;
+
+ continue;
+ }
+
+ //
+ // Check MBI status.
+ //
+
+ switch (mailboxIn->Status) {
+
+ case MBI_SUCCESS:
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ //
+ // Check for data underrun if using scatter/gather
+ // command with residual bytes.
+ //
+
+ if (deviceExtension->CcbScatterGatherCommand == SCATTER_GATHER_COMMAND) {
+
+ //
+ // Update SRB with number of bytes transferred.
+ //
+
+ THREE_TO_FOUR((PFOUR_BYTE)&residualBytes,
+ &ccb->DataLength);
+
+ if (residualBytes != 0) {
+
+ ULONG transferLength = srb->DataTransferLength;
+
+ DebugPrint((2,
+ "A154xInterrupt: Underrun occured. Request length = %lx, Residual length = %lx\n",
+ srb->DataTransferLength,
+ residualBytes));
+
+ //
+ // Update SRB with bytes transferred and
+ // underrun status.
+ //
+
+ srb->DataTransferLength -= residualBytes;
+ srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ if ((LONG)(srb->DataTransferLength) < 0) {
+
+ DebugPrint((0,
+ "A154xInterrupt: Overrun occured. Request length = %lx, Residual length = %lx\n",
+ transferLength,
+ residualBytes));
+ //
+ // Seems to be a FW bug in some revs. where
+ // residual comes back as a negative number, yet the
+ // request is successful.
+ //
+
+ srb->DataTransferLength = 0;
+ srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+
+
+ //
+ // Log the event and then the residual byte count.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_PROTOCOL_ERROR,
+ 0xb);
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_PROTOCOL_ERROR,
+ residualBytes);
+
+ }
+ }
+ }
+
+ luExtension->CurrentSrb = NULL;
+
+ break;
+
+ case MBI_NOT_FOUND:
+
+ DebugPrint((1, "A154xInterrupt: CCB abort failed %lx\n", ccb));
+
+ srb = ccb->AbortSrb;
+
+ srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ //
+ // Check if SRB still outstanding.
+ //
+
+ if (luExtension->CurrentSrb) {
+
+ //
+ // Complete this SRB.
+ //
+
+ luExtension->CurrentSrb->SrbStatus = SRB_STATUS_TIMEOUT;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ luExtension->CurrentSrb);
+
+ luExtension->CurrentSrb = NULL;
+ }
+
+ break;
+
+ case MBI_ABORT:
+
+ DebugPrint((1, "A154xInterrupt: CCB aborted\n"));
+
+ //
+ // Update target status in aborted SRB.
+ //
+
+ srb->SrbStatus = SRB_STATUS_ABORTED;
+
+ //
+ // Call notification routine for the aborted SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ luExtension->CurrentSrb = NULL;
+
+ //
+ // Get the abort SRB from CCB.
+ //
+
+ srb = ccb->AbortSrb;
+
+ //
+ // Set status for completing abort request.
+ //
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ break;
+
+ case MBI_ERROR:
+
+ DebugPrint((2, "A154xInterrupt: Error occurred\n"));
+
+ srb->SrbStatus = MapError(deviceExtension, srb, ccb);
+
+ //
+ // Check if ABORT command.
+ //
+
+ if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Check if SRB still outstanding.
+ //
+
+ if (luExtension->CurrentSrb) {
+
+ //
+ // Complete this SRB.
+ //
+
+ luExtension->CurrentSrb->SrbStatus = SRB_STATUS_TIMEOUT;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ luExtension->CurrentSrb);
+
+ }
+
+ DebugPrint((1,"A154xInterrupt: Abort command failed\n"));
+ }
+
+ luExtension->CurrentSrb = NULL;
+
+ break;
+
+ default:
+
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (1 << 8) | mailboxIn->Status
+ );
+
+ DebugPrint((1, "A154xInterrupt: Unrecognized mailbox status\n"));
+
+ mailboxIn->Status = MBI_FREE;
+
+ continue;
+
+ } // end switch
+
+ //
+ // Indicate MBI is available.
+ //
+
+ mailboxIn->Status = MBI_FREE;
+
+ DebugPrint((2, "A154xInterrupt: SCSI Status %x\n", srb->ScsiStatus));
+
+ DebugPrint((2, "A154xInterrupt: Adapter Status %x\n", ccb->HostStatus));
+
+ //
+ // Update target status in SRB.
+ //
+
+ srb->ScsiStatus = ccb->TargetStatus;
+
+ //
+ // Signal request completion.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ } else {
+
+ break;
+
+ } // end if ((mailboxIn->Status == MBI_SUCCESS ...
+
+ } // end for (i=0; i<MB_COUNT; i++) {
+
+ if (deviceExtension->PendingRequest) {
+
+ //
+ // The last write command to the adapter failed. Try and start it now.
+ //
+
+ deviceExtension->PendingRequest = FALSE;
+
+ //
+ // Tell 154xb a CCB is available now.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,AC_START_SCSI_COMMAND, FALSE)) {
+
+ //
+ // Let request time out and fail.
+ //
+
+ DebugPrint((1,"A154xInterrupt: Can't write command to adapter\n"));
+
+ deviceExtension->PendingRequest = TRUE;
+
+ } else {
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ }
+ }
+
+ return TRUE;
+
+} // end A154xInterrupt()
+
+
+VOID
+BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build CCB for 154x.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PCCB ccb = Srb->SrbExtension;
+
+ DebugPrint((3,"BuildCcb: Enter routine\n"));
+
+ //
+ // Set target id and LUN.
+ //
+
+ ccb->ControlByte = (UCHAR)(Srb->TargetId << 5) | Srb->Lun;
+
+ //
+ // Set CCB Operation Code.
+ //
+
+ ccb->OperationCode = DeviceExtension->CcbScatterGatherCommand;
+
+ //
+ // Set transfer direction bit.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ //
+ // Check if both direction bits are set. This is an
+ // indication that the direction has not been specified.
+ //
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+ ccb->ControlByte |= CCB_DATA_XFER_OUT;
+ }
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ccb->ControlByte |= CCB_DATA_XFER_IN;
+ } else {
+
+ //
+ // if no data transfer, we must set ccb command to to INITIATOR
+ // instead of SCATTER_GATHER and zero ccb data pointer and length.
+ //
+
+ ccb->OperationCode = DeviceExtension->CcbInitiatorCommand;
+ ccb->DataPointer.Msb = 0;
+ ccb->DataPointer.Mid = 0;
+ ccb->DataPointer.Lsb = 0;
+ ccb->DataLength.Msb = 0;
+ ccb->DataLength.Mid = 0;
+ ccb->DataLength.Lsb = 0;
+ }
+
+ //
+ // 01h disables auto request sense.
+ //
+
+ ccb->RequestSenseLength = 1;
+
+ //
+ // Set CDB length and copy to CCB.
+ //
+
+ ccb->CdbLength = (UCHAR)Srb->CdbLength;
+
+ ScsiPortMoveMemory(ccb->Cdb, Srb->Cdb, ccb->CdbLength);
+
+ //
+ // Set reserved bytes to zero.
+ //
+
+ ccb->Reserved[0] = 0;
+ ccb->Reserved[1] = 0;
+
+ ccb->LinkIdentifier = 0;
+
+ //
+ // Zero link pointer.
+ //
+
+ ccb->LinkPointer.Msb = 0;
+ ccb->LinkPointer.Lsb = 0;
+ ccb->LinkPointer.Mid = 0;
+
+ //
+ // Build SDL in CCB if data transfer.
+ //
+
+ if (Srb->DataTransferLength > 0) {
+ BuildSdl(DeviceExtension, Srb);
+ }
+
+ //
+ // Move 0xff to Target Status to indicate
+ // CCB has not completed.
+ //
+
+ ccb->TargetStatus = 0xFF;
+
+ return;
+
+} // end BuildCcb()
+
+
+VOID
+BuildSdl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list for the CCB.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PCCB ccb = Srb->SrbExtension;
+ PSDL sdl = &ccb->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG four;
+ PTHREE_BYTE three;
+ ULONG i = 0;
+
+ DebugPrint((3,"BuildSdl: Enter routine\n"));
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+
+ DebugPrint((3, "BuildSdl: Data buffer %lx\n", dataPointer));
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "BuildSdl: Physical address %lx\n", physicalAddress));
+ DebugPrint((3, "BuildSdl: Data length %lx\n", length));
+ DebugPrint((3, "BuildSdl: Bytes left %lx\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ //
+ // Convert length to 3-byte big endian format.
+ //
+
+ four = length;
+ three = &sdl->Sgd[i].Length;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+
+ //
+ // Convert physical address to 3-byte big endian format.
+ //
+
+ four = (ULONG)physicalAddress;
+ three = &sdl->Sgd[i].Address;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+ i++;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+
+ } while (bytesLeft);
+
+ //##BW
+ //
+ // For data transfers that have less than one scatter gather element, convert
+ // CCB to one transfer without using SG element. This will clear up the data
+ // overrun/underrun problem with small transfers that reak havoc with scanners
+ // and CD-ROM's etc. This is the method employed in ASPI4DOS to avoid similar
+ // problems.
+ //
+ if (i == 0x1) {
+ //
+ // Only one element, so convert...
+ //
+
+ //
+ // The above Do..While loop performed all necessary conversions for the
+ // SRB buffer, so we copy over the length and address directly into the
+ // CCB
+ //
+ ccb->DataLength = sdl->Sgd[0x0].Length;
+ ccb->DataPointer = sdl->Sgd[0x0].Address;
+
+ //
+ // Change the OpCode from SG command to initiator command and we're
+ // done. Easy, huh?
+ //
+ ccb->OperationCode = SCSI_INITIATOR_COMMAND; //##BW _OLD_ command?
+
+ } else {
+ //
+ // Multiple SG elements, so continue as normal.
+ //
+
+ //
+ // Write SDL length to CCB.
+ //
+
+ four = i * sizeof(SGD);
+ three = &ccb->DataLength;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+
+ DebugPrint((3,"BuildSdl: SDL length is %d\n", four));
+
+ //
+ // Write SDL address to CCB.
+ //
+
+ FOUR_TO_THREE(&ccb->DataPointer,
+ (PFOUR_BYTE)&physicalSdl);
+
+ DebugPrint((3,"BuildSdl: SDL address is %lx\n", sdl));
+
+ DebugPrint((3,"BuildSdl: CCB address is %lx\n", ccb));
+ }
+
+ return;
+
+} // end BuildSdl()
+
+
+BOOLEAN
+A154xResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Reset Adaptec 154X SCSI adapter and SCSI bus.
+ Initialize adapter mailbox.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR status;
+ ULONG i;
+
+ DebugPrint((2,"ResetBus: Reset aha154X and SCSI bus\n"));
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR) PathId,
+ 0xFF,
+ 0xFF,
+ (ULONG) SRB_STATUS_BUS_RESET);
+
+ //
+ // Read status register.
+ //
+
+ status = ScsiPortReadPortUchar(&baseIoAddress->StatusRegister);
+
+ //
+ // If value is normal then reset device only.
+ //
+
+ if ((status & ~IOP_MAILBOX_INIT_REQUIRED) != IOP_SCSI_HBA_IDLE) {
+
+ //
+ // Reset SCSI chip.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
+
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Zero out mailboxes.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+
+ mailboxIn = &noncachedExtension->Mbi[i];
+ mailboxOut = &noncachedExtension->Mbo[i];
+
+ mailboxOut->Command = mailboxIn->Status = 0;
+ }
+
+ //
+ // Zero previous indexes.
+ //
+
+ deviceExtension->MboIndex = 0;
+ deviceExtension->MbiIndex = 0;
+
+ if (deviceExtension->PendingRequest) {
+
+ deviceExtension->PendingRequest = FALSE;
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ }
+
+ if (!(status & IOP_SCSI_HBA_IDLE)) {
+ return(FALSE);
+ }
+
+ //
+ // Unlock mailboxes in case the adapter is a 1540B with 1Gb support
+ // or 1540C with extended translation enabled. Maiboxes cannot be
+ // initialized until unlock code is sent.
+
+ status = UnlockMailBoxes(deviceExtension);
+
+ if (!SpinForInterrupt(deviceExtension,FALSE)) {
+ DebugPrint((1,"A154xResetBus: Failed to unlock mailboxes\n"));
+ return FALSE;
+ }
+
+ DebugPrint((3,"ResetBus: Initialize mailbox\n"));
+
+ if (!WriteCommandRegister(deviceExtension,AC_MAILBOX_INITIALIZATION, TRUE)) {
+ DebugPrint((1,"A154xResetBus: Can't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteDataRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteDataRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the middle byte of the mailbox physical address.
+ //
+
+ if (!WriteDataRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteDataRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+#ifdef FORCE_DMA_SPEED
+ //
+ // Set the DMA transfer speed to 5.0 MB/second. This is because
+ // faster transfer speeds cause data corruption on 486/33 machines.
+ // This overrides the card jumper setting.
+ //
+
+ if (!WriteCommandRegister(deviceExtension, AC_SET_TRANSFER_SPEED, TRUE)) {
+
+ DebugPrint((1,"Can't set dma transfer speed\n"));
+
+ } else if (!WriteDataRegister(deviceExtension, DMA_SPEED_50_MBS)) {
+
+ DebugPrint((1,"Can't set dma transfer speed\n"));
+ }
+
+ //
+ // Wait for interrupt.
+ //
+
+ if (!SpinForInterrupt(deviceExtension,TRUE)) {
+ DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
+ }
+#endif
+
+ //
+ // Override default setting for bus on time. This makes floppy
+ // drives work better with this adapter.
+ //
+
+ if (!WriteCommandRegister(deviceExtension, AC_SET_BUS_ON_TIME, TRUE)) {
+
+ DebugPrint((1,"Can't set bus on time\n"));
+
+ } else if (!WriteDataRegister(deviceExtension, 0x07)) {
+
+ DebugPrint((1,"Can't set bus on time\n"));
+ }
+
+ //
+ // Wait for interrupt.
+ //
+
+ if (!SpinForInterrupt(deviceExtension,TRUE)) {
+ DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
+ }
+
+#if defined(_SCAM_ENABLED)
+ //
+ // SCAM because we're a154xResetBus
+ //
+ PerformScamProtocol(deviceExtension);
+#endif
+ return TRUE;
+
+
+} // end A154xResetBus()
+
+
+UCHAR
+MapError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ Translate A154x error to SRB error, and log an error if necessary.
+
+Arguments:
+
+ HwDeviceExtension - The hardware device extension.
+
+ Srb - The failing Srb.
+
+ Ccb - Command Control Block contains error.
+
+Return Value:
+
+ SRB Error
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ UCHAR status;
+ ULONG logError;
+ ULONG residualBytes;
+
+ switch (Ccb->HostStatus) {
+
+ case CCB_SELECTION_TIMEOUT:
+
+ return SRB_STATUS_SELECTION_TIMEOUT;
+
+ case CCB_COMPLETE:
+
+ if (Ccb->TargetStatus == SCSISTAT_CHECK_CONDITION) {
+
+ //
+ // Update SRB with number of bytes transferred.
+ //
+
+ THREE_TO_FOUR((PFOUR_BYTE)&residualBytes,
+ &Ccb->DataLength);
+
+ DebugPrint((2, "Aha154x MapError: Underrun occured. Request length = %lx, Residual length = %lx\n", Srb->DataTransferLength, residualBytes));
+ Srb->DataTransferLength -= residualBytes;
+ }
+
+ return SRB_STATUS_ERROR;
+
+ case CCB_DATA_OVER_UNDER_RUN:
+
+
+ //
+ // Check for data underrun if using scatter/gather
+ // command with residual bytes.
+ //
+
+ if (deviceExtension->CcbScatterGatherCommand == SCATTER_GATHER_COMMAND) {
+
+ THREE_TO_FOUR((PFOUR_BYTE)&residualBytes,
+ &Ccb->DataLength);
+
+ if (residualBytes) {
+ Srb->DataTransferLength -= residualBytes;
+ return SRB_STATUS_DATA_OVERRUN; //##BW this look good
+ } else {
+ logError = SP_PROTOCOL_ERROR;
+ }
+ }
+
+ //
+ // Return instead of posting DU/DO to the log file.
+ //
+ //status = SRB_STATUS_DATA_OVERRUN;
+ return SRB_STATUS_DATA_OVERRUN;
+ break;
+
+ case CCB_UNEXPECTED_BUS_FREE:
+ status = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ logError = SP_UNEXPECTED_DISCONNECT;
+ break;
+
+ case CCB_PHASE_SEQUENCE_FAIL:
+ case CCB_INVALID_DIRECTION:
+ status = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ logError = SP_PROTOCOL_ERROR;
+ break;
+
+ case CCB_INVALID_OP_CODE:
+
+ //
+ // Try CCB commands without residual bytes.
+ //
+
+ deviceExtension->CcbScatterGatherCommand = SCATTER_GATHER_OLD_COMMAND;
+ deviceExtension->CcbInitiatorCommand = SCSI_INITIATOR_OLD_COMMAND;
+ status = SRB_STATUS_INVALID_REQUEST;
+ logError = SP_BAD_FW_WARNING;
+ break;
+
+ case CCB_INVALID_CCB:
+ case CCB_BAD_MBO_COMMAND:
+ case CCB_BAD_LINKED_LUN:
+ case CCB_DUPLICATE_CCB:
+ status = SRB_STATUS_INVALID_REQUEST;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+
+ default:
+ status = SRB_STATUS_ERROR;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+ }
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ (2 << 8) | Ccb->HostStatus
+ );
+
+ return(status);
+
+} // end MapError()
+
+
+BOOLEAN
+ReadCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR DataByte,
+ IN BOOLEAN TimeOutFlag
+ )
+
+/*++
+
+Routine Description:
+
+ Read command register.
+
+Arguments:
+
+ DeviceExtesion - Pointer to adapder extension
+ DataByte - Byte read from register
+
+Return Value:
+
+ TRUE if command register read.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+
+ //
+ // Wait up to 5000 microseconds for adapter to be ready.
+ //
+
+ for (i=0; i<5000; i++) {
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_DATA_IN_PORT_FULL) {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+
+ } else {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if ( (i==5000) && (TimeOutFlag == TRUE)) {
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 8
+ );
+
+ DebugPrint((1, "Aha154x:ReadCommandRegister: Read command timed out\n"));
+ return FALSE;
+ }
+
+ *DataByte = ScsiPortReadPortUchar(&baseIoAddress->CommandRegister);
+
+ return TRUE;
+
+} // end ReadCommandRegister()
+
+
+BOOLEAN
+WriteCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR AdapterCommand,
+ IN BOOLEAN WaitForIdle
+ )
+
+/*++
+
+Routine Description:
+
+ Write operation code to command register.
+
+Arguments:
+
+ DeviceExtension - Pointer to adapter extension
+ AdapterCommand - Value to be written to register
+ WaitForIdle - Indicates if the idle bit needs to be checked
+
+Return Value:
+
+ TRUE if command sent.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+ UCHAR status;
+
+ //
+ // Wait up to 500 milliseconds for adapter to be ready.
+ //
+
+ for (i=0; i<5000; i++) {
+
+ status = ScsiPortReadPortUchar(&baseIoAddress->StatusRegister);
+
+ if ((status & IOP_COMMAND_DATA_OUT_FULL) ||
+ ( WaitForIdle && !(status & IOP_SCSI_HBA_IDLE))) {
+
+ //
+ // Stall 100 microseconds before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(100);
+
+ } else {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+ }
+ }
+
+ if (i==5000) {
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (4 << 8) | status
+ );
+
+
+ DebugPrint((1, "Aha154x:WriteCommandRegister: Write command timed out\n"));
+ return FALSE;
+ }
+
+ ScsiPortWritePortUchar(&baseIoAddress->CommandRegister, AdapterCommand);
+
+ return TRUE;
+
+} // end WriteCommandRegister()
+
+
+BOOLEAN
+WriteDataRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR DataByte
+ )
+
+/*++
+
+Routine Description:
+
+ Write data byte to data register.
+
+Arguments:
+
+ DeviceExtension - Pointer to adapter extension
+ DataByte - Value to be written to register
+
+Return Value:
+
+ TRUE if byte sent.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+
+ //
+ // Wait up to 500 microseconds for adapter to be idle
+ // and ready for next byte.
+ //
+
+ for (i=0; i<500; i++) {
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_COMMAND_DATA_OUT_FULL) {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+
+ } else {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+ }
+ }
+
+ if (i==500) {
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 8 << 8
+ );
+
+ DebugPrint((1, "Aha154x:WriteDataRegister: Write data timed out\n"));
+ return FALSE;
+ }
+
+ ScsiPortWritePortUchar(&baseIoAddress->CommandRegister, DataByte);
+
+ return TRUE;
+
+} // end WriteDataRegister()
+
+
+BOOLEAN
+FirmwareBug (
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Check to see if the host adapter firmware has the scatter/gather
+ bug.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Return FALSE if there is no firmware bug.
+ Return TRUE if firmware has scatter/gather bug.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR ch;
+ int i;
+
+ //
+ // Issue a RETURN SETUP DATA command
+ // If timeout then return TRUE to indicate that there is a firmware bug.
+ //
+
+ if ((WriteCommandRegister(HwDeviceExtension,
+ AC_RETURN_SETUP_DATA,FALSE)) == FALSE) {
+ return TRUE;
+ }
+
+
+ //
+ // Tell the adapter we want to read in 0x11 bytes.
+ //
+
+ if (WriteDataRegister(HwDeviceExtension,0x11) == FALSE) {
+ return TRUE;
+ }
+
+ //
+ // Now try to read in 0x11 bytes.
+ //
+
+ for (i = 0; i< 0x11; i++) {
+ if (ReadCommandRegister(HwDeviceExtension,&ch,TRUE) == FALSE) {
+ return TRUE;
+ }
+ }
+
+ //
+ // Wait for HACC interrupt.
+ //
+
+ SpinForInterrupt(HwDeviceExtension,FALSE); // eddy
+
+
+ //
+ // Issue SET HA OPTION command.
+ //
+
+ if (WriteCommandRegister(HwDeviceExtension,
+ AC_SET_HA_OPTION,FALSE) == FALSE) {
+ return TRUE;
+ }
+
+ //
+ // Delay 500 microseconds.
+ //
+
+ ScsiPortStallExecution(500);
+
+ //
+ // Check for invalid command.
+ //
+
+ if ( (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_INVALID_COMMAND) ) {
+ //
+ // Clear adapter interrupt.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
+ IOP_INTERRUPT_RESET);
+ return TRUE;
+ }
+
+ //
+ // send 01h
+ //
+
+ if (WriteDataRegister(HwDeviceExtension,0x01) == FALSE) {
+ return TRUE;
+ }
+
+ //
+ // Send same byte as was last received.
+ //
+
+ if (WriteDataRegister(HwDeviceExtension,ch) == FALSE) {
+ return TRUE;
+ }
+
+ //
+ // Clear adapter interrupt.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
+ IOP_INTERRUPT_RESET);
+ return FALSE;
+} // end of FirmwareBug ()
+
+
+VOID
+GetHostAdapterBoardId (
+ IN PVOID HwDeviceExtension,
+ OUT PUCHAR BoardId
+ )
+
+/*++
+
+Routine Description:
+
+ Get board id, firmware id and hardware id from the host adapter.
+ These info are used to determine if the host adapter supports
+ scatter/gather.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Board id, hardware id and firmware id (in that order) by modyfing *BoardId
+ If there is any error, it will just return with *BoardId unmodified
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR firmwareId;
+ UCHAR boardId;
+ UCHAR hardwareId;
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
+ IOP_INTERRUPT_RESET);
+
+ if (!WriteCommandRegister(HwDeviceExtension,AC_ADAPTER_INQUIRY,FALSE)) {
+ return;
+ }
+
+ //
+ // Save byte 0 as board ID.
+ //
+
+ if ((ReadCommandRegister(HwDeviceExtension,&boardId,TRUE)) == FALSE) {
+ return;
+ }
+
+ //
+ // Ignore byte 1. Use hardwareId as scrap storage.
+ //
+
+ if ((ReadCommandRegister(HwDeviceExtension,&hardwareId,TRUE)) == FALSE) {
+ return;
+ }
+
+ //
+ // Save byte 2 as hardware revision in hardwareId.
+ //
+
+ if ((ReadCommandRegister(HwDeviceExtension,&hardwareId,TRUE)) == FALSE) {
+ return;
+ }
+
+ if ((ReadCommandRegister(HwDeviceExtension,&firmwareId,TRUE)) == FALSE) {
+ return;
+ }
+
+
+
+ //
+ // If timeout then return with *BoardId unmodified. This means that
+ // scatter/gather won't be supported.
+ //
+
+ if (!SpinForInterrupt(HwDeviceExtension, TRUE)) { // eddy
+ return;
+ }
+
+ //
+ // Clear adapter interrupt.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,IOP_INTERRUPT_RESET);
+
+ //
+ // Return with appropriate ID's.
+ //
+
+ *BoardId++ = boardId;
+ *BoardId++ = hardwareId;
+ *BoardId++ = firmwareId;
+
+ DebugPrint((2,"board id = %d, hardwareid = %d, firmware id = %d\n",
+ boardId,
+ hardwareId,
+ firmwareId));
+
+} // end of GetHostAdapterBoardId ()
+
+
+BOOLEAN
+ScatterGatherSupported (
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+ Determine if the host adapter supports scatter/gather. On older
+ boards, scatter/gather is not supported. On some boards, there is
+ a bug that causes data corruption on multi-segment WRITE commands.
+ The algorithm to determine whether the board has the scatter/gather
+ bug is not "clean" but there is no other way since the firmware revision
+ levels returned by the host adapter are inconsistent with previous
+ releases.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Return TRUE if the algorithm determines that there is no scatter/gather
+ firmware bug.
+
+ Return FALSE if the algorithm determines that the adapter is an older
+ board or that the firmware contains the scatter gather bug
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR HostAdapterId[3];
+
+ GetHostAdapterBoardId(HwDeviceExtension,&HostAdapterId[0]);
+
+ //
+ // If it's an older board then scatter/gather is not supported.
+ //
+
+ if ((HostAdapterId[BOARD_ID] == OLD_BOARD_ID1) ||
+ (HostAdapterId[BOARD_ID] == OLD_BOARD_ID2) ) {
+ return FALSE;
+ }
+
+ //
+ // If 1540A/B then check for firmware bug.
+ //
+
+ if (HostAdapterId[BOARD_ID] == A154X_BOARD) {
+ if (FirmwareBug(HwDeviceExtension)) {
+ return FALSE;
+ }
+ }
+
+ //
+ // Now check hardware ID and firmware ID.
+ //
+
+ if (HostAdapterId[HARDWARE_ID] != A154X_BAD_HARDWARE_ID) {
+ return TRUE;
+ }
+
+ if (HostAdapterId[FIRMWARE_ID] != A154X_BAD_FIRMWARE_ID) {
+ return TRUE;
+ }
+
+ //
+ // Host adapter has scatter/gather bug.
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,IOP_INTERRUPT_RESET);
+
+ return FALSE;
+
+} // end of ScatterGatherSupported ()
+
+
+BOOLEAN
+SpinForInterrupt(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN TimeOutFlag
+ )
+
+/*++
+
+Routine Description:
+
+ Wait for interrupt.
+
+Arguments:
+
+ DeviceExtension - Pointer to adapter extension
+
+Return Value:
+
+ TRUE if interrupt occurred.
+ FALSE if timed out waiting for interrupt.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+
+ //
+ // Wait up to 5 millisecond for interrupt to occur.
+ //
+
+ for (i=0; i<5000; i++) {
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) & IOP_COMMAND_COMPLETE) {
+
+ //
+ // Interrupt occurred. Break out of wait loop.
+ //
+
+ break;
+
+ } else {
+
+ //
+ // Stall one microsecond.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if ( (i==5000) && (TimeOutFlag == TRUE)) {
+
+ ScsiPortLogError(DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 9 << 8
+ );
+
+ DebugPrint((1, "Aha154x:SpinForInterrupt: Timed out waiting for interrupt\n"));
+
+ return FALSE;
+
+ } else {
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ return TRUE;
+ }
+
+} // end SpinForInterrupt()
+
+
+BOOLEAN UnlockMailBoxes (
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Unlock 1542B+ or 1542C mailboxes so that the driver
+ can zero out mailboxes when it's initializing the adapter.
+
+ The mailboxes are locked if:
+ 1. >1Gb option is enabled (this option is available for 154xB+ and
+ 154xC).
+
+ 2. Dynamic scan lock option is enabled (154xC board only)
+
+ The reason the mailboxes are locked by the adapter's firmware is
+ because the BIOS is now reporting 255/63 translation instead of 64/32.
+ As such, if a user inadvertently enabled the >1Gb option (enabling
+ 255/63 translation) and still uses an old driver, hard disk data
+ will be corrupted. Therefore, the firmware will not allow mailboxes
+ to be initialized unless the user knows what he is doing and updates
+ his driver so that his disk won't be trashed.
+
+Arguments:
+
+ DeviceExtension - Pointer to adapter extension
+
+Return Value:
+
+ TRUE if mailboxes are unlocked.
+ FALSE if mailboxes are not unlocked.
+ Note that if the adapter is just a 154xB board (without the >1Gb
+ option), this routine will return FALSE.
+
+--*/
+
+{
+ UCHAR locktype;
+
+ //
+ // Request information.
+ //
+
+ if (WriteCommandRegister(HwDeviceExtension, AC_GET_BIOS_INFO, TRUE) == FALSE) {
+ return FALSE;
+ }
+
+
+ //
+ // Retrieve first byte.
+ //
+
+ if (ReadCommandRegister(HwDeviceExtension,&locktype,FALSE) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Check for extended bios translation enabled option on 1540C and
+ // 1540B with 1GB support.
+ //
+
+ if (locktype != TRANSLATION_ENABLED) {
+
+ //
+ // Extended translation is disabled. Retrieve lock status.
+ //
+
+ if (ReadCommandRegister(HwDeviceExtension,&locktype,FALSE) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Wait for HACC interrupt.
+ //
+
+ SpinForInterrupt(HwDeviceExtension,FALSE); // eddy
+
+
+ if (locktype == DYNAMIC_SCAN_LOCK) {
+ return(SendUnlockCommand(HwDeviceExtension,locktype));
+ }
+ return FALSE;
+ }
+
+ //
+ // Extended BIOS translation (255/63) is enabled.
+ //
+
+
+ if (ReadCommandRegister(HwDeviceExtension,&locktype,FALSE) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Wait for HACC interrupt.
+ //
+
+ SpinForInterrupt(HwDeviceExtension,FALSE); // eddy
+
+
+ if ((locktype == TRANSLATION_LOCK) || (locktype == DYNAMIC_SCAN_LOCK)) {
+ return(SendUnlockCommand(HwDeviceExtension,locktype));
+ }
+
+ return FALSE;
+} // end of UnlockMailBoxes ()
+
+
+BOOLEAN
+SendUnlockCommand(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR locktype
+ )
+
+/*++
+
+Routine Description:
+
+ Send unlock command to 1542B+ or 1542C board so that the driver
+ can zero out mailboxes when it's initializing the adapter.
+
+
+Arguments:
+
+ DeviceExtension - Pointer to adapter extension
+
+Return Value:
+
+ TRUE if commands are sent successfully.
+ FALSE if not.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+
+ if (WriteCommandRegister(deviceExtension,
+ AC_SET_MAILBOX_INTERFACE,TRUE) == FALSE) {
+ return FALSE;
+ }
+
+ if (WriteDataRegister(deviceExtension,MAILBOX_UNLOCK) == FALSE) {
+ return FALSE;
+ }
+
+ if (WriteDataRegister(deviceExtension,locktype) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ return TRUE;
+} // end of SendUnlockCommand ()
+
+
+ULONG
+AhaParseArgumentString(
+ IN PCHAR String,
+ IN PCHAR KeyWord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will parse the string for a match on the keyword, then
+ calculate the value for the keyword and return it to the caller.
+
+Arguments:
+
+ String - The ASCII string to parse.
+ KeyWord - The keyword for the value desired.
+
+Return Values:
+
+ Zero if value not found
+ Value converted from ASCII to binary.
+
+--*/
+
+{
+ PCHAR cptr;
+ PCHAR kptr;
+ ULONG value;
+ ULONG stringLength = 0;
+ ULONG keyWordLength = 0;
+ ULONG index;
+
+ //
+ // Calculate the string length and lower case all characters.
+ //
+ cptr = String;
+ while (*cptr) {
+
+ if (*cptr >= 'A' && *cptr <= 'Z') {
+ *cptr = *cptr + ('a' - 'A');
+ }
+ cptr++;
+ stringLength++;
+ }
+
+ //
+ // Calculate the keyword length and lower case all characters.
+ //
+ cptr = KeyWord;
+ while (*cptr) {
+
+ if (*cptr >= 'A' && *cptr <= 'Z') {
+ *cptr = *cptr + ('a' - 'A');
+ }
+ cptr++;
+ keyWordLength++;
+ }
+
+ if (keyWordLength > stringLength) {
+
+ //
+ // Can't possibly have a match.
+ //
+ return 0;
+ }
+
+ //
+ // Now setup and start the compare.
+ //
+ cptr = String;
+
+ContinueSearch:
+ //
+ // The input string may start with white space. Skip it.
+ //
+ while (*cptr == ' ' || *cptr == '\t') {
+ cptr++;
+ }
+
+ if (*cptr == '\0') {
+
+ //
+ // end of string.
+ //
+ return 0;
+ }
+
+ kptr = KeyWord;
+ while (*cptr++ == *kptr++) {
+
+ if (*(cptr - 1) == '\0') {
+
+ //
+ // end of string
+ //
+ return 0;
+ }
+ }
+
+ if (*(kptr - 1) == '\0') {
+
+ //
+ // May have a match backup and check for blank or equals.
+ //
+
+ cptr--;
+ while (*cptr == ' ' || *cptr == '\t') {
+ cptr++;
+ }
+
+ //
+ // Found a match. Make sure there is an equals.
+ //
+ if (*cptr != '=') {
+
+ //
+ // Not a match so move to the next semicolon.
+ //
+ while (*cptr) {
+ if (*cptr++ == ';') {
+ goto ContinueSearch;
+ }
+ }
+ return 0;
+ }
+
+ //
+ // Skip the equals sign.
+ //
+ cptr++;
+
+ //
+ // Skip white space.
+ //
+ while ((*cptr == ' ') || (*cptr == '\t')) {
+ cptr++;
+ }
+
+ if (*cptr == '\0') {
+
+ //
+ // Early end of string, return not found
+ //
+ return 0;
+ }
+
+ if (*cptr == ';') {
+
+ //
+ // This isn't it either.
+ //
+ cptr++;
+ goto ContinueSearch;
+ }
+
+ value = 0;
+ if ((*cptr == '0') && (*(cptr + 1) == 'x')) {
+
+ //
+ // Value is in Hex. Skip the "0x"
+ //
+ cptr += 2;
+ for (index = 0; *(cptr + index); index++) {
+
+ if (*(cptr + index) == ' ' ||
+ *(cptr + index) == '\t' ||
+ *(cptr + index) == ';') {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
+ value = (16 * value) + (*(cptr + index) - '0');
+ } else {
+ if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
+ value = (16 * value) + (*(cptr + index) - 'a' + 10);
+ } else {
+
+ //
+ // Syntax error, return not found.
+ //
+ return 0;
+ }
+ }
+ }
+ } else {
+
+ //
+ // Value is in Decimal.
+ //
+ for (index = 0; *(cptr + index); index++) {
+
+ if (*(cptr + index) == ' ' ||
+ *(cptr + index) == '\t' ||
+ *(cptr + index) == ';') {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
+ value = (10 * value) + (*(cptr + index) - '0');
+ } else {
+
+ //
+ // Syntax error return not found.
+ //
+ return 0;
+ }
+ }
+ }
+
+ return value;
+ } else {
+
+ //
+ // Not a match check for ';' to continue search.
+ //
+ while (*cptr) {
+ if (*cptr++ == ';') {
+ goto ContinueSearch;
+ }
+ }
+
+ return 0;
+ }
+}
+
+BOOLEAN
+A4448ReadString(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ PUCHAR theString,
+ UCHAR stringLength,
+ UCHAR stringCommand
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Values:
+
+ True if read was OK.
+ False otherwise.
+
+--*/
+{
+ ULONG ii;
+
+ //
+ // Send in the string command
+ //
+ if (!WriteCommandRegister(deviceExtension, stringCommand, TRUE)) {
+ return FALSE;
+ }
+
+ //
+ // Send in the string length
+ //
+ if (!WriteCommandRegister(deviceExtension, stringLength, FALSE)) {
+ return FALSE;
+ }
+
+ //
+ // Read each byte of the string
+ //
+ for (ii = 0; ii < stringLength; ++ii) {
+ if (!ReadCommandRegister(deviceExtension, &theString[ii],FALSE)) {
+ return FALSE;
+ }
+ }
+
+ //
+ // Wait for interrupt.
+ //
+
+ if (!SpinForInterrupt(deviceExtension,FALSE)) {
+ return FALSE;
+ }
+
+
+ return TRUE;
+
+} // End A4448ReadString
+
+
+BOOLEAN
+A4448IsAmi(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ ULONG portNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine determines if the adapter this driver recognized is an
+ AMI4448. Eddy Quicksall of AMI provided MS with this detection code.
+
+Arguments:
+
+ HwDeviceExtension - Pointer to driver device data area.
+ ConfigInfo - Structure describing this adapter's configuration.
+ portNumber - Indicates the ordinal of the card relative to this driver.
+
+Return Values:
+
+ True if an AMI board.
+ False otherwise.
+
+--*/
+{
+
+ PUCHAR x330IoSpace; // mapped I/O for 330
+ ULONG x330Address; // unmapped 330
+ PX330_REGISTER x330IoBase; // mapped 330 for use with struct X330_REGISTER
+
+ //
+ // this string is only avalable if new BIOS
+ // you will get INVDCMD if an old BIOS or some other manufacturer
+ // if an old BIOS, there is nothing that can be done except to check
+ // the Manufacturers ID if you are on an EISA system
+ //
+ struct _CONFIG_STRING {
+ UCHAR companyString[4]; // AMI<0)
+ UCHAR modelString[6]; // <0>
+ UCHAR seriesString[6]; // 48<0>
+ UCHAR versionString[6]; // 1.00<0)
+ } configString;
+
+ //
+ // Get the system physical address for this card. The card uses I/O space.
+ // This actually just maps the I/O if necessary, it does not reserve it.
+ //
+
+ x330IoSpace = ScsiPortGetDeviceBase(
+ HwDeviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress(portNumber),
+ 4, // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+
+ //
+ // Intel port number
+ //
+
+ x330Address = portNumber;
+
+ //
+ // Check to see if the adapter is present in the system.
+ //
+
+ x330IoBase = (PX330_REGISTER)(x330IoSpace);
+
+ //
+ // Criteria is IDLE and not STST,DIAGF,INVDCMD
+ // but INIT, CDF, and DF are don't cares.
+ //
+ // Can't check for INIT because the driver may already be running if it
+ // is the boot device.
+ //
+
+ if (((ScsiPortReadPortUchar((PUCHAR)x330IoBase)) & (~0x2C)) == 0x10) {
+
+ if (A4448ReadString(HwDeviceExtension, (PUCHAR)&configString,
+ sizeof(configString), AC_AMI_INQUIRY ) &&
+ configString.companyString[0] == 'A' &&
+ configString.companyString[1] == 'M' &&
+ configString.companyString[2] == 'I') {
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/private/ntos/miniport/aha154x/aha154x.h b/private/ntos/miniport/aha154x/aha154x.h
new file mode 100644
index 000000000..6339c4e09
--- /dev/null
+++ b/private/ntos/miniport/aha154x/aha154x.h
@@ -0,0 +1,472 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ aha154x.h
+
+Abstract:
+
+ This module contains the structures, specific to the Adaptec aha154x
+ host bus adapter, used by the SCSI miniport driver. Data structures
+ that are part of standard ANSI SCSI will be defined in a header
+ file that will be available to all SCSI device drivers.
+
+Author:
+
+ Mike Glass December 1990
+ Bill Williams (Adaptec)
+
+Revision History:
+
+--*/
+
+#include "scsi.h"
+
+//
+// The following definitions are used to convert ULONG addresses
+// to Adaptec's 3 byte address format.
+//
+
+typedef struct _THREE_BYTE {
+ UCHAR Msb;
+ UCHAR Mid;
+ UCHAR Lsb;
+} THREE_BYTE, *PTHREE_BYTE;
+
+//
+// Convert four-byte Little Endian to three-byte Big Endian
+//
+
+#define FOUR_TO_THREE(Three, Four) { \
+ ASSERT(!((Four)->Byte3)); \
+ (Three)->Lsb = (Four)->Byte0; \
+ (Three)->Mid = (Four)->Byte1; \
+ (Three)->Msb = (Four)->Byte2; \
+}
+
+#define THREE_TO_FOUR(Four, Three) { \
+ (Four)->Byte0 = (Three)->Lsb; \
+ (Four)->Byte1 = (Three)->Mid; \
+ (Four)->Byte2 = (Three)->Msb; \
+ (Four)->Byte3 = 0; \
+}
+
+//
+// Context information for adapter scan/sniff
+//
+
+typedef struct _SCAN_CONTEXT {
+ ULONG adapterCount;
+ ULONG biosScanStart;
+} SCAN_CONTEXT, *PSCAN_CONTEXT;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CCB - Adaptec SCSI Command Control Block
+//
+// The CCB is a superset of the CDB (Command Descriptor Block)
+// and specifies detailed information about a SCSI command.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Byte 0 Command Control Block Operation Code
+//
+
+#define SCSI_INITIATOR_OLD_COMMAND 0x00
+#define TARGET_MODE_COMMAND 0x01
+#define SCATTER_GATHER_OLD_COMMAND 0x02
+#define SCSI_INITIATOR_COMMAND 0x03
+#define SCATTER_GATHER_COMMAND 0x04
+
+//
+// Byte 1 Address and Direction Control
+//
+
+#define CCB_TARGET_ID_SHIFT 0x06 // CCB Op Code = 00, 02
+#define CCB_INITIATOR_ID_SHIFT 0x06 // CCB Op Code = 01
+#define CCB_DATA_XFER_OUT 0x10 // Write
+#define CCB_DATA_XFER_IN 0x08 // Read
+#define CCB_LUN_MASK 0x07 // Logical Unit Number
+
+//
+// Byte 2 SCSI_Command_Length - Length of SCSI CDB
+//
+// Byte 3 Request Sense Allocation Length
+//
+
+#define FOURTEEN_BYTES 0x00 // Request Sense Buffer size
+#define NO_AUTO_REQUEST_SENSE 0x01 // No Request Sense Buffer
+
+//
+// Bytes 4, 5 and 6 Data Length // Data transfer byte count
+//
+// Bytes 7, 8 and 9 Data Pointer // SGD List or Data Buffer
+//
+// Bytes 10, 11 and 12 Link Pointer // Next CCB in Linked List
+//
+// Byte 13 Command Link ID // TBD (I don't know yet)
+//
+// Byte 14 Host Status // Host Adapter status
+//
+
+#define CCB_COMPLETE 0x00 // CCB completed without error
+#define CCB_LINKED_COMPLETE 0x0A // Linked command completed
+#define CCB_LINKED_COMPLETE_INT 0x0B // Linked complete with interrupt
+#define CCB_SELECTION_TIMEOUT 0x11 // Set SCSI selection timed out
+#define CCB_DATA_OVER_UNDER_RUN 0x12
+#define CCB_UNEXPECTED_BUS_FREE 0x13 // Target dropped SCSI BSY
+#define CCB_PHASE_SEQUENCE_FAIL 0x14 // Target bus phase sequence failure
+#define CCB_BAD_MBO_COMMAND 0x15 // MBO command not 0, 1 or 2
+#define CCB_INVALID_OP_CODE 0x16 // CCB invalid operation code
+#define CCB_BAD_LINKED_LUN 0x17 // Linked CCB LUN different from first
+#define CCB_INVALID_DIRECTION 0x18 // Invalid target direction
+#define CCB_DUPLICATE_CCB 0x19 // Duplicate CCB
+#define CCB_INVALID_CCB 0x1A // Invalid CCB - bad parameter
+
+//
+// Byte 15 Target Status
+//
+// See SCSI.H files for these statuses.
+//
+
+//
+// Bytes 16 and 17 Reserved (must be 0)
+//
+
+//
+// Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block
+//
+
+//
+// Bytes 18+n through 18+m-1, where m=buffer size Allocated for Sense Data
+//
+
+#define REQUEST_SENSE_BUFFER_SIZE 18
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Scatter/Gather Segment List Definitions
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Adapter limits
+//
+
+#define MAX_SG_DESCRIPTORS 17
+#define MAX_TRANSFER_SIZE 64 * 1024
+
+//
+// Scatter/Gather Segment Descriptor Definition
+//
+
+typedef struct _SGD {
+ THREE_BYTE Length;
+ THREE_BYTE Address;
+} SGD, *PSGD;
+
+typedef struct _SDL {
+ SGD Sgd[MAX_SG_DESCRIPTORS];
+} SDL, *PSDL;
+
+#define SEGMENT_LIST_SIZE MAX_SG_DESCRIPTORS * sizeof(SGD)
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CCB Typedef
+//
+
+typedef struct _CCB {
+ UCHAR OperationCode;
+ UCHAR ControlByte;
+ UCHAR CdbLength;
+ UCHAR RequestSenseLength;
+ THREE_BYTE DataLength;
+ THREE_BYTE DataPointer;
+ THREE_BYTE LinkPointer;
+ UCHAR LinkIdentifier;
+ UCHAR HostStatus;
+ UCHAR TargetStatus;
+ UCHAR Reserved[2];
+ UCHAR Cdb[MAXIMUM_CDB_SIZE];
+ PVOID SrbAddress;
+ PVOID AbortSrb;
+ SDL Sdl;
+ UCHAR RequestSenseBuffer[REQUEST_SENSE_BUFFER_SIZE];
+} CCB, *PCCB;
+
+//
+// CCB and request sense buffer
+//
+
+#define CCB_SIZE sizeof(CCB)
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Adapter Command Overview
+//
+// Adapter commands are issued by writing to the Command/Data Out port.
+// They are used to initialize the host adapter and to establish control
+// conditions within the host adapter. They may not be issued when there
+// are outstanding SCSI commands.
+//
+// All adapter commands except Start SCSI(02) and Enable Mailbox-Out
+// Interrupt(05) must be executed only when the IDLE bit (Status bit 4)
+// is one. Many commands require additional parameter bytes which are
+// then written to the Command/Data Out I/O port (base+1). Before each
+// byte is written by the host to the host adapter, the host must verify
+// that the CDF bit (Status bit 3) is zero, indicating that the command
+// port is ready for another byte of information. The host adapter usually
+// clears the Command/Data Out port within 100 microseconds. Some commands
+// require information bytes to be returned from the host adapter to the
+// host. In this case, the host monitors the DF bit (Status bit 2) to
+// determine when the host adapter has placed a byte in the Data In I/O
+// port for the host to read. The DF bit is reset automatically when the
+// host reads the byte. The format of each adapter command is strictly
+// defined, so the host adapter and host system can always agree upon the
+// correct number of parameter bytes to be transferred during a command.
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Host Adapter Command Operation Codes
+//
+
+#define AC_NO_OPERATION 0x00
+#define AC_MAILBOX_INITIALIZATION 0x01
+#define AC_START_SCSI_COMMAND 0x02
+#define AC_START_BIOS_COMMAND 0x03
+#define AC_ADAPTER_INQUIRY 0x04
+#define AC_ENABLE_MBO_AVAIL_INT 0x05
+#define AC_SET_SELECTION_TIMEOUT 0x06
+#define AC_SET_BUS_ON_TIME 0x07
+#define AC_SET_BUS_OFF_TIME 0x08
+#define AC_SET_TRANSFER_SPEED 0x09
+#define AC_RET_INSTALLED_DEVICES 0x0A
+#define AC_RET_CONFIGURATION_DATA 0x0B
+#define AC_ENABLE_TARGET_MODE 0x0C
+#define AC_RETURN_SETUP_DATA 0x0D
+#define AC_WRITE_CHANNEL_2_BUFFER 0x1A
+#define AC_READ_CHANNEL_2_BUFFER 0x1B
+#define AC_WRITE_FIFO_BUFFER 0x1C
+#define AC_READ_FIFO_BUFFER 0x1D
+#define AC_ECHO_COMMAND_DATA 0x1F
+#define AC_SET_HA_OPTION 0x21
+#define AC_RETURN_EEPROM 0x23
+#define AC_GET_BIOS_INFO 0x28
+#define AC_SET_MAILBOX_INTERFACE 0x29
+#define AC_EXTENDED_SETUP_INFO 0x8D
+
+//
+//Adapter commands new to the AHA-154xCP are defined below.
+//
+#define AC_SET_DMS_BUS_SPEED 0x2B
+#define AC_TERMINATION_AND_CABLE_STATUS 0x2C
+#define AC_DEVICE_INQUIRY 0x2D
+#define AC_SCSI_DEVICE_TABLE 0x2E
+#define AC_PERFORM_SCAM 0x2F
+
+//
+// EEPROM define for SCAM
+//
+#define SCSI_BUS_CONTROL_FLAG 0x06
+#define SCAM_ENABLED 0x40
+
+//
+// DMA Transfer Speeds
+//
+
+#define DMA_SPEED_50_MBS 0x00
+
+//
+// I/O Port Interface
+//
+
+typedef struct _BASE_REGISTER {
+ UCHAR StatusRegister;
+ UCHAR CommandRegister;
+ UCHAR InterruptRegister;
+} BASE_REGISTER, *PBASE_REGISTER;
+
+//
+// Base+0 Write: Control Register
+//
+
+#define IOP_HARD_RESET 0x80 // bit 7
+#define IOP_SOFT_RESET 0x40 // bit 6
+#define IOP_INTERRUPT_RESET 0x20 // bit 5
+#define IOP_SCSI_BUS_RESET 0x10 // bit 4
+
+//
+// Base+0 Read: Status
+//
+
+#define IOP_SELF_TEST 0x80 // bit 7
+#define IOP_INTERNAL_DIAG_FAILURE 0x40 // bit 6
+#define IOP_MAILBOX_INIT_REQUIRED 0x20 // bit 5
+#define IOP_SCSI_HBA_IDLE 0x10 // bit 4
+#define IOP_COMMAND_DATA_OUT_FULL 0x08 // bit 3
+#define IOP_DATA_IN_PORT_FULL 0x04 // bit 2
+#define IOP_INVALID_COMMAND 0X01 // bit 1
+
+//
+// Base+1 Write: Command/Data Out
+//
+
+//
+// Base+1 Read: Data In
+//
+
+//
+// Base+2 Read: Interrupt Flags
+//
+
+#define IOP_ANY_INTERRUPT 0x80 // bit 7
+#define IOP_SCSI_RESET_DETECTED 0x08 // bit 3
+#define IOP_COMMAND_COMPLETE 0x04 // bit 2
+#define IOP_MBO_EMPTY 0x02 // bit 1
+#define IOP_MBI_FULL 0x01 // bit 0
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Mailbox Definitions
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Mailbox Definition
+//
+
+#define MB_COUNT 0x08 // number of mailboxes
+
+//
+// Mailbox Out
+//
+
+typedef struct _MBO {
+ UCHAR Command;
+ THREE_BYTE Address;
+} MBO, *PMBO;
+
+//
+// MBO Command Values
+//
+
+#define MBO_FREE 0x00
+#define MBO_START 0x01
+#define MBO_ABORT 0x02
+
+//
+// Mailbox In
+//
+
+typedef struct _MBI {
+ UCHAR Status;
+ THREE_BYTE Address;
+} MBI, *PMBI;
+
+//
+// MBI Status Values
+//
+
+#define MBI_FREE 0x00
+#define MBI_SUCCESS 0x01
+#define MBI_ABORT 0x02
+#define MBI_NOT_FOUND 0x03
+#define MBI_ERROR 0x04
+
+//
+// Mailbox Initialization
+//
+
+typedef struct _MAILBOX_INIT {
+ UCHAR Count;
+ THREE_BYTE Address;
+} MAILBOX_INIT, *PMAILBOX_INIT;
+
+#define MAILBOX_UNLOCK 0x00
+#define TRANSLATION_LOCK 0x01 // mailbox locked for extended BIOS
+#define DYNAMIC_SCAN_LOCK 0x02 // mailbox locked for 154xC
+#define TRANSLATION_ENABLED 0x08 // extended BIOS translation (1023/64)
+
+//
+// Scatter/Gather firmware bug detection
+//
+
+#define BOARD_ID 0x00
+#define HARDWARE_ID 0x01
+#define FIRMWARE_ID 0x02
+#define OLD_BOARD_ID1 0x00
+#define OLD_BOARD_ID2 0x30
+#define A154X_BOARD 0x41
+#define A154X_BAD_HARDWARE_ID 0x30
+#define A154X_BAD_FIRMWARE_ID 0x33
+
+//
+// MCA specific definitions.
+//
+
+#define NUMBER_POS_SLOTS 8
+#define POS_IDENTIFIER 0x0F1F
+#define POS_PORT_MASK 0xC7
+#define POS_PORT_130 0x01
+#define POS_PORT_134 0x41
+#define POS_PORT_230 0x02
+#define POS_PORT_234 0x42
+#define POS_PORT_330 0x03
+#define POS_PORT_334 0x43
+
+typedef struct _POS_DATA {
+ USHORT AdapterId;
+ UCHAR BiosEnabled;
+ UCHAR IoPortInformation;
+ UCHAR ScsiInformation;
+ UCHAR DmaInformation;
+} POS_DATA, *PPOS_DATA;
+
+typedef struct _INIT_DATA {
+
+ ULONG AdapterId;
+ ULONG CardSlot;
+ POS_DATA PosData[NUMBER_POS_SLOTS];
+
+} INIT_DATA, *PINIT_DATA;
+
+
+//
+// Real Mode Adapter Config Info
+//
+typedef struct _RM_SAVRES {
+ UCHAR SDTPar;
+ UCHAR TxSpeed;
+ UCHAR BusOnTime;
+ UCHAR BusOffTime;
+ UCHAR NumMailBoxes;
+ UCHAR MBAddrHiByte;
+ UCHAR MBAddrMiByte;
+ UCHAR MBAddrLoByte;
+ UCHAR SyncNeg[8];
+ UCHAR DisOpt;
+
+} RM_CFG, *PRM_CFG;
+
+//
+//AMI Detect Code
+//
+#define AC_AMI_INQUIRY 0x41 // Get model number, ect. (ASCIIZ)
+
+//
+// I/O Port Interface
+//
+
+typedef struct _X330_REGISTER {
+ UCHAR StatusRegister;
+ UCHAR CommandRegister;
+ UCHAR InterruptRegister;
+ UCHAR DiagRegister;
+} X330_REGISTER, *PX330_REGISTER;
diff --git a/private/ntos/miniport/aha154x/aha154x.rc b/private/ntos/miniport/aha154x/aha154x.rc
new file mode 100644
index 000000000..8c1fae3be
--- /dev/null
+++ b/private/ntos/miniport/aha154x/aha154x.rc
@@ -0,0 +1,90 @@
+//***************************************************************************
+//
+// Copyright 1992-1994 Adaptec, Inc. All rights reserved. This software
+// contains the valuable trade secrets of Adaptec. The software is
+// protected under copyright laws as an unpublished work of Adaptec.
+// Notice is for informational purposes only and does not imply publication.
+// The user of this software may make copies of the software for use with
+// parts manufactured by Adaptec or under license from Adaptec and for no
+// other use.
+//
+//***************************************************************************
+
+
+//===========================================================================
+//
+// Module Name:
+//
+// aha154x.rc
+//
+// Abstract:
+//
+// This is the miniport resource file for the aha154x series miniport
+// driver.
+//
+// Author:
+//
+// Bill Williams
+// James Goodwin
+//
+// Environment:
+//
+// kernel mode only
+//
+// Notes:
+//
+// Revision History:
+//
+// Indentation:
+//
+// 4 spaces per tab
+//
+//===========================================================================
+
+#include <windows.h>
+#include <ntverp.h>
+
+//
+// This is the DCS label for the version of the sources from which the driver
+// was built.
+//
+#define SOURCE_VERSION "JSG003"
+
+//
+// Declared miniport version number. Every unique binary released for any reason
+// must have a unique version number.
+//
+#define MINIPORT_VERSION "v1.13"
+
+#if (defined _INCLUDE_DEV_BANNER)
+ //
+ // DEV_BANNER should always include a leading space before text.
+ //
+ #define DEV_BANNER " "
+#else
+ #define DEV_BANNER
+#endif
+
+
+//
+// This defines the copyright years for your driver.
+//
+#define VER_LEGALCOPYRIGHT_YEARS "1992-1995"
+
+//
+// The defines below this line should not be changed. The defines listed above
+// should be set for each driver release.
+//
+//****************************************************************************
+
+//#define VER_COMPANYNAME_STR "Adaptec, Inc."
+#define VER_INTERNALNAME_STR SOURCE_VERSION
+#define VER_FILEVERSION_STR MINIPORT_VERSION DEV_BANNER
+#define VER_FILEDESCRIPTION_STR "Adaptec AHA-154x series SCSI miniport"
+#define VER_ORIGINALFILENAME_STR "aha154x.sys"
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Adaptec, Inc. " VER_LEGALCOPYRIGHT_YEARS
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/aha154x/aha154x.sys b/private/ntos/miniport/aha154x/aha154x.sys
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/private/ntos/miniport/aha154x/aha154x.sys
diff --git a/private/ntos/miniport/aha154x/makefile b/private/ntos/miniport/aha154x/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/miniport/aha154x/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/aha154x/sources b/private/ntos/miniport/aha154x/sources
new file mode 100644
index 000000000..e799e943a
--- /dev/null
+++ b/private/ntos/miniport/aha154x/sources
@@ -0,0 +1,40 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=aha154x
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntoskrnl.lib
+
+#C_DEFINES=-D_SCAM_ENABLED
+
+SOURCES=aha154x.c \
+ aha154x.rc
diff --git a/private/ntos/miniport/aha174x/aha174x.c b/private/ntos/miniport/aha174x/aha174x.c
new file mode 100644
index 000000000..b46eb1084
--- /dev/null
+++ b/private/ntos/miniport/aha174x/aha174x.c
@@ -0,0 +1,2005 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ aha174x.c
+
+Abstract:
+
+ This is the port driver for the AHA174X SCSI adapter.
+
+Authors:
+
+ Mike Glass
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "aha174x.h" // includes scsi.h
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ PEISA_CONTROLLER EisaController;
+
+ UCHAR HostTargetId;
+
+ PSCSI_REQUEST_BLOCK PendingSrb;
+
+ UCHAR RequestCount[8][8];
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+//
+// Define the maximum number of outstanding I/O requests per logical unit.
+//
+
+#define MAX_QUEUE_DEPTH 2
+
+
+//
+// Function declarations
+//
+// Functions that start with 'Aha174x' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+Aha174xEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+Aha174xConfiguration(
+ IN PVOID DeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+Aha174xInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Aha174xStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+Aha174xInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Aha174xResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+//
+// This function is called from Aha174xStartIo.
+//
+
+VOID
+A174xBuildEcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from A174xBuildEcb.
+//
+
+VOID
+A174xBuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+A174xBuildRequestSense(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+A174xSendCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR OperationCode,
+ IN ULONG Address
+ );
+
+//
+// This function is called from Aha174xInterrupt.
+//
+
+VOID
+A174xMapStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PSTATUS_BLOCK StatusBlock
+ );
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ return Aha174xEntry(DriverObject, Argument2);
+
+} // end DriverEntry()
+
+
+ULONG
+Aha174xEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from DriverEntry if this driver is installable
+ or directly from the system if the driver is built into the kernel.
+ It scans the EISA slots looking for an AHA174X that is configured
+ to the ENHANCED mode.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ ULONG AdapterCount = 0;
+
+ DebugPrint((1,"\n\nSCSI Aha174x MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = Aha174xInitialize;
+ hwInitializationData.HwFindAdapter = Aha174xConfiguration;
+ hwInitializationData.HwStartIo = Aha174xStartIo;
+ hwInitializationData.HwInterrupt = Aha174xInterrupt;
+ hwInitializationData.HwResetBus = Aha174xResetBus;
+
+ //
+ // Set number of access ranges and bus type.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 2;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Indicate auto request sense is supported.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ //
+ // Ask for SRB extensions for ECBs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(ECB);
+
+ return ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &AdapterCount);
+
+} // end Aha174xEntry()
+
+
+ULONG
+Aha174xConfiguration(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo - Configuration information structure describing HBA
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ ULONG eisaSlotNumber;
+ PVOID eisaAddress;
+ UCHAR dataByte;
+ PULONG adapterCount = Context;
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ for (eisaSlotNumber=*adapterCount + 1; eisaSlotNumber<MAXIMUM_EISA_SLOTS; eisaSlotNumber++) {
+
+ //
+ // Update the adapter count to indicate this slot has been checked.
+ //
+
+ (*adapterCount)++;
+
+ //
+ // Get the system address for this card.
+ // The card uses I/O space.
+ //
+
+ eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ TRUE);
+
+ eisaController =
+ (PEISA_CONTROLLER)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE);
+
+ if (ScsiPortReadPortUchar(&eisaController->BoardId[0]) == 0x04 &&
+ ScsiPortReadPortUchar(&eisaController->BoardId[1]) == 0x90 &&
+ (ScsiPortReadPortUchar(&eisaController->BoardId[2]) == 0x00 ||
+ ScsiPortReadPortUchar(&eisaController->BoardId[2]) == 0x04)) {
+
+ DebugPrint((1,"AHA174X: Adapter found at EISA slot %d\n",
+ eisaSlotNumber));
+#ifdef MIPS
+ //
+ // Add code to configure the device if necessary. This is only
+ // needed until we get an EISA configuration program.
+ //
+
+ if (!(ScsiPortReadPortUchar(&eisaController->EBControl) & 0x1)) {
+
+ //
+ // The card as not been configured. Jam in a default one.
+ // Enable the card, enable enhanced mode operation, set the
+ // irql to 14, set the target id to 7 and enable the DMA.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->EBControl, 1);
+ ScsiPortWritePortUchar(&eisaController->PortAddress, 0x80);
+ ScsiPortWritePortUchar(&eisaController->BiosAddress, 0x00);
+ ScsiPortWritePortUchar(&eisaController->Interrupt, 0x1d);
+ ScsiPortWritePortUchar(&eisaController->ScsiId, 0x7);
+ ScsiPortWritePortUchar(&eisaController->DmaChannel, 0x2);
+ ScsiPortStallExecution(1000);
+
+ }
+#endif
+ if (ScsiPortReadPortUchar(&eisaController->PortAddress) &
+ ENHANCED_INTERFACE_ENABLED) {
+
+ //
+ // An adapter with the enhanced interface enabled was found.
+ //
+
+ break;
+
+ } else {
+
+ DebugPrint((1,"AHA174X: Adapter is in STANDARD mode\n"));
+ }
+ }
+
+ //
+ // If an adapter was not found unmap it.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension,
+ eisaAddress);
+
+ } // end for (eisaSlotNumber ...
+
+ if (!(eisaSlotNumber < MAXIMUM_EISA_SLOTS)) {
+
+ //
+ // No adapter was found. Indicate that we are done and there are no
+ // more adapters here. Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *adapterCount = 0;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // There is still more to look at.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Store base address of EISA registers in device extension.
+ //
+
+ deviceExtension->EisaController = eisaController;
+
+ ConfigInfo->InitiatorBusId[0] =
+ ScsiPortReadPortUchar(&eisaController->ScsiId) & 0x0F;
+
+ deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0];
+
+ //
+ // Indicate maximum transfer length in bytes.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE;
+
+ //
+ // Maximum number of physical segments is 32.
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS;
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ dataByte = ScsiPortReadPortUchar(&eisaController->Interrupt);
+ ConfigInfo->BusInterruptLevel = (dataByte & 7) + 9;
+
+ //
+ // Determine level or edge interrupt.
+ //
+
+ ConfigInfo->InterruptMode = dataByte & 0x08 ? Latched : LevelSensitive;
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + EISA_ADDRESS_BASE);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+
+ //
+ // Determine the BIOS address.
+ //
+
+ dataByte = ScsiPortReadPortUchar(&eisaController->BiosAddress);
+
+ if (dataByte & BIOS_ENABLED) {
+
+ dataByte &= BIOS_ADDRESS;
+
+ //
+ // Calculate the bios base address.
+ //
+
+ eisaSlotNumber = 0xC0000 + (dataByte * 0x4000);
+
+ if (eisaSlotNumber < 0xF0000) {
+
+ DebugPrint((1, "Aha174xConfiguration: Bios address at: %lx.\n", eisaSlotNumber));
+ (*ConfigInfo->AccessRanges)[1].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(eisaSlotNumber);
+ (*ConfigInfo->AccessRanges)[1].RangeLength = BIOS_LENGTH;
+ (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE;
+
+ }
+ }
+
+ return SP_RETURN_FOUND;
+
+} // end Aha174xConfiguration()
+
+
+BOOLEAN
+Aha174xInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter and mailbox.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ //
+ // Reset Aha174x and SCSI bus.
+ //
+
+ if (!Aha174xResetBus(deviceExtension, 0)) {
+
+ DebugPrint((1, "Aha174xInitialize: Reset bus failed\n"));
+ return FALSE;
+
+ } else {
+
+ ScsiPortNotification(ResetDetected, deviceExtension, 0);
+
+ return TRUE;
+ }
+
+} // end Aha174xInitialize()
+
+
+BOOLEAN
+Aha174xStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to send an ECB or issue an immediate command.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PECB ecb;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ UCHAR opCode;
+ ULONG physicalEcb;
+ ULONG length;
+ ULONG i = 0;
+ UCHAR count = MAX_QUEUE_DEPTH;
+
+ ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
+
+ //
+ // Get ECB from SRB.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ abortedSrb = ScsiPortGetSrb(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ if (abortedSrb != Srb->NextSrb ||
+ abortedSrb->SrbStatus != SRB_STATUS_PENDING) {
+
+ DebugPrint((1, "A174xStartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get ECB to abort.
+ //
+
+ ecb = Srb->NextSrb->SrbExtension;
+
+ //
+ // Set abort SRB for completion.
+ //
+
+ ecb->AbortSrb = Srb;
+
+ } else {
+
+ ecb = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in ECB.
+ //
+
+ ecb->SrbAddress = Srb;
+ ecb->AbortSrb = NULL;
+
+ }
+
+ //
+ // Get ECB physical address.
+ //
+
+ physicalEcb =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, ecb, &length));
+
+ //
+ // Assume physical address is contiguous for size of ECB.
+ //
+
+ ASSERT(length >= sizeof(ECB));
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Build ECB for regular request or request sense.
+ //
+
+ if (Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
+ A174xBuildRequestSense(deviceExtension, Srb);
+ } else {
+ A174xBuildEcb(deviceExtension, Srb);
+ }
+
+ //
+ // Increment the request count.
+ //
+
+ count = ++deviceExtension->RequestCount[Srb->TargetId][Srb->Lun];
+
+ opCode = START_ECB;
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1, "Aha174xStartIo: Abort request received\n"));
+
+ opCode = ABORT_ECB;
+
+ break;
+
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ if (!A174xSendCommand(deviceExtension,
+ (UCHAR)(opCode | Srb->TargetId),
+ physicalEcb)) {
+
+ DebugPrint((1,"Aha174xStartIo: Send command timed out\n"));
+
+ //
+ // Save the request utill a pending one completes.
+ //
+
+ deviceExtension->PendingSrb = Srb;
+
+ return(TRUE);
+
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+
+ if (count < MAX_QUEUE_DEPTH) {
+
+ //
+ // Request another request for this logical unit.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ } else {
+
+ //
+ // Request another request for this adapter.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ }
+
+ return TRUE;
+
+} // end Aha174xStartIo()
+
+
+BOOLEAN
+Aha174xInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the Aha174x SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the ECB is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PECB ecb;
+ PSCSI_REQUEST_BLOCK srb;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PSTATUS_BLOCK statusBlock;
+ UCHAR targetId;
+ UCHAR lun;
+ ULONG physicalEcb;
+ UCHAR interruptStatus;
+
+ //
+ // Check interrupt pending.
+ //
+
+ if (!(ScsiPortReadPortUchar(&eisaController->Status) &
+ INTERRUPT_PENDING)) {
+
+ DebugPrint((4, "Aha174xInterrupt: Spurious interrupt\n"));
+ return FALSE;
+ }
+
+ //
+ // Read interrupt status.
+ //
+
+ interruptStatus = ScsiPortReadPortUchar(
+ &eisaController->InterruptStatus);
+
+ //
+ // Get targetId
+ //
+
+ targetId = interruptStatus & 0x0F;
+
+ //
+ // Get physical address of ECB.
+ //
+
+ physicalEcb = ScsiPortReadPortUlong(&eisaController->MailBoxIn);
+
+ //
+ // Acknowledge interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->Control, CLEAR_INTERRUPT);
+
+ //
+ // Check for pending requests. If there is one then start it.
+ //
+
+ if (deviceExtension->PendingSrb != NULL) {
+
+ srb = deviceExtension->PendingSrb;
+ deviceExtension->PendingSrb = NULL;
+
+ Aha174xStartIo(deviceExtension, srb);
+
+ }
+
+ switch (interruptStatus>>4) {
+
+ case ECB_COMPLETE_SUCCESS:
+ case ECB_COMPLETE_SUCCESS_RETRY:
+
+ //
+ // Get virtual ECB address.
+ //
+
+ ecb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalEcb));
+
+ //
+ // Make sure this was a valid physical address.
+ //
+
+ if (ecb == NULL || ecb->SrbAddress == NULL) {
+ break;
+ }
+
+ //
+ // Get SRB from ECB.
+ //
+
+ srb = ecb->SrbAddress;
+
+ //
+ // Clear SRB from ECB.
+ //
+
+ ecb->SrbAddress = NULL;
+
+ //
+ // Update SRB statuses.
+ //
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ //
+ // If there is a peneding abort request, then complete it.
+ // This adapter does not interrupt when an abort completes.
+ // So one of three cases will occur:
+ // The abort succeeds and the command is termainated.
+ // The abort is too late and command termainates.
+ // The abort fails but the command does not terminate.
+ // The first two cases are handled by completing the abort when the
+ // command completes. The last case is handled by the abort timing
+ // out.
+ //
+
+ if (ecb->AbortSrb != NULL) {
+
+ ecb->AbortSrb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ //
+ // Complete the abort request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ deviceExtension,
+ ecb->AbortSrb
+ );
+
+ ecb->AbortSrb = NULL;
+ }
+
+ if (deviceExtension->RequestCount[srb->TargetId][srb->Lun]--
+ == MAX_QUEUE_DEPTH) {
+
+ //
+ // The adapter can now take another request for this device.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun);
+
+ }
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ return TRUE;
+
+ case ECB_COMPLETE_ERROR:
+
+ //
+ // Get virtual ECB address.
+ //
+
+ ecb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalEcb));
+
+ //
+ // Make sure this was a valid physical address.
+ //
+
+ if (ecb == NULL || ecb->SrbAddress == NULL) {
+ break;
+ }
+
+ //
+ // Get SRB from ECB.
+ //
+
+ srb = ecb->SrbAddress;
+
+ //
+ // Clear SRB from ECB.
+ //
+
+ ecb->SrbAddress = NULL;
+
+ //
+ // Get Status Block virtual address.
+ //
+
+ statusBlock = ScsiPortGetVirtualAddress(deviceExtension,
+ ScsiPortConvertUlongToPhysicalAddress(ecb->StatusBlockAddress));
+
+ //
+ // If there is a peneding abort request, then complete it.
+ // This adapter does not interrupt when an abort completes.
+ // So one of three cases will occur:
+ // The abort succeeds and the command is termainated.
+ // The abort is too late and command termainates.
+ // The abort fails but the command does not terminate.
+ // The first two cases are handled by completing the abort when the
+ // command completes. The last case is handled by the abort timing
+ // out.
+ //
+
+ if (ecb->AbortSrb != NULL) {
+
+ ecb->AbortSrb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ //
+ // Complete the abort request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ deviceExtension,
+ ecb->AbortSrb
+ );
+
+ ecb->AbortSrb = NULL;
+ }
+
+ //
+ // Update SRB status.
+ //
+
+ A174xMapStatus(deviceExtension, srb, statusBlock);
+
+ if (deviceExtension->RequestCount[srb->TargetId][srb->Lun]--
+ == MAX_QUEUE_DEPTH) {
+
+ //
+ // The adapter can now take another request for this device.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun);
+
+ }
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ return TRUE;
+
+ case IMMEDIATE_COMMAND_SUCCESS:
+
+ DebugPrint((2,"Aha174xInterrupt: Immediate command completed\n"));
+ return TRUE;
+
+ case ASYNCHRONOUS_EVENT_NOTIFICATION:
+
+ //
+ // Check if bus was reset.
+ //
+
+ if ((physicalEcb >> 24) == 0x23) {
+
+ //
+ // Clear the reqeust counts.
+ //
+
+ for (targetId = 0; targetId < 8; targetId++) {
+ for (lun = 0; lun < 8; lun++) {
+
+ deviceExtension->RequestCount[targetId][lun] = 0;
+ }
+ }
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ 0,
+ SP_UNTAGGED,
+ 0,
+ SRB_STATUS_BUS_RESET);
+
+
+ //
+ // Notify operating system of SCSI bus reset.
+ //
+
+ ScsiPortNotification(ResetDetected,
+ deviceExtension,
+ NULL);
+ }
+
+ return TRUE;
+
+ case IMMEDIATE_COMMAND_ERROR:
+ default:
+
+ DebugPrint((1, "A174xInterrupt: Unrecognized interrupt status %x\n",
+ interruptStatus));
+
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 1 << 16 | interruptStatus
+ );
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 5 << 16 | interruptStatus
+ );
+
+ return TRUE;
+
+} // end Aha174xInterrupt()
+
+
+VOID
+A174xBuildEcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build ECB for Aha174x.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PECB ecb = Srb->SrbExtension;
+ PSTATUS_BLOCK statusBlock = &ecb->StatusBlock;
+ ULONG length;
+
+ //
+ // Set ECB command.
+ //
+
+ ecb->Command = ECB_COMMAND_INITIATOR_COMMAND;
+
+ //
+ // Disable updating status block on success;
+ //
+
+ ecb->Flags[0] = ECB_FLAGS_DISABLE_STATUS_BLOCK;
+
+ //
+ // initialize ECB flags
+ //
+
+ ecb->Flags[1] = 0;
+
+ //
+ // Set transfer direction bit.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ //
+ // Write command.
+ //
+
+ ecb->Flags[1] |= ECB_FLAGS_WRITE;
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ //
+ // Read command.
+ //
+
+ ecb->Flags[1] |= ECB_FLAGS_READ;
+ }
+
+ //
+ // Check if disconnect explicity forbidden.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
+
+ ecb->Flags[1] |= ECB_FLAGS_NO_DISCONNECT;
+ }
+
+ //
+ // Set LUN (bits 16, 17 and 18).
+ //
+
+ ecb->Flags[1] |= Srb->Lun;
+
+ //
+ // Set CDB length and copy to ECB.
+ //
+
+ ecb->CdbLength = Srb->CdbLength;
+ ScsiPortMoveMemory(ecb->Cdb, Srb->Cdb, Srb->CdbLength);
+
+ //
+ // Build SGL in ECB if data transfer.
+ //
+
+ if (Srb->DataTransferLength > 0) {
+ ecb->Flags[0] |= ECB_FLAGS_SCATTER_GATHER;
+ A174xBuildSgl(DeviceExtension, Srb);
+ } else {
+ ecb->SglLength = 0;
+ }
+
+ //
+ // Set status block pointer.
+ //
+
+ ecb->StatusBlockAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ statusBlock,
+ &length));
+
+ ASSERT(length >= sizeof(STATUS_BLOCK));
+
+ //
+ // Setup auto sense if necessary.
+ //
+
+ if (Srb->SenseInfoBufferLength != 0 &&
+ !(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)) {
+
+ //
+ // Set the flag to enable auto sense and fill in the address and length
+ // of the sense buffer.
+ //
+
+ ecb->Flags[0] |= ECB_FLAGS_AUTO_REQUEST_SENSE;
+ ecb->SenseInfoLength = Srb->SenseInfoBufferLength;
+ ecb->SenseInfoAddress = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ Srb->SenseInfoBuffer,
+ &length));
+
+ ASSERT(length >= Srb->SenseInfoBufferLength);
+
+ } else {
+
+ ecb->SenseInfoLength = 0;
+ }
+
+ //
+ // Zero out next ECB, request sense info fields
+ // and statuses in status block.
+ //
+
+ ecb->NextEcb = 0;
+ statusBlock->HaStatus = 0;
+ statusBlock->TargetStatus = 0;
+
+ return;
+
+} // end A174xBuildEcb()
+
+
+VOID
+A174xBuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list for the ECB.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PECB ecb = Srb->SrbExtension;
+ PSGL sgl = &ecb->Sgl;
+ ULONG physicalSgl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG descriptorCount = 0;
+
+ //
+ // Get physical SGL address.
+ //
+
+ physicalSgl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sgl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SGL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SGL));
+
+ //
+ // Create SGL segment descriptors.
+ //
+
+ do {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ sgl->Descriptor[descriptorCount].Address = physicalAddress;
+ sgl->Descriptor[descriptorCount].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ //
+ // Write SGL length to ECB.
+ //
+
+ ecb->SglLength = descriptorCount * sizeof(SG_DESCRIPTOR);
+
+ //
+ // Write SGL address to ECB.
+ //
+
+ ecb->PhysicalSgl = physicalSgl;
+
+ return;
+
+} // end A174xBuildSgl()
+
+
+VOID
+A174xBuildRequestSense(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a request sense is detected. An adapter
+ command is then built for a request sense. This is the
+ only way to clear the contingent alligience condition that the adapter
+ is always in following a check condition.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE is request succeeds.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PECB ecb = Srb->SrbExtension;
+ PSTATUS_BLOCK statusBlock = &ecb->StatusBlock;
+ ULONG length;
+
+ //
+ // Set ECB command.
+ //
+
+ ecb->Command = ECB_COMMAND_READ_SENSE_INFO;
+
+ //
+ // Disable updating status block on success and enable
+ // automatic request senes.
+ //
+
+ ecb->Flags[0] = ECB_FLAGS_DISABLE_STATUS_BLOCK |
+ ECB_FLAGS_SUPPRESS_UNDERRUN;
+
+ //
+ // Set transfer direction bit.
+ //
+
+ ecb->Flags[1] = ECB_FLAGS_READ;
+
+ //
+ // Check if disconnect explicity forbidden.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
+
+ ecb->Flags[1] |= ECB_FLAGS_NO_DISCONNECT;
+ }
+
+ //
+ // Set LUN (bits 16, 17 and 18).
+ //
+
+ ecb->Flags[1] |= Srb->Lun;
+
+ //
+ // Set status block pointer.
+ //
+
+ ecb->StatusBlockAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ statusBlock,
+ &length));
+
+ //
+ // Set request sense address and length.
+ //
+
+ ecb->SenseInfoAddress = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ Srb,
+ Srb->DataBuffer,
+ &length));
+
+ ASSERT(length >= Srb->DataTransferLength);
+
+ ecb->SenseInfoLength = (UCHAR) Srb->DataTransferLength;
+
+ //
+ // Zero out next ECB, request sense info fields
+ // and statuses in status block.
+ //
+
+ ecb->NextEcb = 0;
+ statusBlock->HaStatus = 0;
+ statusBlock->TargetStatus = 0;
+
+ return;
+
+} // end A174xBuildRequestSense()
+
+
+BOOLEAN
+A174xSendCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR OperationCode,
+ IN ULONG Address
+ )
+
+/*++
+
+Routine Description:
+
+ Send ECB or immediate command to AHA174X.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ OperationCode - value to be written to attention register
+ Address - ECB address or immediate command
+
+Return Value:
+
+ True if command sent.
+ False if adapter never reached 'ready for next command' state.
+
+--*/
+
+{
+ PEISA_CONTROLLER eisaController = DeviceExtension->EisaController;
+ ULONG i;
+
+ for (i=0; i<10; i++) {
+
+ UCHAR status;
+
+ status = ScsiPortReadPortUchar(&eisaController->Status);
+
+ if ((status & MAILBOX_OUT_EMPTY) &&
+ !(status & ADAPTER_BUSY)) {
+
+ //
+ // Adapter ready for next command.
+ //
+
+ break;
+
+ } else {
+
+ //
+ // Stall 50 microseconds before trying again.
+ //
+
+ ScsiPortStallExecution(50);
+ }
+ }
+
+ if (i == 10) {
+
+ return FALSE;
+ }
+
+ //
+ // Write ECB address or immediate command.
+ //
+
+ ScsiPortWritePortUlong(&eisaController->MailBoxOut, Address);
+
+ //
+ // Write operation code to attention register.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->Attention, OperationCode);
+
+ return TRUE;
+
+} // end A174xSendCommand()
+
+BOOLEAN
+Aha174xResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Aha174x SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ ULONG j;
+ UCHAR targetId;
+ UCHAR lun;
+
+
+ UNREFERENCED_PARAMETER(PathId);
+
+ DebugPrint((2,"ResetBus: Reset Aha174x and SCSI bus\n"));
+
+ //
+ // Clean up pending requests.
+ //
+
+ if (deviceExtension->PendingSrb) {
+
+ //
+ // Notify the port driver that another request can be accepted.
+ //
+
+ ScsiPortNotification(NextRequest, deviceExtension);
+
+ //
+ // Clear the pending request. It will be completed by
+ // ScsiPortCompleteRequest.
+ //
+
+ deviceExtension->PendingSrb = NULL;
+
+ }
+
+ //
+ // Clear the reqeust counts.
+ //
+
+ for (targetId = 0; targetId < 8; targetId++) {
+ for (lun = 0; lun < 8; lun++) {
+
+ deviceExtension->RequestCount[targetId][lun] = 0;
+ }
+ }
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ 0,
+ SP_UNTAGGED,
+ SP_UNTAGGED,
+ SRB_STATUS_BUS_RESET);
+
+ targetId = deviceExtension->HostTargetId;
+
+ //
+ // Allow the adapter card to settle.
+ //
+
+ ScsiPortStallExecution(75000);
+ ScsiPortReadPortUchar(&eisaController->Status);
+ ScsiPortStallExecution(1);
+
+ if (!A174xSendCommand(deviceExtension,
+ (UCHAR)(IMMEDIATE_COMMAND | targetId),
+ ECB_IMMEDIATE_RESET)) {
+
+ //
+ // Timed out waiting for adapter to become ready.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4 << 16
+ );
+
+ //
+ // Adapter never reached state to receive command.
+ // Try a hard reset by wiggling the control line.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->Control, HARD_RESET);
+
+ //
+ // Wait at least 10 microseconds.
+ //
+
+ ScsiPortStallExecution(10);
+
+ //
+ // Clear the reset line now that it has been held for 10 us.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->Control, 0);
+
+ //
+ // Write the attention register to wake up the firmware so that
+ // it will clear the busy line in the status register.
+ // The attention value written (0) is ignored by the controller
+ // but will wakeup the firmware.
+ //
+
+ ScsiPortStallExecution(20000); // Add a little delay
+ ScsiPortWritePortUchar(&eisaController->Attention, 0);
+
+ //
+ // Wait for busy to go low.
+ //
+
+ j = 0;
+ while (ScsiPortReadPortUchar(&eisaController->Status) & ADAPTER_BUSY) {
+
+ j++;
+ if (j > 200000) {
+
+ //
+ // Busy has not gone low. Assume the card is gone.
+ // Log the error and fail the request.
+ //
+
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 16
+ );
+
+ return FALSE;
+
+ }
+
+ ScsiPortStallExecution(10);
+ }
+ }
+
+ return TRUE;
+
+} // end Aha174xResetBus()
+
+
+VOID
+A174xMapStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PSTATUS_BLOCK StatusBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Translate Aha174x error to SRB error.
+
+Arguments:
+
+ SRB
+ Status block for request completing with error.
+
+Return Value:
+
+ Updated SRB
+
+--*/
+
+{
+ ULONG logError = 0;
+ UCHAR srbStatus;
+ PECB ecb = Srb->SrbExtension;
+
+
+ DebugPrint((2,
+ "A174xMapStatus: Status word is %x\n",
+ StatusBlock->StatusWord));
+
+ if (StatusBlock->TargetStatus == SCSISTAT_CHECK_CONDITION) {
+
+ //
+ // A check condition occured. Set the srb status and process the
+ // auto sense data.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+
+ //
+ // Set target SCSI status in SRB.
+ //
+
+ Srb->ScsiStatus = StatusBlock->TargetStatus;
+
+ //
+ // Update SRB with actual bytes transferred.
+ //
+
+ Srb->DataTransferLength -= StatusBlock->ResidualByteCount;
+
+ if (StatusBlock->StatusWord & SB_STATUS_SENSE_INFORMATION) {
+
+ //
+ // Indicate the sense information is valid and update the length.
+ //
+
+ Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ Srb->SenseInfoBufferLength = StatusBlock->RequestSenseLength;
+ }
+
+ return;
+ }
+
+ switch (StatusBlock->HaStatus) {
+
+ case SB_HASTATUS_SELECTION_TIMEOUT:
+ srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case SB_HASTATUS_DATA_OVERUNDER_RUN:
+ DebugPrint((1,"A174xMapStatus: Data over/underrun\n"));
+
+ //
+ // Update SRB with actual bytes transferred.
+ //
+
+ Srb->DataTransferLength -= StatusBlock->ResidualByteCount;
+
+ srbStatus = SRB_STATUS_DATA_OVERRUN;
+ break;
+
+ case SB_HASTATUS_UNEXPECTED_BUS_FREE:
+ DebugPrint((1,"A174xMapStatus: Unexpected bus free\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ break;
+
+ case SB_HASTATUS_INVALID_BUS_PHASE:
+ DebugPrint((1,"A174xMapStatus: Invalid bus phase\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ break;
+
+ case SB_HASTATUS_TARGET_NOT_USED:
+ DebugPrint((1,"A174xMapStatus: Target not used\n"));
+ srbStatus = SRB_STATUS_NO_DEVICE;
+ break;
+
+ case SB_HASTATUS_INVALID_ECB:
+ DebugPrint((1,"A174xMapStatus: Invalid ECB\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case SB_HASTATUS_ADAPTER_HARDWARE_ERROR:
+ DebugPrint((1,"A174xMapStatus: Hardware error\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SB_HASTATUS_ADAPTER_RESET_BUS:
+ DebugPrint((1,"A174xMapStatus: Adapter reset bus\n"));
+ srbStatus = SRB_STATUS_BUS_RESET;
+ break;
+
+ case SB_HASTATUS_DEVICE_RESET_BUS:
+ DebugPrint((1,"A174xMapStatus: Device reset bus\n"));
+ srbStatus = SRB_STATUS_BUS_RESET;
+ break;
+
+ case SB_HASTATUS_CHECKSUM_FAILURE:
+ DebugPrint((1,"A174xMapStatus: Checksum failure\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SB_HASTATUS_ADAPTER_ABORTED:
+ DebugPrint((1,"A174xMapStatus: Adapter aborted\n"));
+ srbStatus = SRB_STATUS_ABORTED;
+ break;
+
+ case SB_HASTATUS_HOST_ABORTED:
+ DebugPrint((1,"A174xMapStatus: Host aborted\n"));
+ srbStatus = SRB_STATUS_ABORTED;
+ break;
+
+ case SB_HASTATUS_FW_NOT_DOWNLOADED:
+ DebugPrint((1,"A174xMapStatus: Firmware not downloaded\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SB_HASTATUS_INVALID_SGL:
+ DebugPrint((1,"A174xMapStatus: Invalid SGL\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case SB_HASTATUS_REQUEST_SENSE_FAILED:
+ DebugPrint((1,"A174xMapStatus: Request sense failed\n"));
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ default:
+
+ srbStatus = SRB_STATUS_ERROR;
+
+ //
+ // Check status block word.
+ //
+
+ if (StatusBlock->StatusWord & SB_STATUS_NO_ERROR) {
+
+ //
+ // This should never happen as this routine is only
+ // called when there is an error.
+ //
+
+ DebugPrint((1,"A174xMapStatus: No error\n"));
+ srbStatus = SRB_STATUS_SUCCESS;
+ break;
+
+ }
+
+ //
+ // Check for underrun.
+ //
+
+ if (StatusBlock->StatusWord & SB_STATUS_DATA_UNDERRUN) {
+
+ DebugPrint((1,
+ "A174xMapStatus: Data underrun indicated in status word\n"));
+
+ //
+ // Update SRB with actual bytes transferred.
+ //
+
+ Srb->DataTransferLength -= StatusBlock->ResidualByteCount;
+ break;
+ }
+
+ //
+ // Check for overrun.
+ //
+
+ if (StatusBlock->StatusWord & SB_STATUS_DATA_OVERRUN) {
+
+ DebugPrint((1,
+ "A174xMapStatus: Data overrun indicate in status word\n"));
+ logError = SP_PROTOCOL_ERROR;
+ break;
+ }
+
+ //
+ // Check for initialization required.
+ //
+
+ if (StatusBlock->StatusWord & SB_STATUS_INIT_REQUIRED) {
+ DebugPrint((1,
+ "A174xMapStatus: Initialization required\n"));
+ break;
+ }
+
+ //
+ // Check for contingent allegience condition. If this happens
+ // something is very wrong (because autorequest sense was indicated).
+ //
+
+ if (StatusBlock->StatusWord & SB_STATUS_EXT_CONT_ALLEGIANCE) {
+
+ DebugPrint((1,
+ "A174xMapStatus: Contingent allegiance condition\n"));
+
+ ASSERT(0);
+ }
+
+ if (StatusBlock->StatusWord & SB_STATUS_MAJOR_ERROR) {
+
+ DebugPrint((1,
+ "A174xMapStatus: Major error indicated in status word\n"));
+ break;
+ }
+
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+
+ } // end switch ...
+
+ if (logError != 0) {
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ 2 << 16 | StatusBlock->HaStatus
+ );
+
+ }
+
+ //
+ // Set SRB status.
+ //
+
+ Srb->SrbStatus = srbStatus;
+
+ //
+ // Set target SCSI status in SRB.
+ //
+
+ Srb->ScsiStatus = StatusBlock->TargetStatus;
+
+ return;
+
+} // end A174xMapStatus()
diff --git a/private/ntos/miniport/aha174x/aha174x.h b/private/ntos/miniport/aha174x/aha174x.h
new file mode 100644
index 000000000..74f589a1b
--- /dev/null
+++ b/private/ntos/miniport/aha174x/aha174x.h
@@ -0,0 +1,270 @@
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ 174x.h
+
+Abstract:
+
+ This module contains the structures, specific to the Adaptec 174x
+ host bus adapter, used by the SCSI port driver. Data structures
+ that are part of standard ANSI SCSI will be defined in a header
+ file that will be available to all SCSI device drivers.
+
+Author:
+
+ Mike Glass
+
+Revision History:
+
+--*/
+
+#include "scsi.h"
+
+#define MAXIMUM_EISA_SLOTS 0x10
+#define EISA_ADDRESS_BASE 0x0C80
+#define MAXIMUM_SGL_DESCRIPTORS 0x11
+#define MAXIMUM_DESCRIPTOR_SIZE 0x3FFFFF
+#define MAXIMUM_TRANSFER_SIZE 0xFFFFFF
+#define REQUEST_SENSE_BUFFER_SIZE 0x18
+
+//***************
+// *
+// Status Block *
+// *
+//***************
+
+typedef struct _STATUS_BLOCK {
+ USHORT StatusWord;
+ UCHAR HaStatus;
+ UCHAR TargetStatus;
+ ULONG ResidualByteCount;
+ ULONG ResidualAddress;
+ USHORT AdditionalStatusLength;
+ UCHAR RequestSenseLength;
+ UCHAR Reserved0;
+ ULONG Reserved1;
+ ULONG Reserved2;
+ USHORT Reserved3;
+ UCHAR Cdb[6];
+} STATUS_BLOCK, *PSTATUS_BLOCK;
+
+//
+// Status Word Bit Values
+//
+
+#define SB_STATUS_NO_ERROR 0x0001
+#define SB_STATUS_DATA_UNDERRUN 0x0002
+#define SB_STATUS_HA_QUEUE_FULL 0x0008
+#define SB_STATUS_SPECIFICATION_CHECK 0x0010
+#define SB_STATUS_DATA_OVERRUN 0x0020
+#define SB_STATUS_CHAINING_HALTED 0x0040
+#define SB_STATUS_SCB_INTERRUPT 0x0080
+#define SB_STATUS_ADDITIONAL_STATUS 0x0100
+#define SB_STATUS_SENSE_INFORMATION 0x0200
+#define SB_STATUS_INIT_REQUIRED 0x0800
+#define SB_STATUS_MAJOR_ERROR 0x1000
+#define SB_STATUS_EXT_CONT_ALLEGIANCE 0x4000
+
+//
+// HOST_ADAPTER_STATUS
+//
+
+#define SB_HASTATUS_HOST_ABORTED 0x04
+#define SB_HASTATUS_ADAPTER_ABORTED 0x05
+#define SB_HASTATUS_FW_NOT_DOWNLOADED 0x08
+#define SB_HASTATUS_TARGET_NOT_USED 0x0A
+#define SB_HASTATUS_SELECTION_TIMEOUT 0x11
+#define SB_HASTATUS_DATA_OVERUNDER_RUN 0x12
+#define SB_HASTATUS_UNEXPECTED_BUS_FREE 0x13
+#define SB_HASTATUS_INVALID_BUS_PHASE 0x14
+#define SB_HASTATUS_INVALID_OPERATION 0x16
+#define SB_HASTATUS_INVALID_SCSI_LINK 0x17
+#define SB_HASTATUS_INVALID_ECB 0x18
+#define SB_HASTATUS_DUPLICATE_TARGET 0x19
+#define SB_HASTATUS_INVALID_SGL 0x1A
+#define SB_HASTATUS_REQUEST_SENSE_FAILED 0x1B
+#define SB_HASTATUS_TAGGED_QUEUE_REJECTED 0x1C
+#define SB_HASTATUS_ADAPTER_HARDWARE_ERROR 0x20
+#define SB_HASTATUS_TARGET_NO_RESPOND 0x21
+#define SB_HASTATUS_ADAPTER_RESET_BUS 0x22
+#define SB_HASTATUS_DEVICE_RESET_BUS 0x23
+#define SB_HASTATUS_CHECKSUM_FAILURE 0x80
+
+//
+// Target Status - See SCSI.H
+//
+
+//**********************
+// *
+// Scatter Gather List *
+// *
+//**********************
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Address;
+ ULONG Length;
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+typedef struct _SGL {
+ SG_DESCRIPTOR Descriptor[MAXIMUM_SGL_DESCRIPTORS];
+} SGL, *PSGL;
+
+//**************************
+// *
+// Enhanced Control Block *
+// *
+//**************************
+
+typedef struct _ECB {
+ USHORT Command;
+ USHORT Flags[2];
+ USHORT Reserved1;
+ ULONG PhysicalSgl;
+ ULONG SglLength;
+ ULONG StatusBlockAddress;
+ ULONG NextEcb;
+ ULONG Reserved2;
+ ULONG SenseInfoAddress;
+ UCHAR SenseInfoLength;
+ UCHAR CdbLength;
+ USHORT DataCheckSum;
+ UCHAR Cdb[12];
+ PVOID SrbAddress;
+ PSCSI_REQUEST_BLOCK AbortSrb;
+ SGL Sgl;
+ STATUS_BLOCK StatusBlock;
+} ECB, *PECB;
+
+//
+// Commands
+//
+
+#define ECB_COMMAND_NO_OPERATION 0x0000
+#define ECB_COMMAND_INITIATOR_COMMAND 0x0001
+#define ECB_COMMAND_RUN_DIAGNOSTICS 0x0005
+#define ECB_COMMAND_INITIALIZE_SCSI 0x0006
+#define ECB_COMMAND_READ_SENSE_INFO 0x0008
+#define ECB_COMMAND_DOWNLOAD_FIRMWARE 0x0009
+#define ECB_COMMAND_READ_INQUIRY_DATA 0x000A
+#define ECB_COMMAND_TARGET_COMMAND 0x0010
+
+//
+// Flag word 1
+//
+
+#define ECB_FLAGS_CHAIN_NO_ERROR 0x0001
+#define ECB_FLAGS_DISABLE_INTERRUPT 0x0080
+#define ECB_FLAGS_SUPPRESS_UNDERRUN 0x0400
+#define ECB_FLAGS_SCATTER_GATHER 0x1000
+#define ECB_FLAGS_DISABLE_STATUS_BLOCK 0x4000
+#define ECB_FLAGS_AUTO_REQUEST_SENSE 0x8000
+
+//
+// Flag word 2
+//
+
+#define ECB_FLAGS_SIMPLE_QUEUE_TAG 0x0008
+#define ECB_FLAGS_HEAD_QUEUE_TAG 0x0018
+#define ECB_FLAGS_ORDERED_QUEUE_TAG 0x0028
+#define ECB_FLAGS_NO_DISCONNECT 0x0040
+#define ECB_FLAGS_DATA_TRANSFER 0x0100
+#define ECB_FLAGS_READ 0x0300
+#define ECB_FLAGS_WRITE 0x0100
+#define ECB_FLAGS_SUPPRESS_TRANSFER 0x0400
+#define ECB_FLAGS_CALCULATE_CHECKSUM 0x0800
+#define ECB_FLAGS_ERROR_RECOVERY 0x4000
+
+//****************************
+// *
+// EISA Controller registers *
+// *
+//****************************
+
+typedef struct _EISA_CONTROLLER {
+
+ UCHAR BoardId[4]; // zC80
+ UCHAR EBControl; // zC84
+ UCHAR Unused[0x3B]; // zC85
+ UCHAR PortAddress; // zCC0
+ UCHAR BiosAddress; // zCC1
+ UCHAR Interrupt; // zCC2
+ UCHAR ScsiId; // zCC3
+ UCHAR DmaChannel; // zCC4
+ UCHAR Reserved[11]; // zCC5
+ ULONG MailBoxOut; // zCD0
+ UCHAR Attention; // zCD4
+ UCHAR Control; // zCD5
+ UCHAR InterruptStatus; // zCD6
+ UCHAR Status; // zCD7
+ ULONG MailBoxIn; // zCD8
+ UCHAR MoreStatus; // zCDC
+
+} EISA_CONTROLLER, *PEISA_CONTROLLER;
+
+//
+// PortAddress Register Definition
+//
+
+#define ENHANCED_INTERFACE_ENABLED 0x80
+
+//
+// Bios address mask.
+//
+
+#define BIOS_ADDRESS 0x0f
+#define BIOS_ENABLED 0x40
+#define BIOS_LENGTH 0x4000
+
+//
+// Attention Register Bit Definitions
+//
+
+#define IMMEDIATE_COMMAND 0x10
+#define START_ECB 0x40
+#define ABORT_ECB 0x50
+
+
+//
+// Control Register Bit Definitions
+//
+
+#define SET_HOST_READY 0x20
+#define CLEAR_INTERRUPT 0x40
+#define HARD_RESET 0x80
+
+//
+// Interrupt Status Register Bit Definitions
+//
+
+#define ECB_COMPLETE_SUCCESS 0x01
+#define ECB_COMPLETE_SUCCESS_RETRY 0x05
+#define ADAPTER_FAILURE 0x07
+#define IMMEDIATE_COMMAND_SUCCESS 0x0A
+#define ECB_COMPLETE_ERROR 0x0C
+#define ASYNCHRONOUS_EVENT_NOTIFICATION 0x0D
+#define IMMEDIATE_COMMAND_ERROR 0x0E
+
+//
+// Status Register Bit Definition
+//
+
+#define ADAPTER_BUSY 0x01
+#define INTERRUPT_PENDING 0x02
+#define MAILBOX_OUT_EMPTY 0x04
+
+//
+// Immediate commands
+//
+
+#define ECB_IMMEDIATE_RESET 0x00000080
+#define ECB_IMMEDIATE_RESUME 0x00000090
+
+//
+// Status2 Register Definition
+//
+
+#define HOST_READY 0x01
diff --git a/private/ntos/miniport/aha174x/aha174x.rc b/private/ntos/miniport/aha174x/aha174x.rc
new file mode 100644
index 000000000..74cae3874
--- /dev/null
+++ b/private/ntos/miniport/aha174x/aha174x.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "AHA 174 x SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "aha174x.sys"
+#define VER_ORIGINALFILENAME_STR "aha174x.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/aha174x/makefile b/private/ntos/miniport/aha174x/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/aha174x/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/aha174x/sources b/private/ntos/miniport/aha174x/sources
new file mode 100644
index 000000000..38ae8b770
--- /dev/null
+++ b/private/ntos/miniport/aha174x/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=aha174x
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=aha174x.c aha174x.rc
diff --git a/private/ntos/miniport/always/33c93.c b/private/ntos/miniport/always/33c93.c
new file mode 100644
index 000000000..f44dc9fab
--- /dev/null
+++ b/private/ntos/miniport/always/33c93.c
@@ -0,0 +1,827 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#include "environ.h"
+#include "rqm.h"
+#include "api.h"
+#include "apiscsi.h"
+#include "debug.h"
+
+#include "33c93.h"
+
+#define ReadWDReg(HA,WDReg) (outb(HA->Ext->SBIC.WD33C93.WDSelPort, (WDReg)), inb(HA->Ext->SBIC.WD33C93.WDDataPort))
+
+#ifndef ReadWDReg
+unsigned const
+ReadWDReg (const ADAPTER_PTR HA, const unsigned reg)
+{
+
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, (WDReg));
+ return inb(HA->IOBase + INWDDataOff);
+
+}
+#endif
+
+
+
+
+U8 REGPARMS
+ReadTilStable (ADAPTER_PTR HA, unsigned Reg)
+{
+ U8 Stat1, Stat2;
+
+ Stat2 = ReadWDReg(HA, Reg);
+ do {
+
+ Stat1 = Stat2;
+ Stat2 &= ReadWDReg(HA, Reg);
+ Stat2 &= ReadWDReg(HA, Reg);
+
+ } while (Stat1 != Stat2);
+
+ return Stat1;
+
+}
+
+
+
+// Wait for WD command in progress to complete, then issue a new command:
+#define SendWDCmd(WDSelPort, WDDataPort, WDCmd) {while (inb(WDSelPort) & (WD_Busy | WD_CIP)) ; \
+ outb(WDSelPort, WDCMDReg); outb(WDDataPort, WDCmd); }
+
+#if !defined(SendWDCmd)
+void const REGPARMS
+SendWDCmd (IOHandle WDSelPort, IOHandle WDDataPort, unsigned WDCmd)
+{
+
+ while (inb(WDSelPort) & (WD_Busy | WD_CIP)) ; // Spin on WD busy
+
+ outb(WDSelPort, WDCMDReg); // Select command register
+ outb(WDDataPort, WDCmd); // Issue command
+
+}
+#endif
+
+
+int REGPARMS
+WaitForDataReady (ADAPTER_PTR HA)
+{
+ unsigned stat;
+ unsigned long Spin=100000l;
+
+ while ( ((((stat = inb(HA->Ext->SBIC.WD33C93.WDSelPort)) & WD_DBR) == 0)
+ || (stat & WD_CIP) ) && Spin--) {
+
+ if (stat & (IntPending | CommandIGN))
+ return -1;
+
+ }
+
+ if ((stat & WD_DBR) == 0) { // Fell out of loop because of spin loop exhaustion
+
+ TRACE(0, ("WaitForDataReady(): Spun out waiting for data ready\n"));
+ return -1;
+
+ }
+
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDDataReg);
+ return 0;
+
+}
+
+
+
+int REGPARMS
+WaitForWrite (const ADAPTER_PTR HA, const U8 Data)
+{
+
+ if (WaitForDataReady(HA))
+ return -1;
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, Data);
+ return 0;
+
+}
+
+
+
+int REGPARMS
+WaitForRead (const ADAPTER_PTR HA,
+ U8 FAR *const Data)
+{
+
+ if (WaitForDataReady(HA))
+ return -1;
+ *Data = inb(HA->Ext->SBIC.WD33C93.WDDataPort);
+ return 0;
+
+}
+
+
+
+//#define XferInByte(HA,Data) (SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo | WDSingleByte), WaitForRead(HA, Data))
+#if !defined(XferInByte)
+
+int REGPARMS
+XferInByte (const ADAPTER_PTR HA, U8 FAR *Data)
+{
+
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo | WDSingleByte);
+ return WaitForRead(HA, Data);
+
+}
+#endif
+
+
+//#define XferOutByte(HA,Data) (SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo | WDSingleByte), WaitForWrite(HA, Data))
+#if !defined(XferOutByte)
+
+int REGPARMS
+XferOutByte (const ADAPTER_PTR HA, const U8 Data)
+{
+
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo | WDSingleByte);
+ return WaitForWrite(HA, Data);
+
+}
+#endif
+
+
+
+unsigned
+PIORead (ADAPTER_PTR const HA,
+ U8 FAR *Block,
+ unsigned Count)
+{
+ unsigned i;
+
+ TRACE(5,("in2000: PIORead(): "));
+
+ for (i = 0; i < Count; i++) {
+ if (WaitForRead(HA, Block++))
+ break;
+ }
+ TRACE(5, ("%d read bytes\n", i));
+ return i;
+
+}
+
+
+
+unsigned
+PIOWrite (ADAPTER_PTR HA,
+ U8 FAR *Block,
+ unsigned Count)
+{
+ unsigned i;
+
+ for (i = 0; i < Count; i++) {
+ if (WaitForWrite(HA, *Block++))
+ break;
+ }
+ return i;
+
+}
+
+
+
+static
+PIOWriteBlk (ADAPTER_PTR HA,
+ U8 FAR *Block,
+ unsigned Count)
+{
+ unsigned i;
+
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, 0);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, Count >> 8);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, Count);
+
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo); /* Start data xfer */
+
+ for (i = 0; i < Count; i++) {
+ if (WaitForWrite(HA, *Block++))
+ break;
+ }
+ return i;
+}
+
+
+void REGPARMS
+Abort (ADAPTER_PTR HA)
+{
+
+ SCSISendAbort(HA);
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDSetAtnCmd); /* Set attention */
+
+}
+
+
+void
+WD33C93_Reset (ADAPTER_PTR HA)
+{
+ int Divisor;
+
+ /* Set freq devisor & default SCSI ID; must be set before reset */
+ if (HA->Ext->SBIC.WD33C93.MHz >= 16)
+ Divisor = 4;
+ else if (HA->Ext->SBIC.WD33C93.MHz >= 12)
+ Divisor = 3;
+ else Divisor = 2;
+
+ //IFreq = Internal freq and max xfer rate
+ HA->Ext->SBIC.WD33C93.IFreq = HA->Ext->SBIC.WD33C93.MHz / Divisor;
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDOwnIDReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((Divisor - 2) & 3) << 6) | HA->SCSI_ID);
+
+ critical(HA);
+
+ /* Reset chip, then wait for reset complete interrupt */
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDResetCmd);
+
+ while ((ReadTilStable(HA, WDAuxStatReg) & IntPending) == 0)
+ ;
+ ReadWDReg(HA, WDStatusReg); /* Clear the interrupt */
+
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDControlReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, HaltPE); // Enable parity checking
+
+ /* Set default selection timeout to 250 ms (x = ms * MHz / 80) */
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDTimeoutReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, ((25*HA->Ext->SBIC.WD33C93.MHz)+7) / 8);
+
+ /* Allow reselections: */
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSourceReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, EnableRSel);
+
+ uncritical(HA);
+
+}
+
+int
+WD33C93_Init (ADAPTER_PTR HA)
+{
+
+ WD33C93_Reset(HA);
+
+ /* Sync period in SCSI terms (nS/4) */
+ // Rate(Hz) = IFreq.
+ // Period(ns) = 1,000,000,000 / Rate(Hz) == 1000/Rate(MHz)
+ // SCSI period (Period(ns)/2) == (1000/4)/Rate(MHz)
+ HA->Sync_Period = (((HA->Ext->SBIC.WD33C93.MHz >= 16) ? 500 : 1000)/4) / HA->Ext->SBIC.WD33C93.IFreq;
+ HA->Sync_Offset = 12;
+ TRACE(5, ("WD33C93_Init(): HA Sync. period set to: %d, offset set to %d\n", HA->Sync_Period, HA->Sync_Offset));
+
+ /* This is an 8-bit SCSI bus: */
+ HA->Max_TID = 7;
+ return 0;
+
+}
+
+
+// Set a devices adapter specific sync. value
+LOCAL void REGPARMS
+WD33C93UpdateSync (ADAPTER_PTR HA)
+{
+
+ unsigned Cycles;
+ unsigned FastSCSI=0; // In case we're FAST SCSI on 33C93B
+
+ /* Magic math: */
+ if (HA->Ext->SBIC.WD33C93.MHz >= 16) { // Assume > 16MHz is "B" part
+
+ // First calc. the period in nS for the 33C93 SCSI clock:
+ if ((unsigned)HA->CurrDev->Sync_Period < (200/4)) {
+
+ TRACE(3, ("WD33C93UpdateSync(): Device is asking for fast SCSI: %d\n", (unsigned)HA->CurrDev->Sync_Period));
+ FastSCSI = 0x80; // "B" part, < 200nS xfer period
+ Cycles = 2000/(2*HA->Ext->SBIC.WD33C93.MHz);
+
+ } else {
+
+ Cycles = 2000/(HA->Ext->SBIC.WD33C93.MHz);
+
+ }
+
+ TRACE(3, ("WD33C93UpdateSync(): Period/Cycle =%dnS\n", Cycles));
+
+ // Then calc. the SCSI xfer period by the 33C93 internal period for number of cycles:
+ Cycles = ((unsigned)HA->CurrDev->Sync_Period * 4) / Cycles;
+ TRACE(3, ("WD33C93UpdateSync(): Cycles/Xfer =%d\n", Cycles));
+
+ } else Cycles = ((unsigned)HA->CurrDev->Sync_Period * (4 * 2) * HA->Ext->SBIC.WD33C93.IFreq + 999) / 1000;
+
+ if (Cycles >= 8)
+ Cycles = 0;
+
+ HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1 = ((Cycles & 7)<< 4) | HA->CurrDev->Sync_Offset | FastSCSI;
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1);
+ TRACE(2, ("WD33C93UpdateSync(): HA Sync period set to: %02x\n", HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1));
+
+}
+
+
+
+void REGPARMS
+Resel (ADAPTER_PTR HA, U8 MSG)
+{
+
+ HA->ReqStarting = 0; // Don't accept starting command
+
+ HA->Ext->SBIC.WD33C93.TID = ReadTilStable(HA, WDSourceReg);
+
+ if ((HA->Ext->SBIC.WD33C93.TID & IDValid)
+ && (Reselect(HA, (U8)(HA->Ext->SBIC.WD33C93.TID & 0x7), (U8)(MSG & 0x7), 0) == 0)) {
+
+ if (HA->DevInfo[HA->CurrDev->SCSI_ID].Flags.UseSync) {
+
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1);
+
+ } else {
+
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->Ext->SBIC.WD33C93.AsyncValue);
+
+ }
+
+ } else {
+
+ TRACE(1,("Reselection rejected, TID == %02x, MSG == %02x\n", HA->Ext->SBIC.WD33C93.TID, MSG));
+ LogMessage(HA, NILL, HA->Ext->SBIC.WD33C93.TID, MSG, MSG_BAD_RESEL, __LINE__);
+
+ SCSISendReject(HA);
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDSetAtnCmd); /* Set attention */
+
+ }
+}
+
+
+
+static void REGPARMS
+HandleMessageByte (ADAPTER_PTR HA)
+{
+ switch (Receive_Msg(HA, HA->Ext->SBIC.WD33C93.MI_Temp)) {
+
+ case MI_SYNC_RESP: /* Response from sync req; update values */
+
+ WD33C93UpdateSync(HA);
+ break; /* All done */
+
+
+ case MI_SYNC_REQ: /* got sync req; update values, and respond */
+
+ WD33C93UpdateSync(HA);
+ // Fall Through !!
+
+ case MI_SEND_MSG: /* Msg in resulted in message out request: */
+
+ TRACE(4,("WD33C93_ISR(): Send message requested\n"));
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort,
+ WDSetAtnCmd); // Have a response msg, set attention
+ break;
+
+
+ case MSG_IDENTIFY: /* Identify? */
+
+ Resel(HA, HA->Ext->SBIC.WD33C93.MI_Temp);
+ break;
+
+
+ default:
+
+ break;
+
+ }
+
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDNegAckCmd); // Message received, negate ACK to signal acceptance
+
+
+}
+
+
+
+void
+WD33c93_ISR (ADAPTER_PTR HA)
+{
+ /* Remember, when defining automatics that SS may not equal DS, so
+ don't use pointers to automatics in ISRs. -- This is only a problem
+ in brain dead "real" mode environments. This is not a problem in
+ flat model systems.
+
+ Q: Why is a processor which is limited to 1MB and uses segments in
+ "real" mode? Such a mode should be called "Bogus mode." A "real"
+ processor has none of these characteristics.
+ */
+
+ U32 S;
+ U8 Stat;
+
+#if defined(KEEP_STATS)
+ HA->Ext->SBICInterrupts++;
+#endif
+
+ ReadTilStable(HA, WDAuxStatReg);
+ Stat = ReadWDReg(HA, WDStatusReg);
+
+ TRACE(4,("WD33c93_ISR(): WD status = %02x\n", Stat));
+ if (Stat == 0xff)
+ return;
+
+ if (HA->Ext->SBIC.WD33C93.State & WD_BLOCK_XFER) {
+
+ HA->Service(HA_DATA_CMPLT, HA, (U32)0);
+ HA->Ext->SBIC.WD33C93.State &= ~WD_BLOCK_XFER;
+
+ }
+
+
+
+ /* See if this is a new bus phase interrupt (bit 0x08 set). If so,
+ mask off the most sig. nibble, and case on the new phase: */
+ if (Stat & 0x08)
+ Stat &= WD_PHASE_MASK;
+
+ switch (Stat) {
+
+ case WD_STAT_RESET: /* Chip has reset; Who did that??? */
+ case WD_STAT_RESETA:
+
+ TRACE(1, ("33c93_ISR(): Bus reset detected\n"));
+ HA->ReqStarting = 0;
+ WD33C93_Reset(HA);
+ SCSIBusHasReset(HA);
+ break;
+
+
+ /*
+ The following are the bus phase changes; The most significant
+ nibble is masked off, since we are only interested in the new
+ bus phase.
+ */
+
+ case WD_MDATA_OUT: // Data out phase
+ case WD_MDATA_IN: // Data in phase
+
+ if (HA->ReqCurrentCount == 0) {
+
+ GetXferSegment(HA, HA->CurrReq, &HA->SGDescr, HA->ReqCurrentIndex, FALSE);
+ HA->ReqCurrentCount = HA->SGDescr.SegmentLength;
+
+ }
+
+
+#if defined(COMPOUND_CMD)
+ // If we are using compound commands, the only way we can leave compound mode is by a message interrupt, or a data interrupt
+ HA->Ext->SBIC.WD33C93.State &= ~WD_COMPOUND_CMD;
+#endif
+
+ if ( (((Stat & 1) != 0) && !ReqDataIn(HA->CurrReq)) // Phase is in, no req data
+ || (((Stat & 1) == 0) && !ReqDataOut(HA->CurrReq)) // Phase is out, no req data
+#if defined(ReqNoData)
+ || ReqNoData(HA->CurrReq) // Req. wants no data
+#endif
+ || HA->ReqCurrentCount == 0) { // No data left
+
+ TRACE(0,("WD33C93_ISR(): Data xfer pad: flags = %x, CurrCount = %d, direction = %s\n", ReqFlags(HA->CurrReq), HA->ReqCurrentCount, ((Stat & 1) ? "In" : "Out") ));
+// BreakPoint(HA);
+
+ ReqAPIStatus(HA->CurrReq) = S_REQ_OVERRUN;
+ /* Do a single byte xfer pad: */
+ if (Stat & 1)
+ XferInByte(HA, (U8 FAR *)&Stat);
+ else
+ XferOutByte(HA, (U8)Stat);
+ break;
+
+ }
+
+ TRACE(3,("WD33C93_ISR(): Data xfer of %ld bytes started\n", HA->ReqCurrentCount));
+
+#if defined(NATIVE32)
+
+ /* Set the XFER count register: */
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (U8)(HA->ReqCurrentCount / (long)0x10000));
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (U8)(HA->ReqCurrentCount / (long)0x100));
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (U8)HA->ReqCurrentCount);
+
+#else
+
+ /* Set the XFER count register: */
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((U8 FAR *)&HA->ReqCurrentCount)[2]));
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((U8 FAR *)&HA->ReqCurrentCount)[1]));
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((U8 FAR *)&HA->ReqCurrentCount)[0]));
+
+#endif
+
+ HA->State.DataIn = (Stat & 1); /* Data in or out */
+ S = HA->Service(HA_DATA_SETUP, HA, (U32)(Stat & 1));
+
+ /* Start the data transfer */
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDXferInfo);
+
+ if (S == HAServiceResponse_UseByteIO) {
+
+ S = (Stat & 1) ?
+ PIORead(HA,
+ (U8 FAR *)&(((U8 FAR *)(ReqDataPtr(HA->CurrReq)))[(unsigned)HA->ReqCurrentIndex]),
+ (unsigned)HA->ReqCurrentCount)
+ : PIOWrite(HA,
+ (U8 FAR *)&(((U8 FAR *)(ReqDataPtr(HA->CurrReq)))[(unsigned)HA->ReqCurrentIndex]),
+ (unsigned)HA->ReqCurrentCount);
+ HA->ReqCurrentIndex += S;
+ HA->ReqCurrentCount -= S;
+ TRACE(4,("WD33C93_ISR(): Xfer of %d bytes complete\n", S));
+
+ } else {
+
+ HA->State.DataXfer = 1;
+ HA->Ext->SBIC.WD33C93.State |= WD_BLOCK_XFER;
+
+ }
+ break;
+
+
+ case WD_MCOMMAND: /* Command phase */
+
+ TRACE(3,("WD33C93_ISR(): command phase\n"));
+
+ if (HA->DevInfo[HA->CurrDev->SCSI_ID].Flags.UseSync) { // Sync. xfer been established?
+
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->DevInfo[HA->CurrDev->SCSI_ID].HASync1);
+
+ } else {
+
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDSyncReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, HA->Ext->SBIC.WD33C93.AsyncValue);
+
+ }
+
+ PIOWriteBlk(HA, ReqCDB(HA->CurrReq), ReqCDBLen(HA->CurrReq));
+ break;
+
+
+
+ case WD_STAT_BAD_STATUS: /* Status phase w/ parity */
+
+ TRACE(2, ("WD33C93_ISR(): Parity error detected\n"));
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDSetAtnCmd);
+ HA->Ext->MO_Buff[HA->Ext->MO_Count++] = MSG_INIT_ERROR;
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDNegAckCmd);
+ LogMessage(HA, HA->CurrReq, HA->CurrDev->SCSI_ID, 0, MSG_PARITY, __LINE__);
+ // Fall through
+
+ case WD_MSTATUS: /* status phase */
+
+ XferInByte(HA, (U8 FAR *)&Stat);
+ if (ReqAPIStatus(HA->CurrReq) == S_REQ_STARTED || ReqAPIStatus(HA->CurrReq) == S_REQ_ACCEPTED)
+ ReqAPIStatus(HA->CurrReq) = TargetStatus(Stat);
+
+ // Update the saved index to reflect the number of bytes actually
+ // transfered:
+ ReqSavedIndex(HA->CurrReq) = HA->ReqCurrentIndex;
+
+ TRACE(3, ("WD33C93_ISR(): status phase %02x\n", Stat));
+ break;
+
+
+ /*
+ A disconnect will occur either as an intermediate disconnect,
+ followed by a later reselect, or it happens after command
+ completion. If there is a request in progress, then a later
+ reselect is expected.
+
+ After cleaning up as necessary, the first request for the next
+ pending target is initiated.
+ */
+ case WD_MMSG_OUT: // Message out phase
+
+ TRACE(4,("MsgOutP: sending message %02x\n", HA->Ext->MO_Buff[HA->Ext->MO_Index]));
+
+ if (HA->Ext->MO_Count) { // Any messages waiting?
+
+ PIOWriteBlk(HA, HA->Ext->MO_Buff, HA->Ext->MO_Count); // Then send them
+
+ } else
+ XferOutByte(HA, MSG_NOP); // Otherwise, send a no-op
+
+ HA->Ext->MO_Index = HA->Ext->MO_Count = 0; // Reset the Message Out counters
+
+#if defined(COMPOUND_CMD)
+ // If we are using compound commands, the only way we can leave compound mode is by a message interrupt, or a data interrupt
+ HA->Ext->SBIC.WD33C93.State &= ~WD_COMPOUND_CMD;
+#endif
+
+ break;
+
+
+
+ case WD_MMSG_IN: /* Message in phase */
+
+ if (XferInByte(HA, &HA->Ext->SBIC.WD33C93.MI_Temp)) // Read the message byte
+ TRACE(3,("WD33C93_ISR(): WD_MSG_IN failed: %02x\n", inb(HA->Ext->SBIC.WD33C93.WDSelPort)));
+ if (HA->ReqStarting) // Don't know yet if this message is for the staring request
+ HA->ReqStarting++;
+ TRACE(3, ("WD33C93_ISR(): Message in phase: %02x\n", HA->Ext->SBIC.WD33C93.MI_Temp));
+ /* We should next get a WD_STAT_XFER_PAUSED (0x20) state, process the message there */
+
+#if defined(COMPOUND_CMD)
+ // If we are using compound commands, the only way we can leave compound mode is by a message interrupt, or a data interrupt
+ HA->Ext->SBIC.WD33C93.State &= ~WD_COMPOUND_CMD;
+#endif
+
+ break;
+
+
+
+ case WD_STAT_SELECT_CMPLT: /* Select complete */
+
+ break;
+
+
+
+ /*
+
+ On reselection, get the reselecting target ID. From there, get
+ the first request structure for that ID, and verify that a
+ reselection is pending. If a proper disconnect occured, then
+ the disconnected request is the first on the list for that
+ target ID. If reselection is not pending, send an abort to the
+ reselecting target If a request was started, but reselection
+ occurred out from under it, clear the ReqStarting flag. If at
+ the end of the interrupt, the flag is non-zero, it is
+ decremented. If the flag decrements to zero, the request will
+ be flagged as accepted (by incrementing the command pointer).
+ If the decrement does not set the flag to zero, then the command
+ was just started by the interrupt being processed, so we wait
+ for the next interrupt to occur (with the flag set to 1).
+
+ */
+ /*
+
+ The select and transfer command has completed, and therefore,
+ the request is complete. Retreive the command status into the
+ request structure, de-queue the request, and notify the
+ requestor.
+
+ */
+
+ case WD_STAT_SandT_CMPLT: // Select and transfer complete
+
+ HA->Ext->SBIC.WD33C93.State |= WD_COMPOUND_CMPLT;
+ ReqAPIStatus(HA->CurrReq) = TargetStatus(ReadTilStable(HA, WDTarLUNReg));
+ ReqDone(HA, HA->CurrReq);
+ break;
+
+
+ case WD_STAT_SAVE_PTR: /* Save data pointer */
+
+ TRACE(4, ("WD33C93_ISR(): Saved data pointer status received\n"));
+ HA->Ext->SBIC.WD33C93.MI_Temp = MSG_SAVE_PTR;
+
+ /* Fall through */
+ case WD_STAT_XFER_PAUSED: /* Paused w/ ACK (message in) */
+
+ HandleMessageByte(HA);
+ break;
+
+
+ case WD_STAT_BAD_DISC: // Unexpected bus free
+
+ ReqAPIStatus(HA->CurrReq) = S_AD_FREE;
+ ReqDone(HA, HA->CurrReq);
+ BusFree(HA, 2);
+ break;
+
+
+ case WD_STAT_SEL_TO: /* Select timeout */
+
+ ReqAPIStatus(HA->CurrReq) = S_REQ_NOTAR; // Target not responding
+ ReqDone(HA, HA->CurrReq);
+ BusFree(HA, 2);
+ break;
+
+
+ case WD_STAT_RESELECTED: /* Reselection */
+
+ HA->ReqStarting = 0; /* Don't accept starting command */
+ HA->State.Busy = 1;
+
+ // The actual attachment to a request will be done when we get the
+ // identify message
+ TRACE(3,("WD33c93_ISR(): Reselect phase\n"));
+
+ do {
+
+ HA->Ext->SBIC.WD33C93.TID = ReadTilStable(HA, WDSourceReg);
+
+ } while ((HA->Ext->SBIC.WD33C93.TID & IDValid) == 0);
+
+
+
+ TRACE(3,("WD33c93_ISR(): Reselect, TID = 0x%02x\n", HA->Ext->SBIC.WD33C93.TID));
+ break;
+
+
+ case WD_STAT_RESELECTED_A: // Advanced mode reselection; unexpected, but has been seen
+
+ HA->ReqStarting = 0; /* Don't accept starting command */
+ HA->State.Busy = 1;
+
+ // The actual attachment to a request will be done when we get the
+ // identify message
+ TRACE(3,("WD33c93_ISR(): Reselect phase\n"));
+
+ do {
+
+ HA->Ext->SBIC.WD33C93.TID = ReadTilStable(HA, WDSourceReg);
+
+ } while ((HA->Ext->SBIC.WD33C93.TID & IDValid) == 0);
+
+ TRACE(0, ("WD33C93_ISR(): Unusual advanced mode reselect; TID = 0x%02x, LUN = 0x%02x\n", HA->Ext->SBIC.WD33C93.TID, HA->Ext->MI_Buff[0]));
+ TRACE(3, ("WD33c93_ISR(): Reselect, TID = 0x%02x\n", HA->Ext->SBIC.WD33C93.TID));
+
+ HA->Ext->SBIC.WD33C93.MI_Temp = ReadWDReg(HA, WDDataReg);
+ HandleMessageByte(HA);
+ break;
+
+
+ case WD_STAT_SELECTED: /* Selected */
+ case WD_STAT_SELECTED_ATN: /* Selected w/ATN */
+
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort,
+ HA->Ext->SBIC.WD33C93.WDDataPort,
+ WDDisconnectCmd); /* disconnect */
+ break;
+
+
+ case WD_STAT_DISCONNECT: /* Normal disconnect */
+
+ /*
+ If there is no "CurrReq", then the request has been completed through
+ normal Status and message phases (Status for completion, message for
+ disconnect).
+
+ If the WD "compound" (level II) commands are being used, then the
+ disconnect interrupt will ccur with "CurrReq" still set. In this
+ case, it is a normal disconnect, and the status and message bytes
+ should be examined here.
+ */
+
+ if ((HA->CurrReq == NILL) || ((HA->Ext->SBIC.WD33C93.State & WD_COMPOUND_CMD) && (HA->Ext->SBIC.WD33C93.State & WD_COMPOUND_CMPLT))) {
+
+ TRACE(3,("WD33C93_ISR(): Expected disconnect\n"));
+
+ } else {
+
+ if (ErrorClass(ReqAPIStatus(HA->CurrReq)) !=TargetClass) {
+
+ // The request status is not of target class, so we have not seen a status phase
+ TRACE(3, ("WD33C93_ISR(): Unexpected disconnect\n"));
+ ReqAPIStatus(HA->CurrReq) = S_AD_FREE; // Unexpected bus free
+
+ } else {
+
+ // We have seen a status phase, so this is an expected bus free
+ TRACE(3,("WD33C93_ISR(): Expected disconnect\n"));
+
+ }
+
+ ReqDone(HA, HA->CurrReq);
+
+ }
+ HA->State.Busy = 0; // Mark the adapter as free, to allow new requests to start
+ BusFree(HA, 2);
+ break;
+
+
+ case WD_STAT_PARITY:
+
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDSetAtnCmd); /* Set attention */
+ // Fall Through
+
+ case WD_STAT_PARITY_ATN:
+
+ TRACE(2, ("WD33C93_ISR(): Parity error detected\n"));
+ LogMessage(HA, HA->CurrReq, HA->CurrDev->SCSI_ID, 0, MSG_PARITY, __LINE__);
+ HA->Ext->MO_Buff[HA->Ext->MO_Count++] = MSG_INIT_ERROR;
+ SendWDCmd(HA->Ext->SBIC.WD33C93.WDSelPort, HA->Ext->SBIC.WD33C93.WDDataPort, WDNegAckCmd);
+ break;
+
+
+ default:
+
+// LogMessage(HA, HA->CurrReq, 0, 0, MSG_INTERNAL_ERROR, Stat);
+ TRACE(0, ("WD33C93_ISR(): Unknown status 0x%02x\n", Stat));
+// BreakPoint(HA);
+ HA->Service(HA_RESET_BUS, HA, (U32)0);
+ break;
+
+ }
+ AcceptReq(HA);
+}
diff --git a/private/ntos/miniport/always/33c93.h b/private/ntos/miniport/always/33c93.h
new file mode 100644
index 000000000..f2b171052
--- /dev/null
+++ b/private/ntos/miniport/always/33c93.h
@@ -0,0 +1,145 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#ifndef __33C93_H__
+#define __33C93_H__
+
+#define WDOwnIDReg 0 /* (R/W) */
+#define WDCDBSizeReg 0 /* (R/W) */
+#define WDControlReg 1 /* (R/W) */
+#define WDTimeoutReg 2
+#define WDCDBReg 3
+#define WDTarLUNReg 0xf /* Write: Sets target LUN; Read: Target status */
+ /* byte from Select-and-Transfer commands */
+#define WDPhaseReg 0x10 /* WD Current phase */
+#define WDSyncReg 0x11 /* Sync. xfer configuration */
+#define WDCountReg 0x12 /* Xfer count msb, mid and lsb follow */
+#define WDDestIDReg 0x15 /* Destination SCSI ID for Sel or Resel */
+#define WDSourceReg 0x16 /* Who selected us; enable sel/resel */
+#define WDStatusReg 0x17 /* WD Command status */
+#define WDCMDReg 0x18 /* WD COmmand code register */
+#define WDDataReg 0x19 /* WD Data xfer register */
+#define WDAuxStatReg 0x1f /* Indirect access to aux. status */
+
+/* Aux Status bits: */
+#define WD_DBR 0x1 /* Data buffer ready */
+#define WD_Parity 0x2 /* Parity error */
+#define WD_CIP 0x10 /* Command in progress */
+#define WD_Busy 0x20 /* Level II command in progress */
+#define CommandIGN 0x40 // Last command ignored
+#define IntPending 0x80 // Interrupt pending
+
+/* Own ID register */
+#define DefualtHostID 0x7 /* Own SCSI ID */
+#define EnADV 0x8 /* Enable advanced features */
+#define EnHParity 0x10 /* Enable host parity */
+#define FreqSel 0xc0 /* Input frequency select */
+
+/* Western Digital control register */
+#define HaltPE 0x1 /* Halt on parity error */
+#define HaltATN 0x2 /* Halt on attention */
+#define EnableIDI 0x4 /* enable intermediate disc. inter. */
+#define EnableEDI 0x8 /* Enable ending disconnect inter. */
+#define EnableHHP 0x10 /* Enable halt on host parity */
+#define DMAModeMask 0xe0 /* DMA Mode select */
+#define DMAPIO 0x00 /* DMA mode: Polled I/O */
+#define DMABurst 0x20 /* DMA mode: Burst DMA */
+#define DMABus 0x40 /* DMA mode: 33C93 BUS mode */
+#define DMAStd 0x80 /* DMA mode: standard async. handshake */
+
+/* Target LUN register */
+#define WDTargetLUNMask 0x7 /* LUN of target */
+#define DisconOK 0x40 /* Allow disconnects */
+#define Valid 0x80 /* LUN fieldis valid */
+
+/* Destination ID register */
+#define DestID 0x7 /* Destination ID */
+#define DataReadDir 0x40 /* Data phase direction 1=Read */
+#define EnableSCC 0x80 /* Enable selct command chain */
+
+/* Source ID register */
+#define SourceID 0x7 /* Source ID */
+#define IDValid 0x8 /* Source ID valid */
+#define DisSelPar 0x20 /* Disable sel/resel parity */
+#define EnableSel 0x40 /* Enable selection */
+#define EnableRSel 0x80 /* Enable reselection */
+
+
+
+/* WD Status, read from registr 0x17 */
+//#define SubCode 0xf /* WD Status code */
+//#define StatusCode 0xf0 /* WD Status */
+#define WD_STAT_RESET 0x00 /* Reset received */
+#define WD_STAT_RESETA 0x01 /* Reset in advanced mode */
+#define WD_STAT_RESEL_OK 0x10 /* Reselct command OK */
+#define WD_STAT_SELECT_CMPLT 0x11 // Select command completed successfully
+#define WD_STAT_SandT_CMPLT 0x16 // Select and xfer completed OK
+#define WD_STAT_XFER_PAUSED 0x20
+#define WD_STAT_BAD_DISC 0x41 // Unexpected disconnect (bus free)
+#define WD_STAT_SEL_TO 0x42 // Selection timeout
+#define WD_STAT_PARITY 0x43 // A parity error caused the xfer to terminate, no atn
+#define WD_STAT_PARITY_ATN 0x44 // A parity error caused the xfer to terminate, atn asserted
+#define WD_STAT_SAVE_PTR 0x21 // A save data pointers during a S & T
+#define WD_STAT_BAD_STATUS 0x47 // An incorrect status byte
+#define WD_STAT_RESELECTED 0x80 // A device has reselected us
+#define WD_STAT_RESELECTED_A 0x81 // Been reselected in advanced mode
+#define WD_STAT_SELECTED 0x82 // We have been selected
+#define WD_STAT_SELECTED_ATN 0x83 // "" with ATN
+#define WD_STAT_DISCONNECT 0x85 /* Disconnect occured */
+
+/* Masked phase bits, makes use of fact that phase changes always have the 0x08 bit set */
+#define WD_PHASE_MASK 0x0f /* Mask for new phase */
+#define WD_MDATA_OUT 0x08 /* Masked-- Data out phase */
+#define WD_MDATA_IN 0x09
+#define WD_MCOMMAND 0x0a
+#define WD_MSTATUS 0x0b
+#define WD_MMSG_OUT 0x0e
+#define WD_MMSG_IN 0x0f
+
+
+/* WD Commands 0x */
+/* Level I */
+#define WDResetCmd 0
+#define WDAbortCmd 1
+#define WDSetAtnCmd 2
+#define WDNegAckCmd 3
+#define WDDisconnectCmd 4
+#define WDStatCmpltCmd 0xd /* Send Status and Command complete */
+#define WDSetIDICmd 0xf
+
+/* Level II */
+#define WDReselCmd 5
+#define WDSelATNCmd 6 /* Select w/ATN */
+#define WDSelCmd 7 /* Select w/o ATN */
+#define WDSelATNXCmd 8 /* Select w/ATN and transfer */
+#define WDSelXCmd 9 /* Select and transfer */
+#define WDRselRcvCmd 0xa /* Reselect and receive */
+#define WDRselSndCmd 0xb /* Reselect and send data */
+#define WDWaitRcvCmd 0xc /* Wait for select and receive */
+#define WDSendDiscCmd 0xe /* Send discconect message */
+#define WDRcvCmdCmd 0x10 /* Receive command */
+#define WDRcvDataCmd 0x11 /* Receive data */
+#define WDRcvMsgCmd 0x12 /* Receive message out */
+#define WDRcvUnspecCmd 0x13 /* Receive unspecified data */
+#define WDSendStatCmd 0x14 /* Send status */
+#define WDSendDataCmd 0x15
+#define WDSendMsgINCmd 0x16 /* Send message in */
+#define WDSendUnspecCmd 0x17 /* Send unspecified info */
+#define WDXlateAddrCmd 0x18 /* Translate address */
+#define WDXferInfo 0x20 /* Transfer info */
+#define WDSingleByte 0x80 /* Single byte xfer mask for xfer commands */
+
+
+
+/* State bits for the state field in the wd33c93s struct:
+ (see wd33c93s.h)
+*/
+
+#define WD_NO_STATE 0x00 /* Non-descript state */
+#define WD_BLOCK_XFER 0x01 /* Doing a block xfer */
+#define WD_COMPOUND_CMD 0x02 /* Using WD's compound command */
+#define WD_COMPOUND_CMPLT 0x04 // WD Command complete interrupt seen
+
+#endif /* __33C93_H__ */
diff --git a/private/ntos/miniport/always/33c93s.h b/private/ntos/miniport/always/33c93s.h
new file mode 100644
index 000000000..3cafe0cbb
--- /dev/null
+++ b/private/ntos/miniport/always/33c93s.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#ifndef __33C93S_H__
+#define __33C93S_H__
+
+#define USES33C93
+
+struct WD33C93S {
+
+ IOHandle WDSelPort; /* IO address of select/status register */
+ IOHandle WDDataPort; /* IO address on this board for data port */
+
+ U8 MHz; /* Ext. clock freq. */
+ U8 IFreq; /* Internal freq (X-clock/clock divisor) */
+ U8 AsyncValue; /* Board sync. xfer value for async xfers */
+ U8 State;
+ U8 MI_Temp; /* Temp holding register for received msgs */
+ U8 TID; /* Target ID of reselection */
+
+ };
+
+
+#endif /* __33C93S_H__ */
diff --git a/private/ntos/miniport/always/adapters.c b/private/ntos/miniport/always/adapters.c
new file mode 100644
index 000000000..6e778adbe
--- /dev/null
+++ b/private/ntos/miniport/always/adapters.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#include "environ.h"
+#include "rqm.h"
+#include "api.h"
+#include "apiscsi.h"
+#include "debug.h"
+
+
+#if defined(AL7000)
+ extern int Find_AL7000(ADAPTER_PTR HA, unsigned *Context);
+#endif
+
+#ifdef AL4000H
+ extern int Find_AL4000H(ADAPTER_PTR HA, unsigned *Context);
+#endif
+
+#ifdef IN2000
+ extern int Find_IN2000(ADAPTER_PTR HA, unsigned *Context);
+#endif
+
+#ifdef AL4000I
+ extern int Find_AL4000I(ADAPTER_PTR HA, unsigned *Context);
+#endif
+
+#ifdef NCREVAL /* Emulex FAS216 eval unit */
+ extern int Find_NCR_Eval(ADAPTER_PTR HA, unsigned *Context);
+#endif
+
+
+
+static int ((*HA_List[])(ADAPTER_PTR HA, unsigned *Context)) = {
+
+#ifdef AL4000H
+ Find_AL4000H, /* Host side AL4000 code */
+#endif
+
+#if defined(AL7000)
+ Find_AL7000,
+#endif
+
+#ifdef IN2000
+ Find_IN2000,
+#endif
+
+#ifdef AL4000I
+ Find_AL4000I, /* AL4000 imbedded firmware */
+#endif
+
+#ifdef NCREVAL /* NCR 53C94 eval board */
+ Find_NCR_Eval,
+#endif
+
+ NULL};
+
+
+
+/*
+
+ This procedure is repeatedly called to find all adapters. It searches the list of all adapters, calling
+their find routine until an adapter is located. It is passed a pointer to an int (Context), which is zero on
+the first call. The find routine updates the Context to a value it can use to restart the search. Only one
+adapter is found per call. Subsequent adapters are found on later calls. An adapters find routine will be
+called repeatedly, until it returns a zero, which means it found no additional adapters. When an adapter is
+found, the passed adapter structure (HA) is filled in, and a value of 1 is returned.
+
+ */
+
+int
+Adapter_Init (ADAPTER_PTR HA, unsigned *Context)
+{
+ unsigned i=(*Context) >> 8, j=(*Context) & 0xff;
+
+ /* Step through the list of adapter find routines to find all adapters */
+ while (HA_List[i] != NULL) {
+
+ TRACE(4, ("Adapter_Init(): Calling find routine at %x for adapter %x, Context = %x\n", HA_List[i], HA, *Context));
+ if ((HA_List[i])(HA, &j)) {
+
+ *Context = (i << 8) | j;
+ TRACE(4, ("Adapter_Init(): Adapter found, new context = %x\n", *Context));
+ return 1;
+
+ }
+
+ i++;
+ j = 0;
+
+ }
+ return 0;
+}
diff --git a/private/ntos/miniport/always/adapters.h b/private/ntos/miniport/always/adapters.h
new file mode 100644
index 000000000..69e73ab2c
--- /dev/null
+++ b/private/ntos/miniport/always/adapters.h
@@ -0,0 +1,63 @@
+#ifndef __ADAPTERS_H__
+#define __ADAPTERS_H__
+
+#ifdef IN2000
+#include "in2000s.h"
+#endif
+
+#ifdef AL4000h
+#include "al4000hs.h"
+#endif
+
+#ifdef AL4000I
+#include "al4000is.h"
+#endif
+
+#ifdef NCREVAL
+#include "ncrevals.h"
+#endif
+
+#ifdef AL7000
+#include "al7000s.h"
+#endif
+
+#ifdef EVAL710
+#define USES710
+#include "eval7x0s.h"
+#endif
+
+union AdapterU {
+#ifdef IN2000
+ struct IN2000S IN2000U;
+#endif /* IN2000 */
+#ifdef AL4000
+ struct AL4000HS AL4000HU;
+#endif
+#ifdef AL4000I /* AL4000 on board scsi interface */
+ struct AL4000IS AL4000IU;
+#endif
+#if defined(AL7000)
+ struct AL7000S AL7000U;
+#endif
+};
+
+union SBICU {
+#ifdef USESCDV
+ struct CDVS CDV;
+#endif
+
+#ifdef USES33C93
+ struct WD33C93S WD33C93;
+#endif
+
+#ifdef USES53C94
+ struct NCR53C94S NCR53C94;
+#endif
+#if defined(USES710) || defined(USES720)
+ struct NCR53c7x0S NCR53C7x0;
+#endif
+};
+
+extern int Adapter_Init(ADAPTER_PTR HA, unsigned *Context);
+
+#endif
diff --git a/private/ntos/miniport/always/always.rc b/private/ntos/miniport/always/always.rc
new file mode 100644
index 000000000..68f021b74
--- /dev/null
+++ b/private/ntos/miniport/always/always.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Always Technology SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "always.sys"
+#define VER_ORIGINALFILENAME_STR "always.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/always/api.h b/private/ntos/miniport/always/api.h
new file mode 100644
index 000000000..61257ff7b
--- /dev/null
+++ b/private/ntos/miniport/always/api.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and should be treated as confidential.
+ */
+
+#ifndef __API_H__
+#define __API_H__
+
+
+/* Classes of error conditions */
+#define RequestClass 0x000
+#define AdapterClass 0x100
+#define TargetClass 0x200
+#define SystemClass 0x300
+#define ErrorClass(Error) ((Error) & 0xff00)
+#define ErrorCode(Error) ((Error) & 0x00ff)
+#define TargetStatus(Status) (TargetClass | (unsigned)Status)
+
+
+/* Codes by class: Request Class */
+#define S_REQ_ACCEPTED RequestClass + 0x00 // Request accepted and queued
+#define S_REQ_STARTED RequestClass + 0x01 // Request started execution
+#define S_REQ_ABORT RequestClass + 0x02 // Request was aborted via abort command
+#define S_REQ_OPCODE RequestClass + 0x03 // Request has bad operation code
+#define S_REQ_REQUEST RequestClass + 0x04 // Request is otherwise malformed
+#define S_REQ_BADHA RequestClass + 0x05 // Bad adapter identifier
+#define S_REQ_OVERRUN RequestClass + 0x06 // The target requested to transfer more data than available
+#define S_REQ_NOTAR RequestClass + 0x07 // The requested target is not responding
+#define S_REQ_BADTAR RequestClass + 0x08 // The SCSI ID is out of range for this adapter
+#define S_REQ_BADLUN RequestClass + 0x09 // The SCSI LUN is out of range for this adapter
+
+
+/* Codes by class: Adapter Class */
+#define S_AD_OFF AdapterClass + 0x00 // Adapter offline
+#define S_AD_BUSY AdapterClass + 0x01 // Adapter busy or full
+#define S_AD_FREE AdapterClass + 0x02 // Unexpected bus free
+#define S_AD_PHASE AdapterClass + 0x03 // Unexpected phase
+#define S_AD_RESET AdapterClass + 0x04 // Request aborted due to reset
+#define S_AD_AUTOSENSE_OK AdapterClass + 0x05 // Req received OK autosense data
+#define S_AD_AUTOSENSE_FAIL AdapterClass + 0x05 // Req failed to receive autosense data
+
+
+/* Codes by class: Target Class (Target status phase) */
+#define S_TAR_NOERROR TargetClass + 0x00 // Target completed request w/no error
+#define S_TAR_CHECKCOND TargetClass + 0x02 // Request completed with Check condition status
+#define S_TAR_BUSY TargetClass + 0x08 // Device busy
+#define S_TAR_QUEUEFULL TargetClass + 0x28 // Target queue full
+
+
+/* Codes by class: System Class */
+
+
+// Last internal S_xx codes, for consistancy checks:
+#define S_LAST_S_REQ 0x09
+#define S_LAST_S_AD 0x06
+#define S_LAST_S_SYS 0x00
+
+typedef enum {NonTerminal, Terminal, DetectTerminal} TerminateCode;
+typedef enum {NotSenseable, Senseable} AutosenseCode;
+
+typedef U16 APIStatus;
+
+extern int API_Init(void);
+extern void APISetStatus(IO_REQ_PTR Req, APIStatus Status, TerminateCode Terminal, AutosenseCode IsSenseable);
+
+#if !defined(APINotifyReset)
+extern void APINotifyReset(ADAPTER_PTR HA);
+#endif
+
+#if !defined(APIFindDev) // See if it's already a macro
+extern DEVICE_PTR APIFindDev(const ADAPTER_PTR HA, const U16 TID, const U16 LUN);
+#endif
+
+extern void GetXferSegment(const ADAPTER_PTR HA, IO_REQ_PTR Req, SegmentDescr *SGDescr, U32 Offset, BOOLEAN DemandPhysical);
+
+#endif /* __API_H__ */
diff --git a/private/ntos/miniport/always/apiscsi.h b/private/ntos/miniport/always/apiscsi.h
new file mode 100644
index 000000000..b033273fd
--- /dev/null
+++ b/private/ntos/miniport/always/apiscsi.h
@@ -0,0 +1,170 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and should be treated as confidential.
+ */
+
+#ifndef __SCSI_H__
+#define __SCSI_H__
+
+typedef U8 SCSI24[3];
+typedef U8 SCSI32[4];
+
+
+/* Standard SCSI commands and codes and things: */
+
+#define STATUS_GOOD 0x00 // Request completed OK
+#define STATUS_CKCOND 0x02 // Check condition
+#define STATUS_CONDMET 0x04 // Search condition met
+#define STATUS_BUSY 0x08 // Device busy
+#define STATUS_INTGOOD 0x10 // Intermediate good condition
+#define STATUS_INTCONDMET 0x14 // Intermediate condition met
+#define STATUS_RESCONF 0x18 // Reservation conflict
+#define STATUS_QUEUEFULL 0x28 // Request queue full
+
+#define MSG_IDENTIFY 0x80
+#define MSG_ALLOW_DISC 0x40
+#define MSG_LUN_MASK 0x07
+
+/* Extended messages (Command 1): */
+#define MSG_EXTD_MSG 0x1
+#define XMSG_MODIFY_PTR 0x00 // Modify data pointers
+#define XMSG_SYNC_REQ 0x01
+#define XMSG_EXTD_IDENT 0x02 /* Pre-SCSI 2 */
+#define XMSG_WIDE_REQ 0x03
+
+/* Single byte messages (0, 0x02-0x1f) */
+#define MSG_COMPLETE 0x00 /* Command complete */
+#define MSG_SAVE_PTR 0x02 /* Save data pointers */
+#define MSG_RESTORE_PTR 0x03 /* Restore from saved data pointers */
+#define MSG_DISCONNECT 0x04 /* Target is temp. disconnecting */
+#define MSG_INIT_ERROR 0x05 /* Initiator detected error */
+#define MSG_ABORT 0x06 /* Abort all active target operations */
+#define MSG_REJECT 0x07 /* Last message is rejected */
+#define MSG_NOP 0x08 /* No operation */
+#define MSG_MSG_PARITY 0x09 /* Parity error on last message */
+#define MSG_LINK_CMPLT 0x0a /* Linked command complete */
+#define MSG_LINKF_CMPLT 0x0b /* Linked command with flag complete */
+#define MSG_DEVICE_RESET 0x0c /* Reset device */
+#define MSG_ABORT_TAG 0x0d /* Abort current I/O */
+#define MSG_CLEAR_Q 0x0e /* Clear queue */
+#define MSG_INIT_RECOVERY 0x0f
+#define MSG_REL_RECOVERY 0x10
+#define MSG_TERM_IO 0x11
+
+/* Two byte messages */
+#define MSG_SIMPLEQUEUE 0x20 /* Simple tage queue message */
+#define MSG_HEADQUEUE 0x21 /* Head of tag queue */
+#define MSG_ORDEREDQUEUE 0x22 /* Ordered tag queue */
+#define MSG_IGNORERES 0x23 /* Ignore wide residue */
+
+
+/* Response codes from Receive_Msg: (in addition to standard messages): */
+#define MI_MORE 0xf0 /* More message bytes expected */
+#define MI_SEND_MSG 0xf1 /* Response is in MO buffer; goto msg out phase */
+#define MI_SYNC_RESP 0xf2 /* Got a response from our sync. request; update values */
+#define MI_SYNC_REQ 0xf3 /* Got a sync. request; update ptrs; send MSG OUT buffer */
+
+struct RSenseStruct {
+ unsigned ErrorCode:7;
+ unsigned Valid:1;
+
+ U8 Res1;
+
+ unsigned SenseKey:4;
+ unsigned res2:4;
+
+ U8 Info[4];
+ U8 AddlLen;
+ U8 CmdInfo[4];
+ U8 AddlCode;
+ U8 AddlQual;
+ U8 res3, res4;
+ };
+
+
+struct MSenseStruct {
+
+ U8 DataLen;
+ U8 MediumType;
+
+ unsigned res1:7;
+ unsigned WProtect:1;
+
+ U8 BlockDiscLen;
+ U8 DensityCode; /* Start of default block descriptor */
+ SCSI24 BlockCount;
+ U8 res2;
+ SCSI24 BlockLen;
+};
+
+
+struct CapacityStruct {
+ SCSI32 LastBlock;
+ SCSI32 BlockLen;
+};
+
+
+
+struct InquiryStruct {
+
+ unsigned PeriphDevType:5; // See DT_ codes below
+ unsigned PeriphQual:3;
+
+ unsigned DTQual:7; // Device type qualifier
+ unsigned RMB:1; // Removable media bit
+
+ unsigned ANSIVersion:3; // ANSI version of SCSI supported (s.b. 1 or 2)
+ unsigned ECMAVersion:3;
+ unsigned ISOVersion:2;
+
+ unsigned ResponseFormat:4;
+ unsigned Res1:3;
+ unsigned AENC:1; // Device can generate (periph)/accept (processor) aysync. event notifications
+
+ U8 AddlLength; // Number of additional bytes following
+
+ U8 Res2;
+ U8 Res3;
+
+ unsigned SoftRes:1; // Device uses soft resets
+ unsigned CmdQueue:1; // Device supports command queuing
+ unsigned Res4:1;
+ unsigned Linked:1; // Device supports linked commands
+ unsigned Sync:1; // Device supports synchronous xfers
+ unsigned WBus16:1; // Device supports 16 bit wide SCSI
+ unsigned WBus32:1; // Device supports 32 bit wide SCSI
+ unsigned RelAddr:1; // Device supports relative addressing
+
+ U8 VendorID[8]; // Vendor name (ASCII)
+ U8 ProductID[16]; // Product name (ASCII)
+ U8 Revision[4]; // Revision, ASCII or binary
+ U8 AddlInfo[1]; // Additional information
+
+};
+
+// device type codes from inquiry command:
+#define DT_DIRECT 0 // Direct access storage device (disk ...)
+#define DT_SEQUENTIAL 1 // Sequential (Tape, ...)
+#define DT_PRINTER 2 // guess...
+#define DT_PROCESSOR 3
+#define DT_WORM 4
+#define DT_ROM 5 // CD-ROM, other rad only direct access device
+#define DT_SCANNER 6
+#define DT_OPTMEM 7 // Other types of optical memory
+#define DT_CHANGER 8 // Changer (tape, cartridge, disk, ...)
+#define DT_COMM 9 // Communications device
+#define DT_REMOVEABLE 0x80 // Removable media qualifier
+#define DT_NOTPRESENT 0x1f // LUN not present or not supported
+
+#define SCSIIn 1
+#define SCSIOut 0
+
+extern void BusFree(ADAPTER_PTR HA, int StartLevel);
+extern void SCSIBusHasReset(ADAPTER_PTR HA);
+extern int Interpret_MSG(ADAPTER_PTR HA);
+extern void SCSIMakeIdentify(ADAPTER_PTR HA, unsigned LUN, BOOLEAN AllowDisc);
+extern int SCSISendAbort(ADAPTER_PTR HA);
+extern int SCSISendReject(ADAPTER_PTR HA);
+extern int Receive_Msg(ADAPTER_PTR HA, U8 Msg);
+
+#endif /* __SCSI_H__ */
diff --git a/private/ntos/miniport/always/debug.h b/private/ntos/miniport/always/debug.h
new file mode 100644
index 000000000..b1be949e3
--- /dev/null
+++ b/private/ntos/miniport/always/debug.h
@@ -0,0 +1,25 @@
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#if defined(DEBUG_ON)
+
+ #if !defined(DEBUG_TOKEN)
+ #define DEBUG_TOKEN debug
+ #endif
+ extern int DEBUG_TOKEN;
+
+ #define TRACE(l,s) if (l <= DEBUG_TOKEN) ScsiDebugPrint s
+ #define DmsPause(l, p) if (l <= DEBUG_TOKEN) msPause(p)
+ #define BreakPoint(HA) EnvBreakPoint(HA)
+ #define DEBUG(l,e) if (l <= DEBUG_TOKEN) ScsiDebugPrint e
+
+#else
+
+ #define TRACE(l,s)
+ #define DmsPause(l,p)
+ #define BreakPoint(HA)
+ #define DEBUG(l,e)
+
+#endif
+
+#endif /* __debug_h__ */
diff --git a/private/ntos/miniport/always/environ.h b/private/ntos/miniport/always/environ.h
new file mode 100644
index 000000000..17637d836
--- /dev/null
+++ b/private/ntos/miniport/always/environ.h
@@ -0,0 +1,89 @@
+#ifndef __ENVIRON_H__
+#define __ENVIRON_H__
+
+#ifdef DOSDRIVER
+#define NATIVE16
+#define DEBUG_TOKEN debug_api
+#include "std.h"
+#include "types.h"
+#include "msdrvenv.h"
+#include "idosaspi.h"
+#endif
+
+
+
+#ifdef DOSTEST
+#define NATIVE16
+#define DEBUG_TOKEN debug_api
+#include <dos.h>
+#include "types.h"
+#include "msdosenv.h"
+#include "idosaspi.h"
+#endif
+
+
+
+#ifdef SCOUNIX
+#define NATIVE32
+#define DEBUG_TOKEN debug_api
+#include "scounix.h"
+#endif
+
+
+
+#ifdef NW386
+#define LOCAL
+#define NATIVE32
+#define DEBUG_TOKEN debug_api
+#include "std.h"
+#include "nw386.h"
+#include "inline.h"
+#include "aspimacs.h"
+#include "inwaspi.h"
+#endif
+
+
+
+#ifdef WINNT
+
+#if DBG!=0 // If this is a checked build...
+#undef USEFASTCALLS // disable _fastcall, which forces static
+#endif
+
+#define NATIVE32
+#include "..\..\inc\miniport.h"
+#include "ntenv.h"
+#include "intsrb.h"
+#define SEPERATELUNS
+
+// If this is a free build, shut off debug messages and tests:
+#if DBG==0
+#undef DEBUG_ON
+#else
+#define DEBUG_TOKEN debug_api
+#undef ASSERT // miniport.h defines ASSERT as null
+#endif
+
+#endif
+
+
+
+
+#ifdef AL4000I
+#define NATIVE16
+#define DEBUG_TOKEN debug_api
+#define SMARTHA
+#include "std.h"
+#include "rtkenv.h"
+#include "rtk.h"
+#include "rtklib.h"
+#include "pim.h"
+#include "haaspi.h"
+#include "smartha.h"
+#endif
+
+
+
+#include "envlib.h"
+
+#endif /* __ENVIRON_H__ */
diff --git a/private/ntos/miniport/always/envlib.h b/private/ntos/miniport/always/envlib.h
new file mode 100644
index 000000000..afea3e3c5
--- /dev/null
+++ b/private/ntos/miniport/always/envlib.h
@@ -0,0 +1,184 @@
+/* Copyright (C) 1991 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and should be treated as confidential.
+*/
+
+#ifndef __ENVLIB_H__
+#define __ENVLIB_H__
+
+#define FourCharVers "13.14"
+
+/* Revision:
+ .13.14- Added "NO DISCONNECT" flag to DOS ASPIrequests. Int 13 sets this flag.
+ .13.13- Fix rounding of sync. period in 53c7x0.c.
+ .13.12- 53C7x0 plug handles Reject messages on sync. negotiations.
+ .13.11- Map to physical now uses the same segment descriptor as GetXferSegment()
+ .13.10- Support for revert & resume configurations; add power down commands
+ to board plugs.
+ .13.9 - Fixed '720 driver to DWORD align the script only once in a multi-
+ adapter configuration.
+ .13.8 - 53c7x0: Added support for phase verification.
+ .13.7 - Support for discontiguous SCSI IDs for INT 13.
+ .13.6 - Fixed '7000 load of burst length register, switch polarity for
+ cache line burst
+ .13.5 - Attach sync. negotiations to non-data commands.
+ - Added timer support to msdrvenv.c - Currently disabled
+ .13.4 - Change from leaving ints disabeld in IN2000_ISR() to using
+ InDOSFlag in General_ISR() in MSDRVENV.C
+ - Increase timeout count in WaitForRead in 33c93.c
+ .13.3 - Fix report of last cyl. number in Int 13 GetParam
+ .13.2 - Fix AL-7000 IRQ decode.
+ .13.1 - VDS support
+ .13 - Additional fixes to '720 disconnects. First real release
+ for AL7000.
+ .12.16- Fixed 53c7x0 to not get illegal instr. when reselect comes in
+ when a select is started.
+ .12.15- Changed I/O decodes for AL-7000
+ .12.14- Support for Chicago; S/G fix to IN2000.c
+ .12.11- Added S/G support to ASPIMGR and to AL7000 pieces.
+ .12.10- Added Int 15 support to Int 13 handler
+ .12.9 - Fixed connect/disconnect in 53c7x0.c
+ .12.8 - Added variables "GlobalAllowDisc" & "GlobalAllowSync" to ASPIMGR.C.
+ - Changed DOS ASPIDRVR.ASM to scan command line and set these variables.
+ .12.7 - Added int-13 support for AL-7000, and others using BIOS control interface
+ .12.6 - Added support for AL-7000
+ .12.5 - Changed INT 13 code to be compatable with VCN: 1-04 BIOS
+ .12.4 - Fixed "GetDASD" to preserve ES.
+ .12.3 - Corrected target initiated sync. xfer. request by adding a parameter
+ to AskSync()
+ - Corrected the conditionals for xfer period and offset in target initiated
+ sync. xfer. request.
+ - Modified Int 13 code to support VCN: 1-04 bios
+ .12.2 - Fixed bug in IN2000_ISR(), where it would spin flushing the FIFO
+ upon completion of a write, while waiting for the 33C93 interrupt.
+ - EVAL720 code.
+ .12.1 - Added size definitive typeing (i.e. U32)
+ .12 - Release of 11.9
+ .11.9 - Fixed problem with release of device descriptors on device timeout.
+ Fixed long delay on selection timeout
+ .11.8 - Fixed synchronous calculation in 33c93 initalize
+ Enabled Synchronous as default
+ .11.7 - Made DOS driver work with 11.6 changes
+ .11.6 - Started work on NT driver
+ .11.5 - More generalizing stuff
+ .11.4 - Robert Lou added AL6K plug
+ .11.3 - Changed Adapter structure to add Physical & Supports structures
+ .11.2 - Modified to common error code, returned through APISetStatus
+ .11 - Release of 10.3
+ .10.3 - Added delay in IN2000.c after reset to allow 33C93 to settle.
+ - Reduced the min. number of device descr., since LUNs no longer
+ require unique device descr.
+ .10.2 - Fixed adapter id message from ASPI adapter info command
+ .10.1 - Internal; Shortens reset time from 250 ms to a pulse
+ .10 - First non-beta release; fixed problems w/ smart drive
+
+*/
+
+
+// Scatter / gather segment descriptor:
+typedef struct {
+
+ // Offset of last use of this descr.; -1 if invalid
+ U32 LastOffset;
+
+ // Work areas for S/G handler; preserved from last call only if LastOffset != -1
+ U32 APIScratch[2];
+ U32 MappingScratch[2]; // Area reserved for MapToPhysical and UnlockRegion
+
+ // Length in bytes of (remaining) segment described by SegmentPtr
+ U32 SegmentLength;
+
+ // Pointer to data buffer, to start/resume data xfer
+ U32 SegmentPtr;
+
+ struct {
+
+ BOOLEAN Valid; // Is SegmentPtr a valid address?
+ BOOLEAN IsPhysical; // Is SegmentPtr (above) physical?
+ BOOLEAN SegmentNeedsUnlocking; // Do we need to Unlock when done?
+
+ } Flags;
+
+} SegmentDescr;
+
+
+#if !defined(critical)
+extern void critical(struct Adapter ALLOC_D *HA); // Conditional (nested) start critical context
+extern void uncritical(struct Adapter ALLOC_D *HA); // Conditional (nested) end critical context
+extern int MaybeCritical(void); // Set critical if machine in critical state
+extern void MaybeUncritical(int Was); // Balance the MaybeUncritical, using its return value
+#endif
+
+extern void Notify(struct Adapter ALLOC_D *HA, IO_REQ_PTR Req); // Signal a request completion
+
+#if !defined(min)
+#define min(X, Y) ((X <= Y) ? X : Y)
+#endif
+
+#if !defined(max)
+#define max(X, Y) ((X >= Y) ? X : Y)
+#endif
+
+
+#if !defined(NW386)
+#if !defined(LogMessage)
+extern void LogMessage(ADAPTER_PTR HA, IO_REQ_PTR Req, int TID, int LUN, int ErrCode, int Misc);
+#endif
+#endif
+
+extern ALLOC_T allocm(unsigned count);
+
+extern void freem(ALLOC_T block, unsigned count);
+
+extern void copym(ALLOC_T dest, ALLOC_T src, unsigned count);
+
+extern void DMASetup(unsigned Channel, void FAR *MemHndl, U32 Index,
+ U32 Count, int UseSGList, unsigned Direction);
+
+extern void DMAComplete(unsigned Channel, void FAR *MemHndl, U32 Index,
+ U32 Count, int UseSGList, unsigned Direction);
+
+extern U32 MapToPhysical(void ALLOC_D *HA, SegmentDescr *Descr);
+extern void UnlockRegion(void ALLOC_D *HA, SegmentDescr *Descr);
+extern void FAR *MapToVirtual(void ALLOC_D *HA, U32 PAddr);
+
+#if !defined(ExportReq)
+extern IO_REQ_PTR ExportReq(IO_REQ_PTR Req);
+#endif
+
+#if !defined(ImportReq)
+extern IO_REQ_PTR ImportReq(IO_REQ_PTR Req);
+#endif
+
+#if !defined(msPause)
+extern void msPause(unsigned msTicks);
+#endif
+
+#if !defined(PanicMsg)
+extern void PanicMsg(char *Msg);
+#endif
+
+#if !defined(RegisterIO)
+extern IOHandle RegisterIO(struct Adapter ALLOC_D *HA, U16 Base, U16 Length, int AddrSpace);
+#endif
+
+#if !defined(repinsb)
+extern void repinsb(const unsigned port, unsigned char far *bufferp, unsigned count);
+#endif
+
+#if !defined(repoutsb)
+extern void repoutsb(const unsigned port, unsigned char far *bufferp, unsigned count);
+#endif
+
+#if !defined(repinsw)
+extern void repinsw(const unsigned port, unsigned short far *bufferp, unsigned wcount);
+#endif
+
+#if !defined(repoutsw)
+extern void repoutsw(const unsigned port, unsigned short far *bufferp, unsigned wcount);
+#endif
+
+extern void setm(ALLOC_T block, int val, unsigned count);
+extern ALLOC_T shrinkm(ALLOC_T oldblock, unsigned oldsize, unsigned newsize);
+
+#endif /* __ENVLIB_H__ */
diff --git a/private/ntos/miniport/always/in2000.c b/private/ntos/miniport/always/in2000.c
new file mode 100644
index 000000000..b433a7f87
--- /dev/null
+++ b/private/ntos/miniport/always/in2000.c
@@ -0,0 +1,801 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#include "environ.h"
+#include "rqm.h"
+#include "api.h"
+#include "apiscsi.h"
+#include "debug.h"
+
+#include "33c93.h"
+#include "in2000.h"
+
+#define StatMask 0xc1 // Bits of interest in FIFO status register
+
+#define FIFOThresh 16 // Minimum xfer lenth for FIFOed xfers
+#define FIFOPad 32 // How many bytes must be added to writes to push data out of FIFO
+#define FIFOFillOffset 64 // Minimum amout of room to leave at top of FIFO
+#define FIFOSize 2048 // Total size of FIFO
+#define MaxPreFill (FIFOSize / 2)
+
+#define AuxStat HA->IOBase+INAuxOff
+#define WDSelect HA->IOBase+INWDSelOff
+#define WDData HA->IOBase+INWDDataOff
+#define INData HA->IOBase+INDataOff
+
+#define lengthof(x) (sizeof(x) / sizeof(x[0]))
+
+// Prototypes:
+int IN2000_ISR(ADAPTER_PTR HA);
+U32 IN2000_Service(int Func, ADAPTER_PTR HA, U32 Misc);
+
+#define SetWDReg(HA,WDReg) outb(HA->Ext->AD.IN2000U.IOMap[INWDSelOff], (WDReg))
+#define ReadWDData(HA) inb(HA->Ext->AD.IN2000U.IOMap[INWDDataOff])
+#define ReadWDReg(HA,reg) (SetWDReg(HA,reg), ReadWDData(HA))
+#define WriteWDData(HA, val) outb(HA->Ext->AD.IN2000U.IOMap[INWDDataOff], (val))
+#define WriteWDReg(HA,reg,val) SetWDReg(HA,(reg));WriteWDData(HA, val)
+extern void WD33c93_ISR(ADAPTER_PTR HA);
+extern void WD33C93_Init(ADAPTER_PTR HA);
+extern BOOLEAN GlobalAllowSync;
+
+
+typedef struct {
+
+ U8 OwnID;
+ U8 CtrlReg;
+ U8 TimeOutReg;
+ U8 SourceReg;
+
+} StateBuffer;
+
+
+LOCAL void
+IN2000ReInit (ADAPTER_PTR HA)
+{
+ // Reset the chip with a reset command. The reset is complete when
+ // the interrupt register is set
+ WriteWDReg(HA, WDCMDReg, WDResetCmd);
+
+ while ((ReadWDReg(HA, WDAuxStatReg) & IntPending) == 0)
+ ;
+ ReadWDReg(HA, WDStatusReg); /* Clear the interrupt */
+
+ WD33C93_Init(HA);
+
+ HA->Ext->AD.IN2000U.CurrIntMask = INFIFOMask;
+ outb(HA->IOBase+INIntMaskOff, INFIFOMask); /* Mask off FIFO, allow 33c93 ints. */
+}
+
+
+LOCAL void
+IN2000ResetBus (ADAPTER_PTR HA)
+{
+ unsigned j;
+
+ TRACE(2, ("IN2000ResetBus(): \n"));
+ HA->Ext->AD.IN2000U.CurrIntMask = INFIFOMask;
+ outb(HA->Ext->AD.IN2000U.IOMap[INIntMaskOff], INFIFOMask); /* Mask off FIFO, allow 33c93 ints. */
+
+ // Issue a SCSI bus reset; SCSI-2 says reset can any length > 25uS,
+ // however, some devices lose their mind if reset is too long,
+ // So, we'll try for 50uS, assumeing an 8-MHz bus:
+ outb(HA->Ext->AD.IN2000U.IOMap[INResetOff], 0); // Assert reset
+ for (j=30; j; j--) // don't make reset too short, figure 10Mhz ISA bus, 4 cycles / IO
+ inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]); // but too long breaks some drives
+ inb(HA->Ext->AD.IN2000U.IOMap[INHWRevOff]); // de-assert reset
+
+ WriteWDReg(HA, WDCMDReg, WDResetCmd); // Reset chip, intr. will re-initialize it
+
+}
+
+
+LOCAL U32
+IN2000Init (ADAPTER_PTR HA)
+{
+ int j;
+
+ /* Mask off ints while we're in init. routine */
+ outb(HA->IOBase+INIntMaskOff, INFIFOMask | INSBICMask);
+
+ // Set up the I/O port map:
+ for (j=0; j<= 15; j++)
+ HA->Ext->AD.IN2000U.IOMap[j] = HA->IOBase + j;
+
+ // Issue a SCSI bus reset; SCSI-2 says reset can any length > 25uS,
+ // however, some devices lose their mind if reset is too long,
+ // So, we'll try for 50uS, assumeing an 8-MHz bus:
+ inb(HA->IOBase + INHWRevOff); // Precautionary deassert reset
+ outb(HA->IOBase + INResetOff, 0); // Reset the board
+ for (j=30; j; j--) // don't make reset too short, figure 10Mhz ISA bus, 4 cycles / IO
+ inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]); // but too long breaks some drives
+ inb(HA->IOBase + INHWRevOff); /* de-assert reset */
+ APINotifyReset(HA);
+
+ ((StateBuffer *)(HA->Ext->InitialState))->OwnID = 7;
+ ((StateBuffer *)(HA->Ext->InitialState))->CtrlReg = ReadWDReg(HA, WDControlReg);
+ ((StateBuffer *)(HA->Ext->InitialState))->TimeOutReg = ReadWDReg(HA, WDTimeoutReg);
+ ((StateBuffer *)(HA->Ext->InitialState))->SourceReg = ReadWDReg(HA, WDSourceReg);
+
+ HA->Ext->SBIC.WD33C93.WDSelPort = HA->IOBase;
+ HA->Ext->SBIC.WD33C93.WDDataPort = HA->IOBase+1;
+
+ HA->Ext->SBIC.WD33C93.MHz = 10; /* The IN-2000 uses a 10Mhz 33c93 */
+ HA->Ext->SBIC.WD33C93.AsyncValue = 0x30;
+
+ IN2000ReInit(HA);
+
+ HA->State.Allow = 1; // Allow request processing
+ return 0; // OK
+}
+
+
+
+int
+Find_IN2000 (ADAPTER_PTR HA, unsigned *Context)
+{
+ static const unsigned BaseList[]=
+ {0x100, 0x110, 0x200, 0x220}; /* Bits are inverted */
+ static const unsigned IRQList[]={10, 11, 14, 15};
+ unsigned Switch;
+ IOHandle INBase;
+ int HWVers;
+ unsigned Terminal = lengthof(BaseList);
+
+
+ // For Chicago:
+ //
+ // If HA->IOBase is entered != 0, then we need to find the index of the
+ // matching I/O address. If we find one, limit the terminus of the
+ // primary check below, so we check only one instance. If we don't find
+ // a match, then the primary loop below will fail to start. Not pretty,
+ // but it works.
+
+ if (HA->IOBaseAddr != 0) {
+
+ for (*Context = 0; *Context < lengthof(BaseList); (*Context)++)
+ if (HA->IOBaseAddr == BaseList[*Context])
+ break;
+
+ Terminal = min(*Context + 1, lengthof(BaseList));
+
+ }
+
+
+ TRACE(4, ("Find_IN2000(): HA Ptr = %x,Context = %x\n", HA, *Context));
+ for (; *Context < Terminal; DeregisterIO(HA, INBase), (*Context)++) {
+
+ INBase = RegisterIO(HA, BaseList[*Context], 15, AddrSpaceIO);
+ Switch = inb(INBase+INSwitchOff);
+ TRACE(5,("Find_IN2000(): Switch value read was: %02x\n", Switch));
+ if ((Switch & 3) != *Context) /* Do switch settings match? */
+ continue;
+
+ /* Check the version number port, see if it appears IN-2000-ish */
+ HWVers = inb(INBase+INHWRevOff);
+ TRACE(5,("Find_IN2000(): H/W version read as: %02x\n", HWVers));
+ if ((HWVers < 0x20) || (HWVers > 0x29))
+ continue;
+
+ if (HWVers < MinHWVers) {
+
+ LogMessage(HA, NILL, 0, 0, MSG_BAD_FIRMWARE, HWVers);
+
+ TRACE(1,("Version of the IN-2000 SPROM at I/O address %x is %02x. Please"
+ " call Always\nfor upgrade instructions. Board is being "
+ "ignored.\n\n", INBase, HWVers));
+ continue;
+
+ }
+
+ if (Switch & 0x04)
+ HA->IRQNumber = IRQList[(Switch >> 3) & 0x3];
+ else {
+
+ LogMessage(HA, NILL, 0, 0, MSG_NO_INT_ENABLE, BaseList[*Context]);
+ TRACE(1,("IN-2000 at I/O %xh must have its interrupts enabled."
+ " Board is being ignored.\n\n", INBase));
+ continue;
+
+ }
+
+ HA->IOBase = INBase;
+ HA->IOBaseAddr = BaseList[*Context];
+ HA->IOAddrLen = 15;
+ HA->SCSI_ID = 7;
+ HA->Service = IN2000_Service;
+ HA->ISR = IN2000_ISR;
+ HA->Name = "IN-2000";
+
+#if defined(WINNT)
+ // Test the DOS 5/Sync. switch (8); On, supports DOS 5 & synchronous
+ HA->Supports.Synchronous = ((Switch & 0x20) == 0); // Support sync. if switch 8 is on
+#else
+ HA->Supports.Synchronous = GlobalAllowSync; // Support sync. if switch 8 is on
+#endif
+
+ HA->Supports.Identify = TRUE;
+ HA->Physical.BusType = BT_ISA;
+
+ (*Context)++; // Found one, so inc. for next entry
+ return 1;
+
+ }
+ return 0;
+}
+
+
+void
+SetUpXfer (ADAPTER_PTR HA, IO_REQ_PTR Req, unsigned Dir)
+{
+ unsigned i;
+
+ HA->Ext->AD.IN2000U.CBuff = (char FAR *)&(((char FAR *)(ReqDataPtr(Req)))[(unsigned)(HA->ReqCurrentIndex)]);
+ HA->Ext->AD.IN2000U.CRemain = HA->ReqCurrentCount;
+ HA->Ext->AD.IN2000U.CurrDir = (Dir == SCSIIn) ? IN2000DataIn : IN2000DataOut;
+ TRACE(5,("SetUpXfer(): %ld (0x%lx) bytes to transfered to/from 0x%08lx\n", HA->Ext->AD.IN2000U.CRemain, HA->Ext->AD.IN2000U.CRemain, HA->Ext->AD.IN2000U.CBuff));
+ outb(HA->Ext->AD.IN2000U.IOMap[INFIFOResetOff], 1); /* Reset the FIFO */
+
+ if (HA->ReqCurrentCount >= FIFOThresh) {
+
+ TRACE(5,("SetUpXfer(): Setting up for FIFO xfer\n"));
+ if (Dir == SCSIIn) {
+
+ TRACE(5,("SetUpXfer(): Setting FIFO direction to read\n"));
+ outb(HA->Ext->AD.IN2000U.IOMap[INDirOff], 1); /* set read mode */
+ HA->Ext->AD.IN2000U.CurrIntMask =
+ (HA->Ext->AD.IN2000U.CRemain >= (FIFOSize-FIFOFillOffset)) ? 0 : INFIFOMask;
+
+ }
+
+ i = (ReadWDReg(HA, WDControlReg) & ~DMAModeMask) | DMABus;
+ do {
+ WriteWDReg(HA, WDControlReg, i);
+ } while (i != ReadWDReg(HA, WDControlReg));
+
+ if (Dir != SCSIIn) { // Doing DATA OUT
+
+ /* The IN-2000 FIFO mechinism requires pre-loading on write
+ operations. At least 32 bytes must be pre-loaded, or else
+ data loss may occur. Upon transfering the final bytes to the
+ FIFO, it must be padded by writing 32 bytes of junk, to move
+ the valid data up from the first 32 byte "twilight-zone". This
+ will be done in the FIFO fill routine.
+ */
+
+ i = (unsigned)min(HA->ReqCurrentCount, (U32)MaxPreFill); // Don't overfill FIFO
+
+ TRACE(5,("SetUpXfer(): Preloading %d bytes for write.\n", i));
+ repoutsw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16 FAR *)HA->Ext->AD.IN2000U.CBuff, (i+1)/2); // Pre-fill FIFO
+ HA->Ext->AD.IN2000U.CBuff += i; // Offset buffer ptr by amount written
+ HA->Ext->AD.IN2000U.CRemain -= i; // Decrement remaining count
+
+ if (HA->Ext->AD.IN2000U.CRemain) // is there more stuff after this?
+ HA->Ext->AD.IN2000U.CurrIntMask = 0; // Then don't mask FIFO ints
+ else { // If not, send pad characters
+
+ TRACE(5, ("SetupXfer(): Padding FIFO\n"));
+ for (i=(FIFOPad / 2); i; i--)
+ outw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16)i);
+ HA->Ext->AD.IN2000U.CurrIntMask = INFIFOMask; // Block FIFO ints
+
+ }
+
+ }
+
+ } else {
+
+ TRACE(5, ("SetupXfer(): Using byte I/O\n"));
+ i = (ReadWDReg(HA, WDControlReg) & ~DMAModeMask) | DMAPIO;
+ do {
+ WriteWDReg(HA, WDControlReg, i);
+ } while (i != ReadWDReg(HA, WDControlReg));
+
+ }
+
+ TRACE(5,("SetUpXfer(): SetUpXfer complete\n"));
+
+}
+
+
+U8 REGPARMS
+FIFOStat (const IOHandle Port)
+{
+#ifdef ASMIO
+
+ asm {
+ mov dx, word ptr Port
+ in al, dx
+ }
+InAgain:
+ asm {
+ mov ah, al
+ in al, dx
+ sub ah, al
+ jnz InAgain
+ }
+ return _AX; /* AH is already zeroed for unsigned promotion */
+#else
+
+ int i;
+ U8 Stat1, Stat2;
+
+ Stat2 = inb(Port) & StatMask;
+ do {
+
+ Stat1 = Stat2;
+
+ for (i=3; i; i--)
+ Stat2 &= inb(Port); // Find which bits are stable for 4 reads
+
+ Stat2 &= StatMask; // Most sig. two bits, and int bit are interesting
+
+ } while (Stat1 != Stat2);
+
+ return Stat1;
+#endif
+}
+
+
+void
+EmptyFIFO (ADAPTER_PTR HA)
+{
+ union {
+ U32 l;
+ unsigned char b[4];
+ } Count;
+ unsigned InFIFO, i;
+
+/*
+ Update the pointers; First get the number of bytes
+ the SCSI chip thinks remain to be transfered. Then compare
+ to the number of bytes the HA structure says remain. The
+ differance is the number of bytes in the FIFO.
+
+ In the case of read data, we need to read the bytes out of
+ the FIFO. The number of bytes in the FIFO is the number
+ of bytes the structure says we've read, minus what the SCSI
+ chip has sent to the FIFO. The buffer pointer is then
+ incremented, and the remaining count is decremented by that
+ amount.
+
+ For write data, the number of bytes in the FIFO is the amount
+ the SCSI chip has yet to write, minus what the driver has yet
+ to send to the FIFO. The data in the FIFO is dropped, the
+ buffer pointer is set back, and the remaining count is
+ incremented.
+*/
+
+ if ((HA->Ext->AD.IN2000U.CurrDir == IN2000DataIn) && (HA->Ext->AD.IN2000U.CRemain == 0)) {
+
+ HA->ReqCurrentIndex += HA->ReqCurrentCount;
+ HA->ReqCurrentCount = 0;
+
+ } else {
+
+#if defined(NATIVE32)
+
+ Count.l = (U32)ReadWDReg(HA, WDCountReg);
+ Count.l = (Count.l * 256) + (U32)ReadWDData(HA);
+ Count.l = (Count.l * 256) + (U32)ReadWDData(HA);
+
+#else
+
+ Count.b[3] = 0;
+ Count.b[2] = ReadWDReg(HA, WDCountReg);
+ Count.b[1] = ReadWDData(HA);
+ Count.b[0] = ReadWDData(HA);
+
+#endif
+
+ TRACE(4,("EmptyFIFO(): Value of Xfer count registers: 0x%08lx\n", Count.l));
+
+ if (HA->Ext->AD.IN2000U.CurrDir == IN2000DataIn) {
+
+ // Get number we have untransfered, minus what the chip has left untransfered
+ // to give the number held in the FIFO:
+ InFIFO = (unsigned)(HA->Ext->AD.IN2000U.CRemain - Count.l);
+
+ TRACE(4,("EmptyFIFO(): CRemain=0x%08lx, in FIFO to read: %04x\n", HA->Ext->AD.IN2000U.CRemain, InFIFO));
+
+ if (InFIFO > 0) {
+
+ TRACE(5, ("EmptyFIFO(): final read %d bytes\n", InFIFO));
+ repinsw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16 FAR *)HA->Ext->AD.IN2000U.CBuff, (InFIFO+1)/2);
+
+ }
+ }
+
+ // When the transfer was set up, the count registers where loaded with
+ // ReqCurrCount(); now the counters reflect the number of bytes untransfered
+ // Increment the index by (StartBytesToXfer - RemainBytesToXfer); and save
+ // away the new remaining count:
+ HA->ReqCurrentIndex += HA->ReqCurrentCount - Count.l;
+ HA->ReqCurrentCount = Count.l;
+ TRACE(4,("EmptyFIFO(): New remaining count: %ld(dec)\n", HA->ReqCurrentCount));
+
+ }
+
+ TRACE(5,("EmptyFIFO(): Reseting xfer mode.\n"));
+ HA->Ext->AD.IN2000U.CurrIntMask |= INFIFOMask; /* Block the FIFO ints */
+ outb(HA->Ext->AD.IN2000U.IOMap[INFIFOResetOff], 1); /* Reset the FIFO */
+
+ i = (ReadWDReg(HA, WDControlReg) & 0x1f);
+ do { /* Clear WD Bus mode */
+ WriteWDReg(HA, WDControlReg, i);
+ } while (ReadWDReg(HA, WDControlReg) != i);
+
+ HA->Ext->AD.IN2000U.CurrDir = IN2000NoData;
+ HA->Ext->AD.IN2000U.CRemain = 0;
+
+}
+
+
+void
+FIFO_ISR (ADAPTER_PTR HA)
+{
+ unsigned S;
+
+#if defined(KEEP_STATS)
+ HA->DataInterrupts++;
+#endif
+
+ // Stay in here as long as there is no 33C93 interrupt (bit 0), and there is
+ // at least 512 bytes in the FIFO (0xc0), and there is data remaining.
+ // FIFOStat is called to repeatedly read the FIFO status port, since it
+ // may be unstable for a single read.
+
+ while (!((S = FIFOStat(HA->Ext->AD.IN2000U.IOMap[INFIFOOff])) & 1)
+ && (S & 0xc0) && HA->Ext->AD.IN2000U.CRemain) {
+
+ TRACE(5, ("IN2000_ISR(): FIFO status port read as %x\n", S));
+
+ // Value read from port (bits 1-7) is number of bytes / 16; Bit one is the
+ // WD interrupt pending bit; so the count is effectively already multiplied
+ // by two. Multiply it again by 8 to get the number of bytes in FIFO
+// S = (S & 0xc0) * 8;
+ S = 512;
+
+ if (HA->Ext->AD.IN2000U.CurrDir == IN2000DataIn) {
+
+// if ((U32)S > HA->Ext->AD.IN2000U.CRemain) {
+//
+// TRACE(0, ("FIFO_ISR(): FIFO says %ld, expected remaining is %ld\n", S, HA->Ext->AD.IN2000U.CRemain));
+// S = (unsigned)HA->Ext->AD.IN2000U.CRemain;
+//
+// }
+ S = (unsigned)min(S, HA->Ext->AD.IN2000U.CRemain);
+ TRACE(4, ("FIFO_ISR(): reading %d bytes to %lx\n", S, HA->Ext->AD.IN2000U.CBuff));
+
+#if !defined(ASMIO)
+
+ repinsw(HA->Ext->AD.IN2000U.IOMap[INDataOff], HA->Ext->AD.IN2000U.CBuff, S/2);
+
+#else /* ASMIO */
+
+#if sizeof(HA) == 4 /* far HA ptr */
+ asm {
+ mov ax, di
+ les bx, HA
+ mov dx, es:[bx].IOBase
+ les di, es:[bx].AD.IN2000U.CBuff
+ }
+#else /* near HA ptr */
+ asm {
+ mov ax, di
+ mov bx, HA
+ mov dx, [bx].IOBase
+ les di, [bx].AD.IN2000U.CBuff
+ }
+#endif
+ asm {
+ add dx, INDataOff
+ mov cx, S
+ shr cx, 1
+ cld
+ rep insw
+ mov di, ax
+ }
+
+#endif /* ASMIO */
+
+ } else {
+
+ // Leave 16 bytes (FIFOFillOffset) in FIFO for write flush (see below):
+ S = (unsigned)min(min(S - FIFOFillOffset, FIFOSize/2), HA->Ext->AD.IN2000U.CRemain);
+
+ TRACE(5, ("FIFO_ISR(): Writing next %d chunk from %lx\n", S, HA->Ext->AD.IN2000U.CBuff));
+ repoutsw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16 FAR *)HA->Ext->AD.IN2000U.CBuff, S/2);
+
+ }
+
+ HA->Ext->AD.IN2000U.CBuff += S;
+ HA->Ext->AD.IN2000U.CRemain -= S;
+ TRACE(5, ("FIFO_ISR(): New remaining is %ld (0x%lx)\n", HA->Ext->AD.IN2000U.CRemain, HA->Ext->AD.IN2000U.CRemain));
+// if (HA->Ext->AD.IN2000U.CRemain)
+// for(S=16; S && ((inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]) & 0xc1) == 0); S--) ;
+ }
+
+ /* The FIFO logic on the IN-2000 requires writing FIFOPad bytes of garbage
+ into the FIFO to push the end of the valid data out. This flush
+ occurs here:
+ */
+
+ if (HA->Ext->AD.IN2000U.CRemain == 0) { /* Don't expect any more FIFO ints */
+
+ HA->Ext->AD.IN2000U.CurrIntMask |= INFIFOMask; /* Block the FIFO ints */
+ if (HA->Ext->AD.IN2000U.CurrDir == IN2000DataOut) { // Pad the FIFO
+
+ for (S=(FIFOPad / 2); S; S--)
+ outw(HA->Ext->AD.IN2000U.IOMap[INDataOff], (U16)S);
+
+ }
+ }
+}
+
+
+int
+IN2000_ISR (ADAPTER_PTR HA)
+{
+ unsigned char Stat, Taken = 0;
+
+ TRACE(5, ("IN2000_ISR(): \n"));
+ outb(HA->Ext->AD.IN2000U.IOMap[INIntMaskOff], INFIFOMask | INSBICMask);
+
+ HA->Ext->AD.IN2000U.LastPollHadIntPending = FALSE;
+
+ while (((Stat = inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff])) & 1)
+ || ((Stat & 0xc0) && (HA->Ext->AD.IN2000U.CRemain != 0))) {
+
+ Taken = 1;
+ TRACE(5, ("IN2000_ISR(): FIFOStatus is : %x\n", Stat));
+ if ( !(Stat & 1) )
+ FIFO_ISR(HA);
+
+ while(inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]) & 0x1)
+ WD33c93_ISR(HA);
+
+ }
+
+ outb(HA->Ext->AD.IN2000U.IOMap[INIntMaskOff], HA->Ext->AD.IN2000U.CurrIntMask);
+ return Taken;
+}
+
+
+void
+IN2000_Initiate (ADAPTER_PTR HA, IO_REQ_PTR Req, const int StartLevel)
+{
+#if defined(COMPOUND_CMD)
+ unsigned char C;
+#endif
+
+ TRACE(5, ("IN2000_Initiate(): initiating\n"));
+
+ critical(HA); // Block interrupts for now
+
+ HA->ReqCurrentCount = 0; // Next DXFER phase will cause a GetXferSegment()
+ HA->ReqCurrentIndex = 0;
+
+ HA->Ext->SBIC.WD33C93.State = WD_NO_STATE; // Currently not in any state
+
+ WriteWDReg(HA, WDDestIDReg, ReqTargetID(Req)); // Set the ID of the target
+
+ HA->State.Busy = 1; // Mark flag for adapter in use
+
+ if (HA->DevInfo[ReqTargetID(Req)].Flags.UseSync) { // Do we use sync. xfers on this device?
+
+ WriteWDReg(HA, WDSyncReg, HA->DevInfo[ReqTargetID(Req)].HASync1); // Then write the Sync. values
+
+ } else {
+
+ WriteWDReg(HA, WDSyncReg, HA->Ext->SBIC.WD33C93.AsyncValue); // Alright then, async. values
+
+ }
+
+ // enable reselection
+ WriteWDReg(HA, WDSourceReg, EnableRSel);
+
+ SCSIMakeIdentify(HA, ReqTargetLUN(Req), (BOOLEAN)(ReqAllowDisconnect(Req) && HA->CurrDev->Flags.Allow_Disc)); // Then build Identify with disconnect
+
+#if defined(COMPOUND_CMD)
+
+ // WD Compound commands only know group 0, 1, & 5 CDBs:
+ C = ReqCDB(Req)[0] & 0xe0;
+ if ((HA->Ext->MO_Count > 1) || !(C <= 0x10 || C == 0x50)) {
+
+ WriteWDReg(HA, WDCMDReg, WDSelATNCmd); // Select with attention
+ TRACE(3, ("IN2000_Initiate(): Using discreet commands\n"));
+
+ } else {
+
+ TRACE(3, ("IN2000_Initiate(): Using compound commands\n"));
+
+ WriteWDReg(HA, WDControlReg, EnableIDI);
+ WriteWDReg(HA, WDTarLUNReg, ReqTargetLUN(Req) | ((BOOLEAN)(ReqAllowDisconnect(Req) && HA->CurrDev->Flags.Allow_Disc)) ? 0x40 : 0); // Set ID of target LUN
+
+ if ((HA->ReqCurrentCount >= FIFOThresh) && (ReqDataIn(Req) || ReqDataOut(Req))) {
+
+ TRACE(4, ("IN2000_Initiate(): Early prepare for data xfer; Preparing for %ld byte xfer\n", HA->ReqCurrentCount));
+ HA->State.DataXfer = 1;
+ HA->Ext->SBIC.WD33C93.State |= WD_BLOCK_XFER;
+
+ HA->Ext->AD.IN2000U.CurrIntMask = 0;
+ SetUpXfer(HA, HA->CurrReq, ReqDataIn(Req));
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((char FAR *)&ReqCurrCount(HA->CurrReq))[2]));
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((char FAR *)&ReqCurrCount(HA->CurrReq))[1]));
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, (((char FAR *)&ReqCurrCount(HA->CurrReq))[0]));
+
+ } else {
+
+ HA->Ext->AD.IN2000U.CurrIntMask = INFIFOMask;
+ outb(HA->Ext->SBIC.WD33C93.WDSelPort, WDCountReg);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, 0);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, 0);
+ outb(HA->Ext->SBIC.WD33C93.WDDataPort, 0);
+
+ }
+
+ if (StartLevel <= 1)
+ outb(HA->Ext->AD.IN2000U.IOMap[INIntMaskOff], HA->Ext->AD.IN2000U.CurrIntMask);
+
+ SetWDReg(HA, WDCDBReg); // Send the CDB
+ repoutsb(WDData, ReqCDB(Req), ReqCDBLen(Req));
+ HA->Ext->SBIC.WD33C93.State |= WD_COMPOUND_CMD; // Flag the use of LEVEL II commands
+
+ WriteWDReg(HA, WDCMDReg, WDSelATNXCmd); // Start select & xfer w/ attention
+
+ }
+
+#else
+
+ WriteWDReg(HA, WDCMDReg, WDSelATNCmd); // Select with attention
+
+#endif
+
+ HA->ReqStarting = StartLevel;
+ inb(HA->Ext->AD.IN2000U.IOMap[INLEDOnOff]); // Turn on LED
+ uncritical(HA); // OK, allow ints again
+
+ TRACE(5, ("IN2000_Initiate(): initiating complete\n"));
+
+}
+
+
+U32
+IN2000_Service (int Func, ADAPTER_PTR HA, U32 Misc)
+{
+ int j;
+
+ switch (Func) {
+
+ case HA_INITIALIZE:
+
+ return IN2000Init(HA);
+ break;
+
+
+ case HA_START:
+
+ TRACE(2, ("IN2000_Service(): Got HA_START command\n"));
+ HA->State.Allow = 1;
+ StartNext(HA, 1);
+ break;
+
+
+ case HA_STOP:
+
+ TRACE(2, ("IN2000_Service(): Got HA_STOP command\n"));
+ HA->State.Allow = 0;
+ break;
+
+
+ case HA_TICKLE:
+
+ if (!(HA->State.Busy) && (HA->State.Allow)) {
+
+ TRACE(5, ("IN2000_Service(): Tickling adapter\n"));
+ StartNext(HA,1);
+
+ } else {
+
+ TRACE(5, ("IN2000_Service(): Tickle ignored; Busy = %d, Allow = %d\n", HA->State.Busy, HA->State.Allow));
+
+ }
+
+ break;
+
+
+ case HA_TIMER:
+
+ j = inb(HA->Ext->AD.IN2000U.IOMap[INFIFOOff]) & StatMask;
+ if (HA->Ext->AD.IN2000U.LastPollHadIntPending && j ) {
+
+ if (IN2000_ISR(HA)) {
+
+ LogMessage(HA, HA->CurrReq, 0, 0, MSG_NO_INTERRUPTS, __LINE__);
+ TRACE(0, ("IN2000_Service(): Serviced interrupt on timer\n"));
+
+ }
+
+ } else
+ HA->Ext->AD.IN2000U.LastPollHadIntPending = j;
+ break;
+
+
+ case HA_LED:
+
+ if ((int)Misc) inb(HA->Ext->AD.IN2000U.IOMap[INLEDOnOff]);
+ else inb(HA->Ext->AD.IN2000U.IOMap[INLEDOffOff]);
+ break;
+
+
+ case HA_INITIATE:
+
+ IN2000_Initiate(HA, HA->CurrReq, (unsigned)Misc);
+ break;
+
+
+ case HA_DATA_SETUP:
+
+ SetUpXfer(HA, HA->CurrReq, (unsigned)Misc);
+ if (HA->ReqCurrentCount < FIFOThresh)
+ return HAServiceResponse_UseByteIO;
+ else
+ return HA->Ext->AD.IN2000U.CRemain;
+// break;
+
+
+ case HA_DATA_CMPLT:
+
+ if (HA->Ext->AD.IN2000U.CurrDir != IN2000NoData)
+ EmptyFIFO(HA);
+ break;
+
+ case HA_RESET_BUS:
+
+ IN2000ResetBus(HA);
+ break;
+
+
+ case HA_REVERT_STATE:
+
+ // Restore the board back to its preveous state. This is used by
+ // Netware / Chicago to switch back to BIOS mode.
+ WriteWDReg(HA, WDOwnIDReg, ((StateBuffer *)(HA->Ext->InitialState))->OwnID);
+
+ critical(HA);
+
+ // Reset chip, then wait for reset complete interrupt. This causes the chip
+ // to accept the set ID.
+ WriteWDReg(HA, WDCMDReg, WDResetCmd);
+
+ while ((ReadWDReg(HA, WDAuxStatReg) & IntPending) == 0)
+ ;
+ ReadWDReg(HA, WDStatusReg); // Clear the interrupt
+
+ uncritical(HA);
+
+ WriteWDReg(HA, WDControlReg, ((StateBuffer *)(HA->Ext->InitialState))->CtrlReg);
+ WriteWDReg(HA, WDTimeoutReg, ((StateBuffer *)(HA->Ext->InitialState))->TimeOutReg);
+ WriteWDReg(HA, WDSourceReg, ((StateBuffer *)(HA->Ext->InitialState))->SourceReg);
+ break;
+
+
+ case HA_RESTORE_STATE:
+
+ IN2000ReInit(HA);
+ IN2000ResetBus(HA);
+ break;
+
+
+ case HA_POWER_MODE:
+
+
+ break;
+
+ }
+
+ return 0;
+}
diff --git a/private/ntos/miniport/always/in2000.h b/private/ntos/miniport/always/in2000.h
new file mode 100644
index 000000000..9d8a03900
--- /dev/null
+++ b/private/ntos/miniport/always/in2000.h
@@ -0,0 +1,31 @@
+/* in2000.h -- Port definitions for IN-2000 */
+#ifndef __IN2000_H__
+#define __IN2000_H__
+
+/* Minimum hardware (Xilinx SProm) version supported: */
+#define MinHWVers 0x27
+
+/* Offsets for IN-2000 I/O ports: */
+#define INAuxOff 0 /* WD Aux stat/Register select */
+#define INWDSelOff 0 /* WD register select offset */
+#define INWDDataOff 1 /* 8 bit R/W WD data port */
+#define INDataOff 2 /* 16-bit R/W data port */
+#define INResetOff 3 /* Write sets WD & SCSI bus reset; clear
+ by reading hardware revision */
+#define INFIFOOff 4 /* FIFO byte count/ Int. status:
+ upper 7 bit = # of 16 byte pieces ready
+ in FIFO
+ bit 0 = interrupt status (FIFO | WD) */
+#define INFIFOResetOff 5 /* Resets FIFO count and direction */
+#define INDirOff 7 /* Write sets data direction to read */
+#define INLEDOffOff 8 /* Turn LED off */
+#define INSwitchOff 8 /* Read IN2000 switch positions 2-9 */
+#define INLEDOnOff 9 /* Turn LED on */
+#define INHWRevOff 0xa /* Get IN Xilinx version number; clears
+ reset from write to port +3 */
+#define INIntMaskOff 0xc /* Set masks below to block ints */
+#define INSBICMask 1 /* Mask off 33c93 ints */
+#define INFIFOMask 2 /* mask off FIFO ints */
+
+
+#endif __IN2000_H__
diff --git a/private/ntos/miniport/always/in2000s.h b/private/ntos/miniport/always/in2000s.h
new file mode 100644
index 000000000..6a9eeb1fa
--- /dev/null
+++ b/private/ntos/miniport/always/in2000s.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#ifndef __IN2000S_H__
+#define __IN2000S_H__
+
+typedef enum {IN2000NoData, IN2000DataIn, IN2000DataOut} IN2000DataDirection;
+
+/* Structure for Adapter union in scsi.h */
+struct IN2000S {
+
+ char FAR *CBuff;
+ U32 CRemain;
+ int LastPollHadIntPending;
+ IOHandle IOMap[16];
+ IN2000DataDirection CurrDir;
+ char CurrIntMask;
+ char InISR;
+
+};
+
+#define SCSI_8
+
+#include<33c93s.h>
+
+#endif /* __IN2000S_H__ */
diff --git a/private/ntos/miniport/always/intrlreq.c b/private/ntos/miniport/always/intrlreq.c
new file mode 100644
index 000000000..71753aa22
--- /dev/null
+++ b/private/ntos/miniport/always/intrlreq.c
@@ -0,0 +1,359 @@
+/* Copyright (C) 1994 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#include "environ.h"
+#include "rqm.h"
+#include "api.h"
+#include "apiscsi.h"
+#include "debug.h"
+
+
+LOCAL void REGPARMS StartNextInternalRequest(ADAPTER_PTR HA);
+LOCAL void REGPARMS DeviceInfo(const ADAPTER_PTR HA);
+LOCAL void REGPARMS AutoSense(ADAPTER_PTR HA);
+LOCAL void REGPARMS CompleteDeferedRequest(ADAPTER_PTR HA, APIStatus Status);
+LOCAL void REGPARMS ExecuteDeferedRequest(ADAPTER_PTR HA);
+LOCAL void DoTestUnitReadyComplete(IO_REQ_PTR IReq);
+LOCAL void REGPARMS DoTestUnitReady(ADAPTER_PTR HA);
+
+
+#if !defined(LocalPostCallback)
+extern U32 LocalPostCallback(void (*CallBack)(IO_REQ_PTR));
+#endif
+
+enum ASPI_Priority {NORMAL_REQ, PRIORTY_REQ, IPRIORTY_REQ};
+extern void IExecuteReq(ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req,
+ enum ASPI_Priorty Priorty);
+
+void
+QueueInternalRequest (ADAPTER_PTR HA, IO_REQ_PTR XReq, RequestType Type)
+{
+ IO_REQ_PTR *ReqScan = &(HA->Ext->InternalReqDeferQueue);
+
+ critical(HA);
+ ReqState(XReq).ReqType = Type;
+ while(*ReqScan != (IO_REQ_PTR)NILL)
+ ReqScan = &ReqNext(*ReqScan);
+
+ *ReqScan = XReq;
+ uncritical(HA);
+
+ StartNextInternalRequest(HA);
+}
+
+
+LOCAL void REGPARMS
+StartNextInternalRequest (ADAPTER_PTR HA)
+{
+ IO_REQ_PTR IReq = &HA->Ext->InternalRequest;
+ IO_REQ_PTR XReq;
+ int i;
+
+ TRACE(2, ("StartNextInternalRequest(): InUse flag == %s\n",
+ (HA->State.InternalReqInUse) ? "True" : "False"));
+
+ critical(HA);
+ while (!HA->State.InternalReqInUse
+ && HA->Ext->InternalReqDeferQueue != (IO_REQ_PTR)NILL) {
+
+ HA->State.InternalReqInUse = TRUE;
+ XReq = HA->Ext->InternalReqDeferQueue;
+
+ uncritical(HA);
+
+ ReqTargetID(IReq) = ReqTargetID(XReq);
+ ReqTargetLUN(IReq) = ReqTargetLUN(XReq);
+ ReqDevP(IReq) = ReqDevP(XReq);
+
+ for (i=0; i<12;i++)
+ ReqCDB(IReq)[i] = 0;
+
+ ReqState(IReq).ReqType = ReqState(XReq).ReqType;
+ switch(ReqState(XReq).ReqType) {
+
+ case RTGetInfoReq:
+
+ DeviceInfo(HA);
+ break;
+
+
+ case RTAutoSenseReq:
+
+ AutoSense(HA);
+ break;
+
+
+ case RTSyncNegReq:
+
+ DoTestUnitReady(HA);
+ break;
+
+
+ default:
+ CompleteDeferedRequest(HA, S_REQ_REQUEST);
+ continue;
+
+ }
+
+ critical(HA);
+ }
+ uncritical(HA);
+
+}
+
+
+
+
+void AutoSenseReqComplete(IO_REQ_PTR Req);
+
+LOCAL void REGPARMS
+AutoSense (ADAPTER_PTR HA)
+{
+ IO_REQ_PTR IReq = &HA->Ext->InternalRequest;
+ IO_REQ_PTR XReq = HA->Ext->InternalReqDeferQueue;
+
+ TRACE(4, ("AutoSense(): Starting auto sense for request %lx\n", XReq));
+
+ ReqCDBLen(IReq) = 6;
+ ReqSenseCount(IReq) = 0;
+ ReqDataCount(IReq) = ReqSenseCount(XReq);
+ ReqDataPtr(IReq) = ReqSensePtr(XReq);
+ TRACE(4, ("AutoSense(): Sense data pointer = %lx, sense count = %d\n",
+ ReqSensePtr(XReq), ReqSenseCount(XReq)));
+
+ ReqSetDataInFlags(IReq);
+
+ // First do a request sense to clear the reset, etc conditions:
+ ReqCDB(IReq)[0] = 0x03; // Request Sense is command 0x03
+ ReqCDB(IReq)[4] = min(255, ReqSenseCount(XReq));
+ ReqPost(IReq) = LocalPostCallback(AutoSenseReqComplete);
+
+ TRACE(3, ("AutoSense(): request built, calling IExecuteReq()\n"));
+ QueueReq(HA, IReq, TRUE);
+
+}
+
+
+
+LOCAL void
+AutoSenseReqComplete (IO_REQ_PTR Req)
+{
+ IO_REQ_PTR XReq = ReqAdapterPtr(Req)->Ext->InternalReqDeferQueue;
+
+ TRACE(3, ("AutoSenseReqComplete(): Completion of autosense for request %lx ", XReq));
+ TRACE(3, ("cmd = %02x\n", ReqCommand(XReq)));
+ DmsPause(7, 200);
+
+ FreeMemHandle(Req->ReqDataPtr);
+
+ TRACE(3, ("AutoSenseReqComplete(): Completion of auto sense\n"));
+ DmsPause(7, 100);
+ CompleteDeferedRequest(ReqAdapterPtr(Req),
+ (APIStatus)((ReqAPIStatus(Req) == S_TAR_NOERROR) ? S_AD_AUTOSENSE_OK : S_AD_AUTOSENSE_FAIL));
+
+}
+
+
+
+// The request completed
+LOCAL void
+DevInfoDone (ADAPTER_PTR HA, APIStatus Status)
+{
+ if (Status == S_TAR_NOERROR)
+ ExecuteDeferedRequest(HA); // Queue up request
+ else
+ CompleteDeferedRequest(HA, Status);
+
+}
+
+
+
+// This is the POST routine called when the second step (Inquiry) of the device info completes
+// This completes this devices inquiry. Start the next DevInfoReq for this adapter.
+LOCAL void
+DevInfoInqDone (IO_REQ_PTR Req)
+{
+ DEVICE_PTR DevP = ReqDevP(Req);
+ ADAPTER_PTR HA = ReqAdapterPtr(Req);
+
+ TRACE(4, ("DevInfoInqDone(): Status of Inquiry: %04x\n", ReqAPIStatus(Req)));
+ if (ReqAPIStatus(Req) == S_TAR_NOERROR) {
+
+ TRACE(4, ("DevInfoInqDone(): Inquiry completed without error\n"));
+ if (HA->Ext->InternalReqBuffer[0] == 0x7f) { // Check for LUN not present
+
+ TRACE(2, ("DeviceInfo(): LUN not present\n"));
+ DevInfoDone(HA, S_REQ_NOTAR);
+ return;
+
+ }
+
+ DevP->Device_Type = HA->Ext->InternalReqBuffer[0]; // Get device type
+ TRACE(2, ("DevInfoInqDone(): Device type = %02x\n", DevP->Device_Type));
+ TRACE(3, ("DevInfoInqDone(): Device is SCSI-%d, Flags = %02x\n",
+ (HA->Ext->InternalReqBuffer[3] & 0x0f), (unsigned)HA->Ext->InternalReqBuffer[7]));
+
+ if ((HA->Ext->InternalReqBuffer[3] & 0x0f) > 1) { // Is this dev. SCSI2 or later?
+
+ DevP->Flags.IsSCSI2 = 1; // Set SCSI-2 params valid flag
+ DevP->SCSI2_Flags.Byte = HA->Ext->InternalReqBuffer[7]; // Get the SCSI-2 parameter bytes
+ if (DevP->SCSI_LUN == 0)
+ HA->DevInfo[DevP->SCSI_ID].Flags.NeedSync = (HA->DevInfo[DevP->SCSI_ID].Flags.AllowSync &= DevP->SCSI2_Flags.Bits.Sync); // Use the inquiry info on Sync xfer
+
+ } else { // All right; we'll do thigns the SCSI-1 way
+
+ DevP->SCSI2_Flags.Byte = 0; // Clear all SCSI-2 mode bits
+ HA->DevInfo[DevP->SCSI_ID].Flags.NeedSync =
+ HA->DevInfo[DevP->SCSI_ID].Flags.AllowSync;
+ TRACE(2, ("DevInfoInqDone(): Setting NEED_SYNC flag to %d\n",
+ HA->DevInfo[DevP->SCSI_ID].Flags.NeedSync));
+
+ }
+ DevP->Flags.Allow_Disc = HA->Supports.Identify; // If the adapter supports identify messages, is allows disconnects
+ DevP->Flags.Initialized = 1;
+
+ }
+
+ DevInfoDone(HA, ReqAPIStatus(Req));
+
+}
+
+
+
+// This is the POST routine called when the first step (Request Sense) of the device info completes
+// The next step will be to do the inquiry, initiated here, completed above
+LOCAL void
+DevInfoSenseDone (IO_REQ_PTR Req)
+{
+ ADAPTER_PTR HA = ReqAdapterPtr(Req);
+
+ TRACE(3, ("DevInfoSenseDone(): Status of ReqSense: %02x\n", ReqAPIStatus(Req)));
+ if (ReqAPIStatus(Req) != S_TAR_NOERROR) {
+
+ TRACE(4, ("DevInfoSenseDone(): Completed with error\n"));
+ DevInfoDone(HA, ReqAPIStatus(Req));
+ return;
+
+ }
+
+ // OK, the Request Sense completed OK, now do the inquiry
+ TRACE(3, ("DevInfoSenseDone(): Req. sense completed OK, setting up inquiry\n"));
+ ReqCDB(Req)[0] = (U8)0x12; // Inquiry is command 0x12
+
+ ReqDataCount(Req) = DevInfoInqSize;
+ ReqDataPtr(Req) = HA->Ext->InternalReqBuffer;
+
+ ReqPost(Req) = DevInfoInqDone;
+
+ QueueReq(ReqAdapterPtr(Req), Req, FALSE); // Queue up request
+
+}
+
+
+
+LOCAL void REGPARMS
+DeviceInfo (const ADAPTER_PTR HA)
+{
+ int i;
+ DEVICE_PTR DevP=ReqDevP(HA->Ext->InternalReqDeferQueue);
+ IO_REQ_PTR IReq = &(HA->Ext->InternalRequest);
+
+ TRACE(2, ("DeviceInfo(): for adapter %x\n"));
+
+ for (i = 0; i < sizeof(DevP->Flags); i++)
+ ((char ALLOC_D *)&(DevP->Flags))[i] = 0;
+
+ DevP->SCSI_ID = ReqTargetID(IReq);
+ DevP->SCSI_LUN = ReqTargetLUN(IReq);
+ if (DevP->SCSI_LUN == 0) {
+
+ HA->DevInfo[ReqTargetID(IReq)].Flags.AllowSync = HA->Supports.Synchronous
+ /* && (HA->Parms[DRIVE_PL(ReqTargetID(IReq))] & PL_ALLOW_SYNC) */;
+
+ }
+
+ DevP->HA = HA;
+ DevP->MaxDepth = 1;
+ DevP->CurrDepth = 0;
+ DevP->Device_Type = 0xff;
+
+ DevP->PendingReqList = DevP->AcceptedList = (IO_REQ_PTR)NILL;
+ ReqCDBLen(IReq) = 6;
+ ReqSenseCount(IReq) = 0;
+ ReqDataCount(IReq) = DevInfoInqSize;
+ ReqDataPtr(IReq) = HA->Ext->InternalReqBuffer;
+
+ ReqSetDataInFlags(IReq);
+
+ // First do a request sense to clear the reset, etc conditions:
+ ReqCDB(IReq)[0] = 0x03; // Request Sense is command 0x03
+ ReqCDB(IReq)[4] = (unsigned char)DevInfoInqSize;
+ ReqPost(IReq) = DevInfoSenseDone;
+
+ QueueReq(HA, IReq, FALSE); // Queue up request
+
+}
+
+
+
+
+LOCAL void REGPARMS
+DoTestUnitReady (ADAPTER_PTR HA)
+{
+ IO_REQ_PTR IReq = &HA->Ext->InternalRequest;
+ IO_REQ_PTR XReq = HA->Ext->InternalReqDeferQueue;
+
+ TRACE(4, ("DoTestUnitReady(): Starting Test Unit Ready for request %lx\n", XReq));
+
+ ReqCDBLen(IReq) = 6;
+ ReqSenseCount(IReq) = 0;
+ ReqDataCount(IReq) = 0;
+
+ ReqPost(IReq) = LocalPostCallback(DoTestUnitReadyComplete);
+
+ TRACE(3, ("DoTestUnitReady(): request built, calling IExecuteReq()\n"));
+ QueueReq(HA, IReq, FALSE); // Queue up request
+
+}
+
+
+LOCAL void
+DoTestUnitReadyComplete (IO_REQ_PTR IReq)
+{
+
+ ExecuteDeferedRequest(ReqAdapterPtr(IReq)); // Queue up original request
+
+}
+
+
+LOCAL void REGPARMS
+CompleteDeferedRequest (ADAPTER_PTR HA, APIStatus Status)
+{
+ IO_REQ_PTR XReq = HA->Ext->InternalReqDeferQueue;
+ HA->Ext->InternalReqDeferQueue = ReqNext(XReq);
+
+ TRACE(3, ("CompleteDeferedRequest(): Completing defered request %x on adapter %x\n", XReq, HA));
+ HA->State.InternalReqInUse = FALSE;
+ StartNextInternalRequest(HA);
+ ReqState(XReq).ReqType = RTNormalReq;
+ APISetStatus(XReq, Status, Terminal, NotSenseable);
+
+}
+
+
+
+LOCAL void REGPARMS
+ExecuteDeferedRequest (ADAPTER_PTR HA)
+{
+ IO_REQ_PTR XReq = HA->Ext->InternalReqDeferQueue;
+ HA->Ext->InternalReqDeferQueue = ReqNext(XReq);
+
+ TRACE(3, ("ExecuteDeferedRequest(): Executing defered request %x on adapter %x\n", XReq, HA));
+ HA->State.InternalReqInUse = FALSE;
+ StartNextInternalRequest(HA);
+ ReqState(XReq).ReqType = RTNormalReq;
+ IExecuteReq(HA, ReqDevP(XReq), XReq, NORMAL_REQ); // Queue up request
+
+}
diff --git a/private/ntos/miniport/always/intsrb.h b/private/ntos/miniport/always/intsrb.h
new file mode 100644
index 000000000..5818af4de
--- /dev/null
+++ b/private/ntos/miniport/always/intsrb.h
@@ -0,0 +1,100 @@
+/* Copyright (C) 1991-1993 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+// Microsoft Windows NT SRB internalizations: This module defines the
+// abstractions used throught the SCSI API, mapping to NT's SRB structure.
+
+#if !defined(__intsrb_h__)
+#define __intsrb_h__
+
+// Define the SRB extension; this is an area added to each SRB from the SCSIPort
+// as an adapter scratch area:
+
+struct IOReqExtension {
+
+ U32 SavedIndex; // Value stored by "Save data pointers"
+ struct Adapter *HA;
+ struct _SCSI_REQUEST_BLOCK *NextReq;
+ struct DeviceDescr *DevP;
+ U16 Status;
+ struct {
+
+ unsigned Connected:1;
+ unsigned ReselPending:1;
+ unsigned InternalRequest:1;
+ enum RequestType ReqType:4;
+
+ } State;
+
+};
+typedef struct IOReqExtension *IOReqExtensionPtr;
+
+#include "..\..\inc\scsi.h"
+
+#define AUTOSENSE
+
+typedef SCSI_REQUEST_BLOCK IO_REQ;
+typedef PSCSI_REQUEST_BLOCK IO_REQ_PTR;
+
+// API generic Req->ReqXXX fields:
+// Macro "functions" for getting request info
+
+#define ReqCommand(Req) (Req)->Function
+//#define ReqSGLength(Req) (Req)->SGListLength
+//#define ReqSGPtr(Req) (Req)->DataPtr
+#define ReqDataPtr(Req) (Req)->DataBuffer
+#define ReqIsDataPtrPhys(Req) (FALSE)
+#define ReqDataCount(Req) (Req)->DataTransferLength
+#define ReqSensePtr(Req) (Req)->SenseInfoBuffer
+#define ReqSenseCount(Req) (Req)->SenseInfoBufferLength
+
+#define ReqCDB(Req) (Req)->Cdb
+#define ReqCDBLen(Req) (Req)->CdbLength
+
+#define ReqTargetID(Req) (Req)->TargetId
+#define ReqTargetLUN(Req) (Req)->Lun
+//#define ReqQID(Req) (Req)->QueueTag
+#define ReqFlags(Req) ((Req)->SrbFlags)
+
+#define ReqExtensionPtr(Req) (((IOReqExtensionPtr)(Req)->SrbExtension)) // Used as flag for allocating extensions for internal IO_REQs
+#define ReqSavedIndex(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->SavedIndex
+#define ReqState(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->State
+#define ReqAPIStatus(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->Status
+#define ReqDevP(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->DevP
+#define ReqNext(Req) (((IOReqExtensionPtr)(Req)->SrbExtension))->NextReq
+#define ReqAdapterPtr(Req) ((ADAPTER_PTR)((((IOReqExtensionPtr)(Req)->SrbExtension)))->HA)
+
+// This entry is used only for internal requests
+typedef void (*PFV_R)(IO_REQ_PTR);
+#define ReqPost(Req) ((PFV_R)(Req)->OriginalRequest)
+
+#define ReqQueueAction(Req) (((Req)->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ? (Req)->QueueAction : 0)
+#define ReqAllowAutoSense(Req) !((Req)->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)
+#define ReqAllowDisconnect(Req) !((Req)->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+#define ReqAllowCache(Req) ((Req)->SrbFlags & SRB_FLAGS_ENABLE_ADAPTER_CACHE))
+
+#define ReqDataIn(Req) ((Req)->SrbFlags & SRB_FLAGS_DATA_IN)
+#define ReqSetDataInFlags(Req) (Req)->SrbFlags |= SRB_FLAGS_DATA_IN
+#define ReqDataOut(Req) ((Req)->SrbFlags & SRB_FLAGS_DATA_OUT)
+#define ReqSetDataOutFlags(Req) (Req)->SrbFlags |= SRB_FLAGS_DATA_OUT
+#define ReqNoData(Req) (((Req)->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) == 0)
+#define ReqSetNoDataFlags(Req) (Req)->SrbFlags &= ~(SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)
+
+
+// API functions:
+#define APIFindDev(HA, TID, LUN) ((DEVICE_PTR)(ScsiPortGetLogicalUnit(HA, 0, (char)(TID), (char)(LUN))))
+
+
+typedef struct SG_LIST FAR *SGListPtr;
+typedef struct SG_LIST SGList;
+
+struct SG_LIST {
+
+ U32 Addr;
+ U32 Count;
+
+};
+
+
+#endif
diff --git a/private/ntos/miniport/always/makefile b/private/ntos/miniport/always/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/always/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/always/ntenv.c b/private/ntos/miniport/always/ntenv.c
new file mode 100644
index 000000000..0a4eb402e
--- /dev/null
+++ b/private/ntos/miniport/always/ntenv.c
@@ -0,0 +1,80 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+
+*/
+
+#include "environ.h"
+#include "rqm.h"
+#include "api.h"
+#include "apiscsi.h"
+#include "debug.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#if defined(DEBUG_ON)
+int DEBUG_TOKEN=0;
+#endif
+
+
+void
+PanicMsg (char *Message)
+{
+
+ TRACE(0,Message);
+ BreakPoint(HA);
+
+}
+
+
+
+U32
+MapToPhysical (void ALLOC_D *HA, SegmentDescr *Descr)
+{
+ U32 T;
+ U32 Size = Descr->SegmentLength;
+
+ TRACE(5, ("MapToPhysical(): Request to map addr: 0x%x for a length of: %d\n",
+ Descr->SegmentPtr, Size));
+
+ T = (U32)ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(HA, NULL, (PVOID)(Descr->SegmentPtr), &Size));
+ if (Size < Descr->SegmentLength)
+ Descr->SegmentLength = Size;
+
+ Descr->SegmentPtr = T;
+ Descr->Flags.IsPhysical = TRUE;
+
+ TRACE(5, ("MapToPhysical(): Mapped to 0x%lx\n", T));
+
+ return T;
+}
+
+
+
+#if !defined(NO_MALLOC)
+ALLOC_T
+allocm (unsigned Count)
+{
+ // This is a cludge until we do it the right way.
+ // It's too late in the evening to do anything else:
+ static U8 MemoryPool[8192];
+ static int MemPoolIndex=0;
+ ALLOC_T T;
+
+ TRACE(4, ("allocm(): Requesting %d bytes; current pool index at: %d\n",
+ Count, MemPoolIndex));
+ T = (ALLOC_T)&MemoryPool[MemPoolIndex];
+ MemPoolIndex += Count;
+
+ return T;
+}
+#endif
+
+
+void
+EnvLib_Init (void)
+{
+
+}
diff --git a/private/ntos/miniport/always/ntenv.h b/private/ntos/miniport/always/ntenv.h
new file mode 100644
index 000000000..0e0a6eb88
--- /dev/null
+++ b/private/ntos/miniport/always/ntenv.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 1993 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and should be treated as confidential.
+*/
+
+#ifndef __NTENV_H__
+#define __NTENV_H__
+
+#define VCN "655"
+
+#define FAR
+#define ALLOC_D /* Distance of a allocm (far or blank) */
+#define FARLOCALNOTIFY /* The internal notify procs are FAR */
+#define NILL NULL /* Local definition of what is usually NULL */
+
+// In a debug build, export all procedures for the debugger:
+#if !defined(DEBUG_ON)
+ #define LOCAL static /* Optional for those who don't like statics (i.e. symdeb'ers */
+#else
+ #define LOCAL
+#endif
+
+
+#ifdef USEFASTCALLS
+#define REGPARMS _fastcall
+#else
+#define REGPARMS
+#endif
+
+#define ALLOC_T void ALLOC_D * /* Type and distance of a malloc */
+
+typedef signed char I8;
+typedef UCHAR U8;
+typedef signed short int I16;
+typedef USHORT U16;
+typedef LONG I32;
+typedef ULONG U32;
+
+
+#ifdef USEFASTCALLS
+#define REGPARMS _fastcall
+#else
+#define REGPARMS
+#endif
+
+
+/* Envlib type things: */
+
+#define inb(Port) ScsiPortReadPortUchar((PUCHAR)(Port))
+#define inw(Port) ScsiPortReadPortUshort((PUSHORT)(Port))
+#define outb(Port, Val) ScsiPortWritePortUchar((PUCHAR)(Port), (UCHAR)(Val))
+#define outw(Port, Val) ScsiPortWritePortUshort((PUSHORT)(Port), (USHORT)(Val))
+#define repinsb(Port, Buffer, Count) ScsiPortReadPortBufferUchar((PUCHAR)(Port), (PUCHAR)(Buffer), (ULONG)(Count))
+#define repinsw(Port, Buffer, Count) ScsiPortReadPortBufferUshort((PUSHORT)(Port), (PUSHORT)(Buffer), (ULONG)(Count))
+#define repoutsb(Port, Buffer, Count) ScsiPortWritePortBufferUchar((PUCHAR)(Port), (PUCHAR)(Buffer), (ULONG)(Count))
+#define repoutsw(Port, Buffer, Count) ScsiPortWritePortBufferUshort((PUSHORT)(Port), (PUSHORT)(Buffer), (ULONG)(Count))
+
+#define FreeMemHandle(MemHandle)
+#define LocalMemHandle(MHP, MemPtr)(*(MHP) = (void FAR *)(MemPtr))
+#define LocalPostCallback(ofs) ofs
+#define msPause(msTicks) {unsigned register i = msTicks;while(i--) ScsiPortStallExecution(1000L);}
+#define ImportReq(Req) Req
+#define ExportReq(Req) Req
+#define RegisterIO(HA, Base, Length, AddrSpace) ((PUCHAR)ScsiPortGetDeviceBase(HA, Isa, 0, ScsiPortConvertUlongToPhysicalAddress((ULONG)Base), Length, (AddrSpace == AddrSpaceIO) ))
+ #define AddrSpaceIO 0
+ #define AddrSpaceMem 1
+#define DeregisterIO(HA, Handle) ScsiPortFreeDeviceBase(HA, Handle)
+
+typedef PUCHAR IOHandle;
+typedef unsigned short CriticalT;
+
+#define critical(HA)
+#define uncritical(HA)
+
+//#define EnvBreakPoint(HA) DbgBreakPoint() // Define the break call for the DEBUG breakpoit
+#define EnvBreakPoint(HA)
+
+
+/* Load time permanent parameters and parm list type: */
+#define ParmStrucVersion 0x1010 /* Structure format 1.0, content version 1.0 */
+struct AD_ParmStruc {
+
+ unsigned short Version; /* Version of this entry */
+ unsigned short ParmLength; /* Number of parm bytes to follow */
+ unsigned short ADStrucEntries; /* Number of AD Parm structs */
+ struct AD_ParmList *AD_List; /* Pointer to list AD Parm strucs */
+ unsigned short DebugEntries; /* Number of debug things */
+ int *DebugPtr; /* Pointer to debug level control */
+
+};
+
+struct AD_ParmList {
+
+ unsigned short IO_Addr; /* IO address for this addapter */
+ unsigned char ParmList[16]; /* Parm bytes for the adapter at this address */
+
+};
+
+// ParmList array index defines:
+#define PL_ID_PARMS 0 /* Start of drive parms per SCSI ID (0-7) */
+ #define PL_ALLOW_SYNC 0x01 /* Attempt sync. xfer on this SCSI_ID */
+ #define PL_USE_DISC 0x02 /* Attempt disconnect/reconnect on this SCSI ID */
+ #define DRIVE_PL(SCSI_ID) (PL_ID_PARMS + SCSI_ID)
+#define PL_HA_ID 15
+
+typedef unsigned char ADParmList[16]; /* Type for adapter parm list; an array, or pointer to array */
+
+#define LogMessage(HA, Req, TID, LUN, Code, Info) ScsiPortLogError(HA, Req, 0, TID, LUN, Code, Info)
+#define MSG_PARITY SP_BUS_PARITY_ERROR
+#define MSG_INTERNAL_ERROR SP_INTERNAL_ADAPTER_ERROR // Some form of internal error
+#define MSG_BUS_FREE SP_UNEXPECTED_DISCONNECT
+#define MSG_SCSI_PROTCOL SP_PROTOCOL_ERROR
+#define MSG_BAD_RESEL SP_INVALID_RESELECTION
+#define MSG_SEL_TIMEOUT SP_BUS_TIMEOUT
+#define MSG_NO_INTERRUPTS SP_IRQ_NOT_RESPONDING
+#define MSG_BAD_FIRMWARE SP_BAD_FW_ERROR
+#define MSG_NO_INT_ENABLE SP_IRQ_NOT_RESPONDING
+
+#endif /* __NTENV_H__ */
diff --git a/private/ntos/miniport/always/ntmgr.c b/private/ntos/miniport/always/ntmgr.c
new file mode 100644
index 000000000..511f7b4d2
--- /dev/null
+++ b/private/ntos/miniport/always/ntmgr.c
@@ -0,0 +1,547 @@
+/* Copyright (C) 1991-1994 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#include "environ.h"
+#include "rqm.h"
+#include "api.h"
+#include "apiscsi.h"
+#include "debug.h"
+
+#define HAExtentLen sizeof(struct Adapter)
+#define DEVExtentLen sizeof(struct DeviceDescr)
+#define REQExtentLen sizeof(struct IOReqExtension)
+
+
+enum ASPI_Priority {NORMAL_REQ, PRIORTY_REQ, IPRIORTY_REQ};
+void IExecuteReq(ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req, enum ASPI_Priorty Priorty);
+
+extern void EnvLib_Init(void);
+
+
+#define FreeDev(DevP)
+
+#if !defined(APIFindDev)
+DEVICE_PTR
+APIFindDev (const ADAPTER_PTR HA, const unsigned TID, const unsigned LUN)
+{
+
+ return ScsiPortGetLogicalUnit(HA, 0, (char)TID, (char)LUN);
+
+}
+#endif
+
+
+void
+APISetStatus (IO_REQ_PTR Req, // Request structure
+ APIStatus Status, // Status
+ TerminateCode Terminal, // Is this the terminal (Notify completion)
+ AutosenseCode IsSenseable) // Auto sense allowed?
+{
+ static U8 REQStats[]={
+ SRB_STATUS_PENDING, SRB_STATUS_PENDING, SRB_STATUS_ABORTED,
+ SRB_STATUS_BAD_FUNCTION, SRB_STATUS_INVALID_REQUEST, SRB_STATUS_NO_HBA,
+ SRB_STATUS_DATA_OVERRUN, SRB_STATUS_SELECTION_TIMEOUT,
+ SRB_STATUS_INVALID_TARGET_ID, SRB_STATUS_INVALID_LUN
+ };
+
+ static U8 ADStats[]={
+ SRB_STATUS_NO_HBA, SRB_STATUS_BUSY, SRB_STATUS_UNEXPECTED_BUS_FREE,
+ SRB_STATUS_PHASE_SEQUENCE_FAILURE, SRB_STATUS_BUS_RESET,
+ SRB_STATUS_AUTOSENSE_VALID, SRB_STATUS_ERROR};
+
+
+// Make sure the high numbers match what this module knows of:
+#if S_LAST_S_REQ != 0x09
+#err
+#endif
+
+#if S_LAST_S_AD != 0x06
+#err
+#endif
+
+#if S_LAST_S_SYS != 0
+#err
+#endif
+
+
+ switch (ErrorClass(Status)) {
+
+ case RequestClass:
+
+ DEBUG(0, if (Status == S_REQ_ABORT)
+ TRACE(0, ("APISetStatus(): Set Req (%x) status to aborted\n")) );
+ Req->SrbStatus = REQStats[ErrorCode(Status)];
+ break;
+
+
+ case AdapterClass:
+
+ Req->SrbStatus = ADStats[ErrorCode(Status)];
+ break;
+
+
+ case TargetClass:
+
+ Req->ScsiStatus = ErrorCode(Status);
+ switch (ErrorCode(Status)) {
+
+ case STATUS_CKCOND:
+
+ ReqDataCount(Req) = ReqSavedIndex(Req);
+#if defined(AUTOSENSE)
+ if ((IsSenseable == Senseable) && ReqSenseCount(Req)) {
+
+ Terminal = NonTerminal;
+ QueueInternalRequest(ReqAdapterPtr(Req), Req, RTAutoSenseReq);
+
+ } else
+#endif
+ Req->SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+
+ case STATUS_GOOD:
+ case STATUS_CONDMET:
+ case STATUS_INTGOOD:
+ case STATUS_INTCONDMET:
+
+ Req->SrbStatus = SRB_STATUS_SUCCESS;
+ if (ReqDataCount(Req) > ReqSavedIndex(Req)) {
+
+ Req->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ // Update number of bytes transferred.
+
+ // ReqSavedIndex is the number of bytes successfully transfered
+
+ // One thing the NT people will have to address is zero latency
+ // xfers. How will number of bytes xfered be represented
+ // on an error, when the xfer has holes?
+ ReqDataCount(Req) = ReqSavedIndex(Req);
+
+ }
+ break;
+
+
+ default:
+
+ Req->SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ }
+ TRACE(4, ("APISetStatus(): Setting target status to %02x\n",
+ Req->ScsiStatus));
+
+ break;
+ }
+
+ TRACE(4, ("APISetStatus(): Setting request status to %02x\n", Req->SrbStatus));
+
+ if (Terminal != NonTerminal) {
+
+ TRACE(3, ("APISetStatus(): Notifying completion\n"));
+ Notify(ReqAdapterPtr(Req), Req);
+
+ }
+}
+
+
+
+void
+Notify (ADAPTER_PTR HA, IO_REQ_PTR Req)
+{
+
+ if (ReqState(Req).InternalRequest)
+ (*(ReqPost(Req)))(Req);
+ else
+ ScsiPortNotification(RequestComplete, HA, Req);
+
+}
+
+
+void
+APINotifyReset (ADAPTER_PTR HA)
+{
+ TRACE(0, ("APINotifyReset():\n"));
+ ScsiPortNotification(ResetDetected, HA);
+}
+
+
+
+void
+IExecuteReq (ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req, enum ASPI_Priorty Priorty)
+{
+ TRACE(5, ("IExecuteReq(): Got request %x for device %x on adapter %x\n", Req, DevP, HA));
+
+ if (HA->DevInfo[ReqTargetID(Req)].Flags.NeedSync)
+ QueueInternalRequest(HA, Req, RTSyncNegReq);
+ else
+ QueueReq(HA, (IO_REQ_PTR)Req, (Priorty > NORMAL_REQ));
+
+}
+
+
+#define HAPollTime (ULONG)500000 // Time in uS for 500mS
+void
+HATimer (IN PVOID HAObject)
+{
+
+ TRACE(6, ("HATimer(): Timer entered\n"));
+ ((ADAPTER_PTR)HAObject)->Service(HA_TIMER, (ADAPTER_PTR)HAObject, 0l);
+ ScsiPortNotification(RequestTimerCall, HAObject, HATimer, HAPollTime);
+
+}
+
+
+
+BOOLEAN
+HAInit (PVOID HAObject)
+{
+ ADAPTER_PTR HA = HAObject;
+
+ TRACE(3, ("HAInit(): \n"));
+
+ HA->Ext->InternalRequest.Length = sizeof(HA->Ext->InternalRequest);
+ HA->Ext->InternalRequest.SrbExtension = &(HA->Ext->IntlReqExtension);
+ ReqCommand(&(HA->Ext->InternalRequest)) = SRB_FUNCTION_EXECUTE_SCSI; // internally generated command
+ ReqAdapterPtr(&HA->Ext->InternalRequest) = HA;
+ ReqState(&(HA->Ext->InternalRequest)).InternalRequest = 1;
+
+ ((ADAPTER_PTR)HAObject)->Service(HA_INITIALIZE, (ADAPTER_PTR)HAObject, 0l);
+ ScsiPortNotification(RequestTimerCall, HAObject, HATimer, HAPollTime);
+ return TRUE;
+
+}
+
+
+
+BOOLEAN
+ResetBus (PVOID HAObject, ULONG PathID)
+{
+
+ TRACE(0, ("ResetBus(): \n"));
+
+ ((ADAPTER_PTR)HAObject)->Service(HA_RESET_BUS, (ADAPTER_PTR)HAObject, 0l);
+
+ // Stall here, to allow the interrupt service routine to handle the reset
+ // and blow off requests, etc.
+ ScsiPortStallExecution(100l);
+
+ // Send completion of reset request:
+ ScsiPortCompleteRequest(HAObject, (UCHAR)PathID, (UCHAR)-1, (UCHAR)-1, SRB_STATUS_BUS_RESET);
+ return TRUE;
+
+}
+
+
+
+BOOLEAN
+AdapterState (IN PVOID HAObject, IN PVOID Context, IN BOOLEAN SaveState)
+{
+
+ if (SaveState)
+ ((ADAPTER_PTR)HAObject)->Service(HA_RESTORE_STATE, (ADAPTER_PTR)HAObject,
+ (U32)0);
+ return TRUE;
+
+}
+
+
+BOOLEAN
+StartIO (IN PVOID HAObject, IN PSCSI_REQUEST_BLOCK Req)
+{
+ ADAPTER_PTR HA = HAObject;
+ DEVICE_PTR DevP;
+ int i;
+
+ TRACE(2, ("StartIO(): Req @%x, Function = 0x%x, Req->SrbExtension @%x\n", Req, Req->Function, Req->SrbExtension));
+
+ switch (Req->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+
+ ReqNext(Req) = (IO_REQ_PTR)NILL;
+ ReqAdapterPtr(Req) = HA;
+ for (i=0; i < sizeof(ReqState(Req)); i++)
+ ((U8 *)&ReqState(Req))[i] = 0;
+
+ ReqState(Req).ReqType = RTNormalReq;
+
+ if ( (DevP = ScsiPortGetLogicalUnit(HA, Req->PathId, ReqTargetID(Req), ReqTargetLUN(Req))) == NILL) {
+
+ TRACE(3, ("ExecuteReq(): Unable to get device info\n"));
+ Req->SrbStatus = SRB_STATUS_NO_DEVICE;
+ return FALSE;
+
+ }
+
+ ReqDevP(Req) = DevP;
+ if (!DevP->Flags.Initialized)
+ QueueInternalRequest(HA, Req, RTGetInfoReq);
+ else
+ IExecuteReq(HA, DevP, Req, NORMAL_REQ);
+ break;
+
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ TRACE(3, ("StartIO(): RESET_BUS command\n"));
+ ResetBus(HAObject, Req->PathId);
+ break;
+
+
+ case SRB_FUNCTION_RESET_DEVICE:
+ case SRB_FUNCTION_TERMINATE_IO:
+ case SRB_FUNCTION_FLUSH:
+ case SRB_FUNCTION_SHUTDOWN:
+
+ Req->SrbStatus = SRB_STATUS_SUCCESS;
+ ScsiPortNotification(RequestComplete, HA, Req);
+ break;
+
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ TRACE(0, ("StartIO(): Request at %x to abort request %x\n", Req, Req->NextSrb));
+ if ((DevP = ScsiPortGetLogicalUnit(HA, Req->PathId, ReqTargetID(Req), ReqTargetLUN(Req))) == NILL
+ || (DevP->Flags.Initialized == 0)
+ || !AbortRequest(HA, DevP, Req->NextSrb) ) {
+
+ TRACE(0, ("StartIO(): Abort operation failed\n"));
+ Req->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ } else {
+
+
+ TRACE(0, ("StartIO(): Abort operation success\n"));
+ Req->SrbStatus = SRB_STATUS_SUCCESS;
+
+ }
+ ScsiPortNotification(RequestComplete, HA, Req);
+ break;
+
+
+ case SRB_FUNCTION_RELEASE_RECOVERY:
+ case SRB_FUNCTION_RECEIVE_EVENT:
+ case SRB_FUNCTION_IO_CONTROL:
+ default:
+
+ TRACE(0, ("StartIO(): Unsupported command: 0x%x\n", Req->Function));
+ APISetStatus(Req, S_REQ_OPCODE, Terminal, NotSenseable);
+ return FALSE;
+ break;
+
+
+ }
+
+ ScsiPortNotification(NextLuRequest, HA, Req->PathId, Req->TargetId, Req->Lun);
+ return TRUE;
+
+}
+
+
+BOOLEAN
+GeneralISR (PVOID HAObject)
+{
+
+ return (BOOLEAN) ( ((ADAPTER_PTR)HAObject)->ISR((ADAPTER_PTR)HAObject) );
+
+}
+
+
+ULONG
+FindAdapter (IN PVOID HAObject, IN PVOID PContext, IN PVOID BusInfo,
+ IN PCHAR ArgString, IN OUT PPORT_CONFIGURATION_INFORMATION Config,
+ OUT PBOOLEAN PAgain)
+{
+ ADAPTER_PTR HA = HAObject;
+
+ TRACE(3, ("FindAdapter(): Adapter ptr = %x, Config ptr = %x, Len = 0x%x\n", HA, Config, sizeof(struct _PORT_CONFIGURATION_INFORMATION)));
+
+ /* Hunt down and register the adapters in the system: */
+ HA->IOBaseAddr = (U16)ScsiPortConvertPhysicalAddressToUlong(
+ (*Config->AccessRanges)[0].RangeStart);
+
+ if (Adapter_Init(HA, (unsigned *)PContext)) {
+
+ // Set Again TRUE, only if we're being called with a non-sepcific access range
+ *PAgain = ScsiPortConvertPhysicalAddressToUlong(
+ (*Config->AccessRanges)[0].RangeStart) == 0;
+
+ Config->BusInterruptLevel = HA->IRQNumber;
+
+ Config->ScatterGather = HA->Supports.ScatterGather;
+ Config->MaximumTransferLength = 0x400000;
+ Config->NumberOfPhysicalBreaks = 0x400;
+// Config->NumberOfPhysicalBreaks = HA->MaxSGListLength;
+
+ (*Config->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(HA->IOBaseAddr);
+ (*Config->AccessRanges)[0].RangeLength = HA->IOAddrLen;
+ (*Config->AccessRanges)[0].RangeInMemory = FALSE;
+
+ Config->NumberOfBuses = 1;
+ Config->InitiatorBusId[0] = HA->SCSI_ID;
+ Config->Master = (HA->Physical.Xfermode == XM_MASTER) || (HA->Physical.Xfermode == XM_MASTER24);
+ Config->Dma32BitAddresses = (HA->Physical.Xfermode == XM_MASTER);
+ Config->DemandMode = (HA->Physical.Xfermode == XM_DMAD);
+ Config->NeedPhysicalAddresses = XM_PHYSICAL(HA->Physical.Xfermode);
+ Config->MapBuffers = TRUE;
+ Config->CachesData = HA->Supports.Caching;
+ Config->AlignmentMask = 0x3;
+
+ Config->TaggedQueuing = FALSE;
+
+#if defined(AUTOSENSE)
+ Config->AutoRequestSense = TRUE;
+#else
+ Config->AutoRequestSense = FALSE;
+#endif
+
+ Config->MultipleRequestPerLu = Config->AutoRequestSense;
+
+ Config->ReceiveEvent = FALSE;
+
+ HA->Ext = ScsiPortGetUncachedExtension(HA, Config, sizeof(AdapterExtension));
+
+ return SP_RETURN_FOUND;
+
+ } else {
+
+ *PAgain = FALSE;
+ return SP_RETURN_NOT_FOUND;
+
+ }
+}
+
+
+ULONG
+DriverEntry (IN PVOID HAObject, IN PVOID ARG)
+{
+ HW_INITIALIZATION_DATA InitData; // Adapter init. struct
+ unsigned i;
+ ULONG AdapterCount;
+ ULONG ISAStatus, EISAStatus;
+// ULONG MCAStatus, LocalStatus;
+
+ /* Initialize the environment: */
+ EnvLib_Init();
+
+ // Initialize the object
+ for (i=0; i < sizeof(InitData); i++)
+ ((char *)&InitData)[i] = 0;
+
+ InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ // Set pointers to service functions:
+ InitData.HwInitialize = HAInit;
+ InitData.HwStartIo = StartIO;
+ InitData.HwInterrupt = GeneralISR;
+ InitData.HwFindAdapter = FindAdapter;
+ InitData.HwResetBus = ResetBus;
+ InitData.HwAdapterState = AdapterState; //
+
+ // Set capabilities
+ InitData.MapBuffers = TRUE; // This should be in PORT config info
+ InitData.NeedPhysicalAddresses = FALSE;
+ InitData.TaggedQueuing = FALSE;
+
+#if defined(AUTOSENSE)
+ InitData.AutoRequestSense = TRUE;
+#else
+ InitData.AutoRequestSense = FALSE;
+#endif
+
+ InitData.MultipleRequestPerLu = InitData.AutoRequestSense;
+
+ InitData.ReceiveEvent = FALSE;
+
+ // Set misc. things:
+ InitData.NumberOfAccessRanges = 1;
+
+ // Set the size of extensions
+ InitData.DeviceExtensionSize = HAExtentLen;
+ InitData.SpecificLuExtensionSize = DEVExtentLen;
+ InitData.SrbExtensionSize = REQExtentLen;
+
+ AdapterCount = 0;
+
+ TRACE(3, ("DriverEntry(): Trying EISA adapters\n"));
+ InitData.AdapterInterfaceType = Eisa;
+ EISAStatus = ScsiPortInitialize(HAObject, ARG, &InitData, (PVOID)&AdapterCount);
+ TRACE(2, ("DriverEntry(): ScsiPortInitialize() returned: %x\n", EISAStatus));
+
+ if (EISAStatus != 0) {
+
+ TRACE(3, ("DriverEntry(): Trying ISA adapters\n"));
+ InitData.AdapterInterfaceType = Isa;
+ ISAStatus = ScsiPortInitialize(HAObject, ARG, &InitData, (PVOID)&AdapterCount);
+ TRACE(2, ("DriverEntry(): ScsiPortInitialize() returned: %x\n", ISAStatus));
+
+ }
+
+ return min(ISAStatus, EISAStatus);
+
+}
+
+
+
+void
+GetXferSegment (const ADAPTER_PTR HA, IO_REQ_PTR Req, SegmentDescr *SGDescr,
+ U32 Offset, BOOLEAN DemandPhysicalAddr)
+{
+
+ TRACE(4, ("GetXferSegment(): Offset = %d\n", Offset));
+ TRACE(4, ("GetXferSegment(): Non-S/G request, ReqDataCount = %d\n", ReqDataCount(Req)));
+
+ if (Offset < ReqDataCount(Req)) { // Make sure we don't over run
+
+ SGDescr->SegmentLength = ReqDataCount(Req) - Offset;
+ SGDescr->SegmentPtr = (U32)ReqDataPtr(Req) + Offset;
+
+ } else {
+
+ SGDescr->SegmentLength = 0; // No data left
+ SGDescr->SegmentPtr = 0;
+ BreakPoint(HA);
+
+ }
+ TRACE(4, ("GetXferSegment(): %d bytes remain in segment at %08x (offset %d)\n",
+ SGDescr->SegmentLength, SGDescr->SegmentPtr, Offset));
+
+ SGDescr->Flags.IsPhysical = FALSE;
+
+ if (DemandPhysicalAddr) {
+
+ if (ReqState(Req).InternalRequest) {
+
+ TRACE(5, ("GetXferSegment(): Mapping internal request\n"));
+ MapToPhysical(HA, SGDescr);
+
+ } else {
+
+ ULONG Size = SGDescr->SegmentLength;
+
+ SGDescr->SegmentPtr = (U32)ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(HA, Req,
+ (PVOID)((U32)ReqDataPtr(Req) + Offset) /*(SGDescr->SegmentPtr)*/,
+ &Size));
+
+ if (Size < SGDescr->SegmentLength)
+ SGDescr->SegmentLength = Size;
+
+ DEBUG(5, {
+ if (SGDescr->SegmentLength < (ReqDataCount(Req) - Offset))
+ DPrintf("Segment length is %d out of %d\n",
+ SGDescr->SegmentLength, ReqDataCount(Req) - Offset);});
+
+ SGDescr->Flags.IsPhysical = TRUE;
+
+ TRACE(5, ("GetXferSegment(): Mapped to 0x%lx for %lu bytes\n",
+ SGDescr->SegmentPtr, Size));
+
+ }
+ }
+}
diff --git a/private/ntos/miniport/always/rqm.c b/private/ntos/miniport/always/rqm.c
new file mode 100644
index 000000000..e68ad9b62
--- /dev/null
+++ b/private/ntos/miniport/always/rqm.c
@@ -0,0 +1,569 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+*/
+
+#include "environ.h"
+#include "rqm.h"
+#include "api.h"
+#include "apiscsi.h"
+#include "debug.h"
+
+/*
+ Add the device index for a request to the tail of the FIFO. AddReqFIFO
+ is called only when a request is moved to the head of the queue, i.e.,
+ the first command for a device or when the current request for a device
+ completes, and the second command moves to the head.
+*/
+
+void REGPARMS
+AddReqFIFO (ADAPTER_PTR HA, DEVICE_PTR DevP)
+{
+ DevP->FIFO_Next = NILL;
+
+ TRACE(3,("AddReqFIFO(): Adding device %02x to FIFO\n", DevP));
+
+ if (HA->FIFO_Head == DevP) {
+
+ PanicMsg("AddReqFIFO(): Circular device chain\n");
+
+ }
+
+ critical(HA);
+ if (HA->FIFO_Head == NILL)
+ HA->FIFO_Head = DevP;
+ else
+ HA->FIFO_Tail->FIFO_Next = DevP;
+
+ HA->FIFO_Tail = DevP;
+ uncritical(HA);
+
+}
+
+
+
+/*
+ Get the next request in the request FIFO. The FIFO is not incremented
+ until AcceptReq is called. See the comment below for more details.
+*/
+
+IO_REQ_PTR REGPARMS
+GetReqFIFO (ADAPTER_PTR HA)
+{
+ IO_REQ_PTR Req=NILL;
+
+ // Because an abort request may empty the pending queue, we will scan the
+ // device FIFO until we find a device with an non-empty request list. If we
+ // don't find one, return NULL, which says there are not more pending requests.
+ while (HA->FIFO_Head != NILL) {
+
+ Req = HA->FIFO_Head->PendingReqList;
+ if (Req == NILL)
+ HA->FIFO_Head = HA->FIFO_Head->FIFO_Next;
+ else
+ break;
+
+ }
+
+ return Req;
+}
+
+
+
+/* Start the next request for a given adapter: */
+void
+StartNext (ADAPTER_PTR HA, int StartLevel)
+{
+ IO_REQ_PTR Req;
+
+ if (!(HA->State.Busy) && (Req = GetReqFIFO(HA)) != NILL) {
+
+ critical(HA);
+ HA->Ext->MI_Count = HA->Ext->MI_Needed = HA->Ext->MO_Count = 0; /* Clear msg buffers */
+ HA->CurrReq = Req;
+ HA->CurrDev = (DEVICE_PTR)ReqDevP(Req);
+ HA->Service(HA_INITIATE, HA, (long)StartLevel);
+ uncritical(HA);
+ TRACE(3,("StartNext(): Starting request: %lx\n", (long)Req));
+
+ } else {
+
+ TRACE(3,("StartNext(): Empty queue\n"));
+
+ }
+}
+
+
+/*
+ If the adapter has taken a request off the queue, and has attempted
+ to initiate it, it will set the "ReqStarting" flag. When the controller
+ acknowledges the start of the command, then the following procedure is
+ called to remove it from the queue. If the controller does not accept the
+ command (usually caused if a reselection occuring before the new
+ target is selected), the flag will be cleared, and the request not removed
+ from the queue. So the next time GetReqFIFO is called, the same request
+ will be returned.
+*/
+
+void
+AcceptReq (ADAPTER_PTR HA)
+{
+ DEVICE_PTR DevP;
+ IO_REQ_PTR Req;
+
+ if ((HA->ReqStarting !=0) && (--(HA->ReqStarting) == 0)) {
+
+
+ critical(HA);
+
+ DevP = HA->FIFO_Head;
+
+ DevP->CurrDepth++; // Bump the numberof active requests
+ HA->FIFO_Head = DevP->FIFO_Next; // Advance the next device w/ pending requests
+
+ Req = DevP->PendingReqList;
+
+ DevP->PendingReqList = ReqNext(Req);
+ ReqNext(Req) = DevP->AcceptedList;
+ DevP->AcceptedList = Req;
+
+ ReqState(Req).Connected = 1;
+
+ uncritical(HA);
+
+#if defined(KEEP_STATS)
+ HA->ReqsAccepted++;
+#endif
+
+ TRACE(5,("AcceptReq(): Request (@%lx) accepted for device %x\n", Req, DevP));
+
+ }
+}
+
+
+
+/*
+ Find a request block by device and queue tag; returns a pointer to
+ the request, or NULL if it not found.
+*/
+IO_REQ_PTR
+Find_Req (DEVICE_PTR DevP, const unsigned LUN, const unsigned QID)
+{
+ IO_REQ_PTR Req = DevP->AcceptedList;
+
+ while ((Req != NILL) && ((ReqTargetLUN(Req) != LUN)
+#if defined(ReqQID)
+ || (ReqQID(Req) != QID)
+#endif
+ )) {
+
+ Req = ReqNext(Req);
+
+ }
+ return Req;
+}
+
+
+
+int
+Reselect_Req (ADAPTER_PTR HA, IO_REQ_PTR Req)
+{
+
+ HA->CurrReq = Req;
+ HA->CurrDev = (DEVICE_PTR)ReqDevP(Req);
+ HA->State.Busy = 1;
+ HA->State.Reselecting = 0;
+ HA->Ext->MI_Count = HA->Ext->MI_Needed = HA->Ext->MO_Count = 0; /* Clear message buffers */
+
+ /* Reselection performs an implied restore pointers: */
+ HA->ReqCurrentIndex = ReqSavedIndex(HA->CurrReq);
+ TRACE(3, ("Reselect_Req(): Implied restore data ptr, ReqSavedIndex() = %d\n",
+ ReqSavedIndex(HA->CurrReq)));
+ // CurrentCounts == 0 will cause a GetXferSegment from the above offset
+ HA->ReqCurrentCount = 0;
+
+ TRACE(4,("Reselect_Req(): reselect on TID %d, req @ %lx\n", ReqTargetID(Req), Req));
+ HA->Service(HA_LED, HA, 1);
+
+ ReqState(Req).Connected = 1;
+ return 0;
+
+}
+
+
+
+int
+Reselect (ADAPTER_PTR HA, const unsigned TID, const unsigned LUN, const unsigned QID)
+{
+ DEVICE_PTR DevP;
+ IO_REQ_PTR Req;
+
+ HA->CurrReq = NILL;
+ DevP = APIFindDev(HA, TID, LUN);
+ if (DevP == NILL)
+ return 1;
+
+ Req = Find_Req(DevP, LUN, QID);
+ if (Req == NILL)
+ return 1;
+ return Reselect_Req(HA, Req);
+
+}
+
+
+/*
+ This function handles completion of an arbitrary request by:
+
+ 1) De-queuing the request
+
+ 2) Handling of temporary device descriptor disposal
+
+ 3) Handling sync. negotiations which fail with a check condition status
+
+ 4) Notify the request call back (if ReqFlags(Req).Post is true)
+
+ 5) --->> Sets HA->CurrReq to NILL; <<---
+ This is highlighted because the request passed in is not necessarly
+ the one in HA->CurrReq. However, if an adapter is completing a
+ request, then it's attention can't be on a differant one too.
+*/
+
+void
+ReqDone (ADAPTER_PTR HA, IO_REQ_PTR Req)
+{
+ DEVICE_PTR DevP;
+
+
+ if (Req == (IO_REQ_PTR)NILL) {
+
+ TRACE(0, ("ReqDone(): Completing NULL request\n"));
+ return;
+
+ }
+
+ /* Get the descriptor for the device which processed this request: */
+ DevP = (DEVICE_PTR)ReqDevP(Req);
+ if (DevP->PendingReqList == Req)
+ AcceptReq(HA);
+
+ DevP->CurrDepth--; // Dec. number of active reqs.
+
+ if (DevP->AcceptedList == Req)
+ DevP->AcceptedList = ReqNext(Req);
+ else {
+
+ /* Search for the pointer to this request in the accepted list: */
+ IO_REQ_PTR Req2 = DevP->AcceptedList;
+ while (ReqNext(Req2) != Req && Req2 != NILL)
+ Req2 = ReqNext(Req2);
+
+ if (Req2 == NILL)
+ PanicMsg("ReqDone(): Request not on list. Catastrophic failure.\n");
+
+ /* Unlink by pointing this one's predicessor to this one's next. */
+ ReqNext(Req2) = ReqNext(Req);
+
+ }
+
+
+ /*
+ Since we just finished up one request, add the next (if any) to the FIFO
+ of devices with pending requests.
+ */
+ if ((DevP->PendingReqList != NILL) && (DevP->CurrDepth < DevP->MaxDepth))
+ AddReqFIFO(HA, DevP);
+
+ /* If we get a check condition during sync. negotiaitons (Need_Sync still
+ true, then the target rejected the synchronous request via by 1) not
+ completing the negotiaition (no msg in phase); & 2) going directly
+ to the status phase (by passing command phase). Clean up the sync.
+ control bits for the device, saying that sync. is not allowed, don't
+ use it, and don't ask for it.
+ */
+
+ if ((ReqAPIStatus(Req) == S_TAR_CHECKCOND) && (HA->DevInfo[ReqTargetID(Req)].Flags.NeedSync)) {
+
+ HA->DevInfo[ReqTargetID(Req)].Flags.UseSync = HA->DevInfo[ReqTargetID(Req)].Flags.AllowSync =
+ HA->DevInfo[ReqTargetID(Req)].Flags.NeedSync = FALSE;
+ TRACE(3,("ReqDone(): Sync. negotiation aborted by CHECK CONDITION\n"));
+
+ }
+
+ HA->CurrReq = NILL;
+
+ /* If we are to notify someone of the command completion, do so now: */
+
+ TRACE(4,("ReqDone(): Status = %04x\n", ReqAPIStatus(Req)));
+
+#if defined(KEEP_STATS)
+ HA->ReqsCompleted++;
+#endif
+
+ ReqState(Req).Connected = 0;
+ APISetStatus(Req, ReqAPIStatus(Req), Terminal, HA->Supports.OnBoardQueuing ? NotSenseable : Senseable);
+
+}
+
+
+
+LOCAL IO_REQ_PTR * REGPARMS
+ScanReqList (IO_REQ_PTR *List, IO_REQ_PTR Req)
+{
+ if (List == (IO_REQ_PTR *)NILL)
+ return List;
+
+ while (*List != (IO_REQ_PTR)NILL && *List != Req)
+ List = (IO_REQ_PTR *)&(ReqNext(*List));
+ return List;
+
+}
+
+
+BOOLEAN
+AbortRequest (ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req)
+{
+ IO_REQ_PTR *ReqScan = &(DevP->PendingReqList);
+ BOOLEAN OnAccepted=FALSE;
+
+ if (HA->CurrReq == Req) {
+
+ TRACE(1, ("AbortRequest(): Request is active; not aborting\n"));
+ return FALSE;
+
+ }
+
+ if (*ReqScan == Req) {
+
+ TRACE(2, ("AbortRequest(): Request to abort found at PendingHead\n"));
+ if ((DevP->PendingReqList = ReqNext(Req)) == NILL) {
+
+ // We have removed the only request for this device, so now
+ // remove the device from the chain of pending devices:
+ if (HA->FIFO_Head == DevP) {
+
+ HA->FIFO_Head = DevP->FIFO_Next;
+ DevP->FIFO_Next = NILL;
+
+ } else {
+
+ DEVICE_PTR ScanDev=HA->FIFO_Head;
+ while (ScanDev != NILL && ScanDev->FIFO_Next != DevP)
+ ScanDev = ScanDev->FIFO_Next;
+
+ if (ScanDev != NILL)
+ ScanDev->FIFO_Next = DevP->FIFO_Next;
+
+ if (HA->FIFO_Tail == DevP)
+ HA->FIFO_Tail = ScanDev;
+
+ }
+ }
+
+ } else {
+
+ if ((ReqScan = ScanReqList(ReqScan, Req)) == NILL) {
+
+ TRACE(2, ("AbortRequest(): Scanning accepted list\n"));
+ ReqScan = ScanReqList(&(DevP->AcceptedList), Req);
+ OnAccepted = TRUE;
+
+ }
+
+ }
+
+ if (ReqScan == NILL) {
+
+ TRACE(2, ("AbortRequest(): Request not found in pending list\n"));
+ return FALSE; // but the abort didn't work directly
+
+ }
+
+ // At this point, ReqScan points to pointer to the request we want to abort
+ *ReqScan = ReqNext(Req); // Take Req out of chain
+
+ // OK, so Req has been verified as being on the pending queue, and has
+ // been removed. Now we can complete the request, with an aborted status.
+
+ APISetStatus(Req, S_REQ_ABORT, Terminal, NotSenseable);
+
+ if (OnAccepted) {
+
+ // This was an accpted request. Decrement the pending count to allow
+ // more requests to pass to the target.
+ DevP->CurrDepth--;
+
+ }
+
+ return TRUE; // Abort was successful
+
+}
+
+
+/*
+ Queue up a request. The queues are kept by Target ID. If an entry already
+ exists for a particular Target ID, then the new request is appended to the
+ queue. If the queue is empty, the request is added as the head, and the
+ target ID is added to the FIFO of targets with requests pending.
+*/
+
+void
+QueueReq (ADAPTER_PTR HA, IO_REQ_PTR Req, int AtHead)
+{
+ DEVICE_PTR DevP = (DEVICE_PTR)ReqDevP(Req);
+
+ TRACE(4,("QueueReq(): Got request @%lx for TID/LUN %d/%d(device %lx)\n", Req, ReqTargetID(Req), ReqTargetLUN(Req), DevP));
+
+ DmsPause(6, 1000);
+
+ if (HA->State.OffLine) {
+
+ APISetStatus(Req, S_AD_OFF, Terminal, NotSenseable);
+ return;
+
+ }
+
+ ReqAPIStatus(Req) = S_REQ_ACCEPTED;
+ APISetStatus(Req, S_REQ_ACCEPTED, NonTerminal, NotSenseable);
+
+ if (ReqCDBLen(Req) == 10 || ReqCDBLen(Req) == 6 || ReqCDBLen(Req) == 12) {
+
+ } else {
+
+ TRACE(0,("QueueReq(): Request rejected; CDB Length = %d\n", ReqCDBLen(Req)));
+ APISetStatus(Req, S_REQ_OPCODE, NonTerminal, NotSenseable);
+ return;
+
+ }
+
+ ReqSavedIndex(Req) = 0; // Index used for saved data pointers
+
+ /* If we support linked commands, see if this one is linked; if it is not,
+ force the link chain pointer to NILL. If linked commands are not
+ supported, then always force link field to zero
+ */
+
+ critical(HA);
+
+ /* At head will only come from an auto-request sense; therefore, the first
+ entry (if any) will NOT be in progress. If AtHEad is requested at any
+ other time, the top request on the queue must be checked to see if it
+ in progress; and if so, the AtHead request must be made the second
+ request on the queue.
+ */
+
+ if (AtHead) {
+
+ TRACE(5, ("QueueReq(): Queing at head\n"));
+
+ ReqNext(Req) = DevP->PendingReqList;
+ DevP->PendingReqList = Req;
+ if ((ReqNext(Req) == NILL) && (DevP->CurrDepth < DevP->MaxDepth))
+ AddReqFIFO(HA, DevP);
+
+ } else {
+
+#if defined(RF_LINKED)
+ if (!(ReqFlags(Req) & RF_LINKED))
+ ReqNext(Req) = NILL;
+#else
+ ReqNext(Req) = NILL;
+#endif
+
+ if (DevP->PendingReqList == NILL) {
+
+ DevP->PendingReqList = Req;
+ if (DevP->CurrDepth < DevP->MaxDepth)
+ AddReqFIFO(HA, DevP);
+
+ } else {
+
+ IO_REQ_PTR ReqScan = DevP->PendingReqList;
+ while (ReqNext(ReqScan) != NILL)
+ ReqScan = ReqNext(ReqScan);
+ ReqNext(ReqScan) = Req;
+
+ }
+
+ }
+
+#if defined(KEEP_STATS)
+ HA->ReqsQueued++;
+#endif
+
+ TRACE(2,("QueueReq(): Request @ %0lx", Req));
+ TRACE(2,(" CDB[0] = %02x, Data @%08lx, Count = %ld\n", ReqCDB(Req)[0], ReqDataPtr(Req), ReqDataCount(Req)));
+
+ DmsPause(6, 2000);
+ if (DevP->CurrDepth < DevP->MaxDepth) {
+
+ TRACE(5,("About to tickle adapter\n"));
+ HA->Service(HA_TICKLE, HA, (long)0);
+
+ }
+
+ uncritical(HA);
+
+}
+
+
+
+void
+BlowAwayRequests (ADAPTER_PTR HA, int Which, APIStatus Status)
+{
+
+ unsigned ID, LUN;
+ DEVICE_PTR DevP;
+ IO_REQ_PTR Req;
+
+ /* Walk the device tables, and abort accepted commands. Then set the
+ device states to require re-negotiating sync. xfers */
+
+ TRACE(1, ("BlowAwayRequests(): Scaning for device IDs 0-%d on HA %x\n", HA->Max_TID, HA));
+ for (ID = 0; ID <= HA->Max_TID; ID++) {
+
+ HA->DevInfo[ID].Flags.UseSync = 0;
+ HA->DevInfo[ID].Flags.NeedSync = HA->DevInfo[ID].Flags.AllowSync;
+
+ for (LUN = 0; LUN <= 7; LUN++) {
+
+ DevP = APIFindDev(HA, ID, LUN);
+ if (DevP == NILL || DevP->Flags.Initialized == 0)
+ continue;
+
+ TRACE(2, ("BlowAwayRequests(): Got device descriptor for %d/%d\n", ID, LUN));
+ if (Which == ACTIVE_REQUESTS || Which == ALL_REQUESTS) {
+
+ while (DevP->AcceptedList != NILL) {
+
+ TRACE(4, ("BlowAwayRequests(): Completeing request %x\n", DevP->AcceptedList));
+ ReqAPIStatus(DevP->AcceptedList) = Status;
+ if (HA->Supports.OnBoardQueuing)
+ HA->Service(HA_ABORT_REQ, HA, (U32)DevP->AcceptedList);
+ else
+ ReqDone(HA, DevP->AcceptedList);
+
+ }
+ } // if (Which ...
+
+ if (Which == PENDING_REQUESTS || Which == ALL_REQUESTS) {
+
+ for (Req=DevP->PendingReqList; Req != NILL; Req=DevP->PendingReqList) {
+
+ TRACE(4, ("BlowAwayRequests(): Completeing request %x\n", Req));
+ DevP->PendingReqList = ReqNext(Req);
+ APISetStatus(Req, Status, Terminal, NotSenseable);
+
+ } // for (Req ...
+ } // if (Which ...
+ } // for (LUN = ...
+ } // for (ID = ...
+}
+
+
+
+void
+HAParmChange (ADAPTER_PTR HA)
+{
+ HA->Service(HA_PARM_CHANGE, HA, (U32)0);
+}
+
diff --git a/private/ntos/miniport/always/rqm.h b/private/ntos/miniport/always/rqm.h
new file mode 100644
index 000000000..28f67562a
--- /dev/null
+++ b/private/ntos/miniport/always/rqm.h
@@ -0,0 +1,330 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and should be treated as confidential.
+ */
+
+#ifndef __RQM_H__
+#define __RQM_H__
+
+#define DevInfoInqSize 8 // 8 bytes of Inquiry buffer for Device info requests
+
+typedef struct DeviceDescr *DEVICE_PTR;
+typedef struct Adapter *ADAPTER_PTR;
+
+
+#include "adapters.h"
+
+
+// Find the maximum width of SCSI defined for all adapters:
+#if defined(SCSI_32) // Is WIDE 32 defined?
+ #define MAX_SCSI_WIDTH 32
+#else
+ #if defined(SCSI_16) // Is WIDE 16 defined?
+ #define MAX_SCSI_WIDTH 16
+ #else
+ #define MAX_SCSI_WIDTH 8 // Then default to 8 bit SCSI
+ #endif
+#endif
+
+
+#define MAX_HA 8 // Max number of adapters to try for
+#if defined(SEPERATELUNS)
+ #define MIN_DEVS 32
+#else
+ #define MIN_DEVS MAX_SCSI_WIDTH // Min number of dev. descrs. allocated
+#endif
+
+
+#if defined(NATIVE64)
+ typedef U64 QueueIDMask;
+ #define QueueIDMaskWidth 64
+#else
+ #if defined(NATIVE32)
+ typedef U32 QueueIDMask;
+ #define QueueIDMaskWidth 32
+ #else
+ typedef U16 QueueIDMask;
+ #define QueueIDMaskWidth 16
+ #endif
+#endif
+
+
+struct DeviceDescr {
+
+ // Word aligned things here:
+ IO_REQ_PTR PendingReqList; // Head of request chain for this device
+ IO_REQ_PTR AcceptedList; // Chain of requests accepted on this device
+ ADAPTER_PTR HA; // The HA this device is attached to
+
+ QueueIDMask TaggedQueueMask; // Bit array for generating unique tagged queue IDs
+
+ // Byte aligned things here:
+ U8 SCSI_ID; // SCSI ID of the device described here
+
+#if defined(SEPERATELUNS)
+ U8 SCSI_LUN; // SCSI LUN of the device described here
+ DEVICE_PTR Next_LUN; // Pointer to device with same SCSIID, next higher LUN
+#endif
+
+ U8 MaxDepth; // Max number of queued requests
+ U8 CurrDepth; // Curr number of queued requests
+
+ struct {
+
+ unsigned Initialized:1; // Has this entry been initialized?
+ unsigned Allow_Disc:1; // Allow use of disc/reconnect
+ unsigned AllowsQueued:1; // Supports queued commands
+ unsigned OnFIFO:1; // Is this device already on the FIFO?
+ unsigned IsSCSI2:1; // The SCSI-2 flags below are meaningful
+
+ } Flags;
+
+ U8 Device_Type; // Dev. type field from inquiry data
+ union { //
+ struct { //
+ unsigned SoftReset:1; // Device supports soft reset option
+ unsigned Queuing:1; // Supports tagged queuing
+ unsigned Reserved:1; //
+ unsigned Linked:1; // Device supports linked commands
+ unsigned Sync:1; // Device supports sync. xfers
+ unsigned WBus16:1; // Supports 16 bit wide SCSI
+ unsigned WBus32:1; // Supports 32 bit wide SCSI
+ unsigned RelAddr:1; // Linked commands support rel. addressing
+ } Bits;
+ U8 Byte; // easy byte access; set from inquiry data
+ } SCSI2_Flags;
+
+ DEVICE_PTR FIFO_Next; // Next Dev_Index on adapter to start a req.
+
+ U8 Sync_Period; // Raw (SCSI message byte) negotiated period value
+ U8 Sync_Offset; // Negotiated SCSI sync. offset
+
+};
+
+
+
+
+// Synchronous info. by SCSI ID in adapter terms:
+struct HADeviceStruct {
+ U8 HASync1; // These fields are adapter specific; the adapter driver puts
+ U8 HASync2; // what ever values it needs for setting its registers when selecting a device
+ struct {
+ unsigned AllowSync:1; // Allow Syncronous negotiation
+ unsigned UseSync:1; // Allow Syncronous negotiation
+ unsigned NeedSync:1; // Allow Syncronous negotiation
+ } Flags;
+};
+
+
+typedef struct {
+
+ union AdapterU AD; // Adapter specific unions
+
+ union SBICU SBIC; // SBIC specific unions
+
+ U8 MI_Buff[8]; // Message interp. buffer
+ int MI_Count; // Count of messages in buffer
+ int MI_Needed; // Number of messages still needed
+
+ int MO_Count; // Number of messages in the message out buffer
+ int MO_Index; // Current index of messages as they are sent
+ U8 MO_Buff[8]; // Buffer where message out bytes are stored
+
+ U8 InitialState[16]; // Area into which to save the initial state
+
+ IO_REQ_PTR InternalReqDeferQueue; // List of requests waiting for internal request
+ U8 InternalReqBuffer[DevInfoInqSize]; // Buffer for internal req data
+
+#if defined(ReqExtensionPtr)
+ struct IOReqExtension IntlReqExtension; // Request extension for internal requests
+#endif
+
+ IO_REQ InternalRequest; // Internal Request block
+
+} AdapterExtension;
+
+
+struct Adapter {
+
+ IOHandle IOBase; // IO base address handle of described adapter
+ U16 IOBaseAddr; // Raw I/O address
+ U16 IOAddrLen; // Number of ports used
+ U8 Channel; // DMA or ??? channel
+ U8 IRQNumber; // IRQ number of adapter
+
+ int (*ISR)(struct Adapter ALLOC_D *HA); // Interrupt service routine for this model
+ U32 (*Service)(int Function, ADAPTER_PTR HA, U32 Misc); // Helper routine for this model
+ AdapterExtension ALLOC_D *Ext; // Adapter, SBIC, Env extensions
+
+ IO_REQ_PTR CurrReq; // Pointer to the active request
+ U32 ReqCurrentCount; // Remain xfer count for active request
+ U32 ReqCurrentIndex; // Xfer index for active request
+
+ short MaxSGListLength; // Max. number of SG list entries
+ CriticalT CriticalFlag; // Count, semiphore, ??? used by critical/uncritical
+
+ DEVICE_PTR DeviceList[MAX_SCSI_WIDTH]; // list of device indicies by SCSI ID (allow for wide)
+ struct HADeviceStruct DevInfo[MAX_SCSI_WIDTH];
+ DEVICE_PTR FIFO_Head, FIFO_Tail; // First and last devs with reqs pending
+ DEVICE_PTR CurrDev; // Pointer to device of curr. req
+
+ SegmentDescr SGDescr; // S/G segment descriptor data xfer setup
+
+ struct {
+
+ unsigned Busy:1; // there is stuff going on or pending
+ unsigned Reselecting:1; // In the process of reselecting
+ unsigned DataIn:1; // Data function is input to adapter
+ unsigned DataXfer:1; // Doing some data xfer; dir. defd. above
+ unsigned DoingSync:1; // We have initiated a sync. negotiation
+ unsigned Allow:1; // Debug to defer initiating commands
+ unsigned OffLine:1; // Adapter has gone off line
+ unsigned Connected:1; // Actively on the bus
+ unsigned InternalReqInUse:1; // Internal request in use flag
+
+ } State;
+
+ struct { // Flags describing this adapter functionality
+
+ unsigned TargetMode:1; // Supports selection as a target
+ unsigned AEN:1; // Asynchronous event notification
+
+ unsigned Caching:1; // Adapter caches (either on board, or host side), and cache is enabled
+ unsigned HostSideCache:1; // Has host side cache (opposed to on board cache (6x00))
+
+ unsigned Identify:1; // Identify messages and therefore disc/reconnect
+ unsigned Synchronous:1; // Synchronous xfer
+ unsigned TaggedQueuing:1; // Tagged queuing
+ unsigned ScatterGather:1; // Scatter/gather xfers
+
+ unsigned OnBoardQueuing:1; // Has onboard request queue (don't confuse with tagged queuing)
+
+ } Supports;
+
+ struct { // Physical descriptors
+
+ unsigned BusType:4; // Support upto 16 host bus types (ISA, EISA, etc), see BT_xxx
+ unsigned Xfermode:3; // Data xfer mode (PIO, Bus master, ...), see XM_xxx
+
+ } Physical;
+
+
+ ADParmList Parms; // Either an array, or a pointer to an array
+
+ char *Name; // Adapter name
+
+ U8 SCSI_ID; // ID of this adapter
+ U8 ReqStarting; // Flag for state of issued command
+
+ U8 Sync_Period; // The best period (in SCSI terms) for sync. xfers
+ U8 Sync_Offset; // The best offset e can support
+
+ unsigned Max_TID; // Maximum target ID: 7, 15, or 31 for 8, 16, and 32 bit wide SCSI
+
+
+#if defined(KEEP_STATS)
+
+ U32 ReqsRequested; // Number of requests passed in, whether queued or not
+ U32 ReqsQueued; // Number of requests queued
+ U32 ReqsAccepted; // Number of requests accepted
+ U32 ReqsCompleted; // Number of requests completed (error or no)
+ U32 ReqsAborted; // Number of requests aborted via abort command
+ U32 DataInterrupts; // Number of times the DATA move ISR entered
+ U32 SBICInterrupts; // Number of times the SBIC ISR entered
+
+#endif // KEEP_STATS
+};
+
+
+// Bus type defines:
+#define BT_ISA 0 // ISA bus
+#define BT_EISA 1 // EISA bus
+#define BT_VESA 2 // VESA local bus
+#define BT_PCI 3 // PCI local bus
+#define BT_MC 4 // Micro channel
+#define BT_PCMCIA 5 // PC Memory Card International Association
+#define BT_ANY -1 // Match any bus type
+
+// Tranfer types supported: (Type to be used if multiple are supported):
+// Types 0-3 use virtual addresses, 4->* use physical:
+#define XM_PIO 0x01 // PIO transfer type
+#define XM_MEMORY 0x00 // Memory mapped xfers
+#define XM_DMAS 0x04 // System DMA, single xfer mode
+#define XM_DMAD 0x05 // System DMA, demand mode
+#define XM_MASTER24 0x06 // Bus mastering, 24 bits (< 16MB)
+#define XM_MASTER 0x07 // Bus mastering, 32+ bits (> 16MB)
+#define XM_PHYSICAL(Mode) (Mode >= 4) // Test for need physical memory
+
+// Defines for HA->State
+#define HA_BUSY 1 // There is stuff going on or pending
+#define HA_Reselecting 0x8 // In the process of reselecting
+#define HA_DataIn 0x10 // Data function is input to adapter
+#define HA_DataXfer 0x20 // Doing some data xfer; dir. defd. above
+#define HA_DoingSync 0x40 // We have initiated a sync. negotiation
+#define HA_Allow 0x80 // Debug to defer initiating commands
+#define HA_Connected 0x100 // Adapter is on the SCSI bus
+
+
+// HA.Service function codes:
+#define HA_INITIALIZE 0 // Initialize the adapter
+#define HA_START 1 // Start processing requests, if ready
+#define HA_STOP 2 // Stop accepting new requests
+#define HA_TICKLE 3 // New FIFO head entered, starti it if ready
+#define HA_TIMER 4 // Timer poll
+#define HA_LED 5 // Set LED to (Misc == 0) ? Off : On
+#define HA_INITIATE 6 // Initiate a SCSI request for the adapter
+#define HA_DATA_SETUP 7 // Begin data transfer
+#define HA_DATA_CMPLT 8 // End data transfer
+#define HA_RESET_BUS 9 // Reset adapters SCSI bus
+#define HA_PARM_CHANGE 10 // One or some of the HA or device parms has changed
+#define HA_REVERT_STATE 11 // Revert to state saved during init.
+#define HA_RESTORE_STATE 12 // Restore to run configuration
+#define HA_POWER_MODE 13 // Set power to (PARM) level: Down, low, normal
+#define HA_ABORT_REQ 32 // On board queuing only; Abort the request passed as parm
+#define HA_RESET_DEV 33 // On board queuing/autonomous only; Reset the target identified
+#define HA_PRE_QUEUE_REQ 34 // On board queuing only; Board is given chance to queue up request(s)
+ // passed Parm. Returns number of requests accepted, else the value below
+#define HA_IOCTL 48 // Adapter defined IOCTL; Parm points to IOCTL structure
+
+// Parms for HA_POWER_MODE
+// Note: A NORMAL_POWER signal may occur without first seeing a TO_LOW or
+// POWER_DOWN signal. NORMAL_POWER assumes system RAM is OK (i.e., the HA
+// structre), but the board is in an unknown state.
+#define HA_PARM_TO_POWER_DOWN 0 // Power level 0: going to loss of power
+#define HA_PARM_TO_LOW_POWER 1 // Request to set board to low power
+#define HA_PARM_NORMAL_POWER 2 // Power has been restored, RAM is OK, board is ??
+
+
+// Response codes from HA->Service(HA_DATA_SETUP):
+#define HAServiceResponse_UseByteIO (U32)-1 // -1 for byte I/O, Otherwise, return byte count
+
+// Response codes for HA_PRE_QUEUE_REQ; return the value below, or number of chained requests accepted:
+#define HAServiceResponse_NotAccepted 0
+
+
+// Class of requests: Used by the likes of BlowAwayRequests
+#define ACTIVE_REQUESTS 0x01
+#define PENDING_REQUESTS 0x02
+#define ALL_REQUESTS 0x03
+
+
+extern void AcceptReq(ADAPTER_PTR HA);
+extern void BlowAwayRequests(ADAPTER_PTR HA, int Which, U16 Status);
+extern void HAParmChange(ADAPTER_PTR HA);
+extern void QueueReq(ADAPTER_PTR HA, IO_REQ_PTR Req, int AtHead);
+extern void ReqDone(ADAPTER_PTR HA, IO_REQ_PTR Req);
+extern int Reselect(ADAPTER_PTR HA, const unsigned TID, const unsigned LUN, const unsigned QID);
+extern void StartNext(ADAPTER_PTR HA, int StartLevel);
+
+#define SL_APPL 1 // StartNext level for "application" context
+#define SL_ISR 2 // StartNext level for "interrupt" context
+
+
+// Stuff in the SCSILIB
+extern BOOLEAN AbortRequest(ADAPTER_PTR HA, DEVICE_PTR DevP, IO_REQ_PTR Req);
+extern int Initialize(void);
+
+typedef enum RequestType {RTNormalReq, RTGetInfoReq, RTAutoSenseReq, RTSyncNegReq} RequestType;
+extern void QueueInternalRequest(ADAPTER_PTR HA, IO_REQ_PTR Req, RequestType Type);
+
+#endif // __RQM_H__
diff --git a/private/ntos/miniport/always/scsi.c b/private/ntos/miniport/always/scsi.c
new file mode 100644
index 000000000..89c91ebdd
--- /dev/null
+++ b/private/ntos/miniport/always/scsi.c
@@ -0,0 +1,400 @@
+/* Copyright (C) 1991, 1992 by Always Technology Corporation.
+ This module contains information proprietary to
+ Always Technology Corporation, and is be treated as confidential.
+
+*/
+
+#include "environ.h"
+#include "rqm.h"
+#include "api.h"
+#include "apiscsi.h"
+#include "debug.h"
+
+/*
+ This function is called by the adapter/chip interrupt service routine
+ to handle going to SCSI bus free. This means that the bus has gone
+ to the free state, and the adpter is ready to start a new request.
+*/
+
+
+/* Called from interrupt context */
+void
+BusFree (ADAPTER_PTR HA, int StartLevel)
+{
+
+ HA->State.Busy = HA->State.DataIn = HA->State.DoingSync = FALSE;
+ HA->CurrDev = NILL;
+ HA->CurrReq = NILL;
+ HA->ReqCurrentCount = 0;
+ HA->ReqCurrentIndex = 0;
+ HA->Service(HA_LED, HA, (long)0);
+ StartNext(HA, StartLevel); /* Called from interrupt, so level = 2 */
+
+}
+
+
+
+/*
+ This functions is called by the adapter drivers when the detect a
+ bus reset. All requests in the accepted queues of the devices
+ attached to this adapter will be completed with a HAS_BADPHASE error
+
+ Called from interrupt context
+*/
+
+void
+SCSIBusHasReset (ADAPTER_PTR HA)
+{
+
+ BlowAwayRequests(HA, ACTIVE_REQUESTS, S_AD_RESET);
+ APINotifyReset(HA);
+ BusFree(HA, 2);
+
+}
+
+
+
+int
+SCSISendAbort (ADAPTER_PTR HA)
+{
+
+ HA->Ext->MO_Buff[0] = MSG_ABORT;
+ HA->Ext->MO_Index = 0;
+ HA->Ext->MO_Count = 1;
+ TRACE(0,("SCSISendAbort(): Abort message requested\n"));
+ return MI_SEND_MSG; /* Tell driver we have a message to send */
+
+}
+
+
+
+int
+SCSISendReject (ADAPTER_PTR HA)
+{
+
+ HA->Ext->MO_Buff[0] = MSG_REJECT;
+ HA->Ext->MO_Index = 0;
+ HA->Ext->MO_Count = 1;
+ TRACE(0, ("SCSISendReject(): Reject message requested\n"));
+ return MI_SEND_MSG; /* Tell driver we have a message to send */
+
+}
+
+
+
+LOCAL void REGPARMS
+SCSIAskSyncMsg (ADAPTER_PTR HA, BOOLEAN Initiate)
+{
+ U8 ALLOC_D *Buff = &HA->Ext->MO_Buff[HA->Ext->MO_Count];
+
+ *Buff++ = MSG_EXTD_MSG;
+ *Buff++ = 3;
+ *Buff++ = XMSG_SYNC_REQ;
+
+ *Buff++ = HA->Sync_Period;
+ *Buff = HA->Sync_Offset;
+
+ HA->Ext->MO_Count += 5;
+ HA->Ext->MO_Index = 0;
+ HA->State.DoingSync = Initiate;
+ HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.UseSync = 0;
+ TRACE(3,("SCSIAskSyncMsg(): Sync. request message created: %d/%d\n",
+ HA->Sync_Period, HA->Sync_Offset));
+
+}
+
+
+void
+SCSIMakeIdentify (ADAPTER_PTR HA, unsigned LUN, BOOLEAN AllowDisc)
+{
+
+ HA->Ext->MO_Buff[0] = MSG_IDENTIFY | LUN | (AllowDisc ? MSG_ALLOW_DISC : 0);
+ HA->Ext->MO_Index = 0;
+ HA->Ext->MO_Count = 1;
+ TRACE(3,("SCSIMakeIDentify(): Identify message (%02x) requested\n",
+ (unsigned)HA->Ext->MO_Buff[0]));
+
+ if (ReqState(HA->CurrReq).ReqType == RTSyncNegReq) { // Allow sync. xfers on this device?
+
+ SCSIAskSyncMsg(HA, TRUE); // Then build sync. message
+
+ }
+}
+
+
+
+LOCAL U32
+S32toU32 (U8 *b)
+{
+
+#if defined(NATIVE32)
+
+ return ( ((((U32)(b[0]) * 256) + (U32)(b[1])) * 256)
+ + (U32)(b[2])) * 256 + (U32)(b[3]);
+
+#else
+ struct {
+ U32 l;
+ U8 b[4];
+ } X32;
+
+ X32.b[0] = b[3];
+ X32.b[1] = b[2];
+ X32.b[2] = b[1];
+ X32.b[3] = b[0];
+ return X32.l;
+
+#endif
+}
+
+
+LOCAL int
+ExtdMessage(ADAPTER_PTR HA)
+{
+ I32 Offset;
+ unsigned char Resp = MSG_NOP;
+
+ TRACE(4,("Inerpret_MSG: Extended message\n"));
+ switch (HA->Ext->MI_Buff[2]) { /* Extened message code; length is in [1] */
+
+ case XMSG_MODIFY_PTR: /* Got a Modify data pointers request */
+
+ TRACE(0,("Interpret_MSG(): The rarely seen Modify Data Ptr message received\n"));
+ /* Make sure the length of the message is correct and that the signed offset is in range: */
+ if (HA->Ext->MI_Buff[1] != 5)
+ return SCSISendReject(HA);
+
+ Offset = S32toU32(&(HA->Ext->MI_Buff[3]));
+
+ // If the offset is less than zero (going to back up), then see if that
+ // would make index (the number of bytes xfered so far) less than 0;
+ // If offset > 0, then check to see if is greater than the number of
+ // bytes remaining:
+
+ if (Offset < 0) {
+
+ if (((U32)-Offset) > HA->ReqCurrentIndex)
+ return SCSISendReject(HA);
+
+ } else {
+
+ if ((U32)Offset > HA->ReqCurrentCount)
+ return SCSISendReject(HA);
+
+ }
+
+ HA->ReqCurrentIndex += Offset;
+ HA->ReqCurrentCount -= Offset;
+ Resp = MSG_NOP;
+ break;
+
+
+ case XMSG_SYNC_REQ:
+
+ /* Sync negotiaition request; may be a response to our request */
+ TRACE(4,("Interpret_MSG: sync. negotiation\n"));
+ if ((HA->Ext->MI_Buff[1] != 3) || !HA->Supports.Synchronous)
+ return SCSISendReject(HA);
+
+ HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.NeedSync = FALSE;
+
+ if (HA->State.DoingSync) { /* Did we initiate sync. neg? */
+
+ TRACE(4,(" Response to host initiated negotiation\n"));
+ HA->State.DoingSync = FALSE; /* then we are done */
+ Resp = MI_SYNC_RESP; /* We got a sync response */
+
+ } else { /* Else, respond */
+
+ TRACE(4,("Target initiated negotiation\n"));
+ SCSIAskSyncMsg(HA, FALSE); /* Request sync. negotiation be done */
+
+ /* use the values most suited for the adapter and target: */
+ if (HA->Sync_Period < HA->Ext->MI_Buff[3])
+ HA->Ext->MO_Buff[3] = HA->Ext->MI_Buff[3];
+
+ if (HA->Sync_Offset > HA->Ext->MI_Buff[4])
+ HA->Ext->MO_Buff[4] = HA->Ext->MI_Buff[4];
+ Resp = MI_SYNC_REQ; /* We got a sync req; so send resp */
+
+ }
+
+ HA->CurrDev->Sync_Period = HA->Ext->MI_Buff[3];
+ HA->CurrDev->Sync_Offset = HA->Ext->MI_Buff[4];
+ HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.UseSync = TRUE;
+ if (HA->Ext->MI_Buff[4] == 0) {
+
+ /* no sync. support; clear allowed flag; no handling of msg needed */
+ HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.AllowSync = FALSE;
+ HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.UseSync = FALSE;
+ Resp = MSG_NOP;
+
+ }
+
+ TRACE(4,("Using sync period of: %d and offset of: %d\n", (unsigned)HA->Ext->MI_Buff[3], (unsigned)HA->Ext->MI_Buff[4]));
+
+ }
+ return Resp;
+
+}
+
+
+int
+Interpret_MSG (ADAPTER_PTR HA)
+{
+ unsigned char Resp = HA->Ext->MI_Buff[0];
+
+ HA->Ext->MI_Count = HA->Ext->MI_Needed = 0; /* Reset for next time */
+ TRACE(3,("Interpret_MSG: 1st Message byte: %02x\n", HA->Ext->MI_Buff[0]));
+
+ if (HA->Ext->MI_Buff[0] & 0x80) /* Identify message? */
+ return 0x80; // Return identify code
+
+ switch (HA->Ext->MI_Buff[0]) {
+
+ case MSG_SAVE_PTR:
+
+ TRACE(5, ("Interpret_MSG(): Save Data Ptr, Saved index=%d\n", HA->ReqCurrentIndex));
+ ReqSavedIndex(HA->CurrReq) = HA->ReqCurrentIndex;
+ break;
+
+
+ case MSG_RESTORE_PTR:
+
+ HA->ReqCurrentIndex = ReqSavedIndex(HA->CurrReq);
+ HA->ReqCurrentCount = 0;
+ TRACE(5, ("Interpret_MSG(): Restore Data Ptr, Saved index=%d\n", HA->ReqCurrentIndex));
+ break;
+
+
+ case MSG_DISCONNECT:
+
+ ReqState(HA->CurrReq).ReselPending = TRUE;
+ ReqState(HA->CurrReq).Connected = FALSE;
+ HA->CurrReq = 0;
+ break;
+
+
+ case MSG_REJECT:
+
+ HA->Ext->MO_Count = HA->Ext->MO_Index = 0; /* Clear message out indicators */
+ if (HA->State.DoingSync) {
+
+ TRACE(2,("Synchronous negotiation rejected by target\n"));
+ HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.NeedSync = 0;
+ HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.AllowSync = 0;
+ HA->DevInfo[ReqTargetID(HA->CurrReq)].Flags.UseSync = 0;
+ HA->State.DoingSync = 0;
+
+ } else {
+
+ // See if the reject is in response to an Identify with LUN:
+ if ((HA->Ext->MO_Buff[0] & 0x80) && (HA->Ext->MO_Buff[0] & 7))
+ ReqAPIStatus(HA->CurrReq) = S_REQ_BADLUN;
+
+ }
+ break;
+
+
+ case MSG_EXTD_MSG:
+
+ Resp = ExtdMessage(HA);
+ break;
+
+
+ case MSG_COMPLETE:
+ case MSG_NOP:
+
+ break;
+
+
+ default:
+
+ TRACE(0, ("Interpret_MSG(): Unknown message: 0x%02x %02x %02x %02x\n", HA->Ext->MI_Buff[0], HA->Ext->MI_Buff[1], HA->Ext->MI_Buff[2], HA->Ext->MI_Buff[3]));
+ Resp = SCSISendReject(HA);
+ break;
+
+ }
+
+ return Resp;
+}
+
+
+LOCAL unsigned
+NewMessage (ADAPTER_PTR HA, unsigned char Msg)
+{
+
+ TRACE(4,("NewMessage(): %02x\n", Msg));
+ switch (Msg) {
+
+ case MSG_EXTD_MSG:
+
+ HA->Ext->MI_Count = -1; /* Special flag for first byte of extd. msg */
+ HA->Ext->MI_Needed = -1;
+ return MI_MORE;
+
+
+ default:
+
+ if ((Msg & 0xf0) == 0x20) { /* Two byte messages */
+
+ HA->Ext->MI_Buff[0] = Msg;
+ HA->Ext->MI_Count = 1;
+ HA->Ext->MI_Needed = 1; /* One more byte needed */
+ return MI_MORE;
+
+ } else
+ Msg = Interpret_MSG(HA);
+
+ break;
+ }
+ return Msg;
+}
+
+
+
+/* Called from interrupt context */
+int
+Receive_Msg (ADAPTER_PTR HA, unsigned char Msg)
+{
+ unsigned char NM;
+
+ TRACE(4,("Receive_Msg(): MI_Count = %d, Needed = %d\n", HA->Ext->MI_Count, HA->Ext->MI_Needed));
+ switch (HA->Ext->MI_Count) {
+
+ case 0: /* New first message byte */
+
+ HA->Ext->MI_Buff[0] = Msg;
+ NM = NewMessage(HA, Msg);
+ TRACE(5,("Receive_Msg(): NewMessage says: 0x%02x\n", NM));
+ return NM;
+
+
+ case -1: /* Second byte (length) of extended message */
+
+ TRACE(4,("Receive_Msg(): Extd msg length = %d\n", Msg));
+ if (Msg == 0) {
+
+ HA->Ext->MI_Needed = 0;
+ HA->Ext->MI_Buff[1] = 0;
+ HA->Ext->MI_Count = 0;
+ return SCSISendReject(HA);
+
+ }
+ HA->Ext->MI_Needed = Msg;
+ HA->Ext->MI_Buff[1] = Msg;
+ HA->Ext->MI_Count = 2;
+ return MI_MORE;
+
+
+ default: /* Subsequent bytes of multi-byte message */
+
+ HA->Ext->MI_Buff[HA->Ext->MI_Count++] = Msg;
+ if (--(HA->Ext->MI_Needed) == 0)
+ return Interpret_MSG(HA);
+ break;
+
+ }
+
+ return MI_MORE;
+}
diff --git a/private/ntos/miniport/always/sources b/private/ntos/miniport/always/sources
new file mode 100644
index 000000000..b0b66830f
--- /dev/null
+++ b/private/ntos/miniport/always/sources
@@ -0,0 +1,36 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=always
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+NTCPPFLAGS=/DIN2000 /DWINNT /DUSEFASTCALLS /DDEBUG_OFF
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+
+SOURCES=33c93.c adapters.c in2000.c ntenv.c ntmgr.c rqm.c scsi.c intrlreq.c always.rc
diff --git a/private/ntos/miniport/atapi/atapi.c b/private/ntos/miniport/atapi/atapi.c
new file mode 100644
index 000000000..35e8d6c1f
--- /dev/null
+++ b/private/ntos/miniport/atapi/atapi.c
@@ -0,0 +1,7983 @@
+/*++
+
+Copyright (c) 1993-6 Microsoft Corporation
+
+Module Name:
+
+ atapi.c
+
+Abstract:
+
+ This is the miniport driver for ATAPI IDE controllers.
+
+Author:
+
+ Mike Glass (MGlass)
+ Chuck Park (ChuckP)
+ Joe Dai (joedai)
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+ george C.(georgioc) Merged wtih Compaq code to make miniport driver function
+ with the 120MB floppy drive
+ Added support for MEDIA STATUS NOTIFICATION
+ Added support for SCSIOP_START_STOP_UNIT (eject media)
+
+ joedai PCI Bus Master IDE Support
+ ATA Passthrough (temporary solution)
+ LBA with ATA drive > 8G
+ PCMCIA IDE support
+ Native mode support
+
+--*/
+
+
+#include "miniport.h"
+#include "atapi.h" // includes scsi.h
+#include "ntdddisk.h"
+#include "ntddscsi.h"
+
+#include "intel.h"
+
+//
+// Logical unit extension
+//
+
+typedef struct _HW_LU_EXTENSION {
+ ULONG Reserved;
+} HW_LU_EXTENSION, *PHW_LU_EXTENSION;
+
+//
+// control DMA detection
+//
+ULONG AtapiPlaySafe = 0;
+
+//
+// PCI IDE Controller List
+//
+CONTROLLER_PARAMETERS
+PciControllerParameters[] = {
+ { PCIBus,
+ "8086", // Intel
+ 4,
+ "7111", // PIIX4 82371
+ 4,
+ 2, // NumberOfIdeBus
+ FALSE, // Dual FIFO
+ NULL,
+ IntelIsChannelEnabled
+ },
+ { PCIBus,
+ "8086", // Intel
+ 4,
+ "7010", // PIIX3 82371
+ 4,
+ 2, // NumberOfIdeBus
+ FALSE, // Dual FIFO
+ NULL,
+ IntelIsChannelEnabled
+ },
+ { PCIBus,
+ "8086", // Intel
+ 4,
+ "1230", // PIIX 82371
+ 4,
+ 2, // NumberOfIdeBus
+ FALSE, // Dual FIFO
+ NULL,
+ IntelIsChannelEnabled
+ },
+ { PCIBus,
+ "1095", // CMD
+ 4,
+ "0646", // 646
+ 4,
+ 2, // NumberOfIdeBus
+ FALSE, // Dual FIFO
+ NULL,
+ ChannelIsAlwaysEnabled
+ },
+ { PCIBus,
+ "10b9", // ALi (Acer)
+ 4,
+ "5219", // 5219
+ 4,
+ 2, // NumberOfIdeBus
+ FALSE, // Dual FIFO
+ NULL,
+ ChannelIsAlwaysEnabled
+ },
+ { PCIBus,
+ "1039", // SiS
+ 4,
+ "5513", // 5513
+ 4,
+ 2, // NumberOfIdeBus
+ FALSE, // Dual FIFO
+ NULL,
+ ChannelIsAlwaysEnabled
+ },
+ { PCIBus,
+ "0e11", // Compaq
+ 4,
+ "ae33", //
+ 4,
+ 2, // NumberOfIdeBus
+ FALSE, // Dual FIFO
+ NULL,
+ ChannelIsAlwaysEnabled
+ },
+ { PCIBus,
+ "10ad", // WinBond
+ 4,
+ "0105", // 105
+ 4,
+ 2, // NumberOfIdeBus
+ FALSE, // Dual FIFO
+ NULL,
+ ChannelIsAlwaysEnabled
+ },
+
+
+// Broken PCI controllers
+ { PCIBus,
+ "1095", // CMD
+ 4,
+ "0640", // 640
+ 4,
+ 2, // NumberOfIdeBus
+ TRUE, // Single FIFO
+ NULL,
+ ChannelIsAlwaysEnabled
+ },
+ { PCIBus,
+ "1039", // SiS
+ 4,
+ "0601", // ????
+ 4,
+ 2, // NumberOfIdeBus
+ TRUE, // Single FIFO
+ NULL,
+ ChannelIsAlwaysEnabled
+ }
+};
+#define NUMBER_OF_PCI_CONTROLLER (sizeof(PciControllerParameters) / sizeof(CONTROLLER_PARAMETERS))
+
+PSCSI_REQUEST_BLOCK
+BuildMechanismStatusSrb (
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId,
+ IN ULONG TargetId
+ );
+
+PSCSI_REQUEST_BLOCK
+BuildRequestSenseSrb (
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId,
+ IN ULONG TargetId
+ );
+
+VOID
+AtapiHwInitializeChanger (
+ IN PVOID HwDeviceExtension,
+ IN ULONG TargetId,
+ IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus
+ );
+
+ULONG
+AtapiSendCommand(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+AtapiZeroMemory(
+ IN PCHAR Buffer,
+ IN ULONG Count
+ );
+
+VOID
+AtapiHexToString (
+ ULONG Value,
+ PCHAR *Buffer
+ );
+
+LONG
+AtapiStringCmp (
+ PCHAR FirstStr,
+ PCHAR SecondStr,
+ ULONG Count
+ );
+
+BOOLEAN
+AtapiInterrupt(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+AtapiHwInitialize(
+ IN PVOID HwDeviceExtension
+ );
+
+ULONG
+IdeBuildSenseBuffer(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+IdeMediaStatus(
+ IN BOOLEAN EnableMSN,
+ IN PVOID HwDeviceExtension,
+ IN ULONG Channel
+ );
+
+VOID
+DeviceSpecificInitialize(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+PrepareForBusMastering(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+EnableBusMastering(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+SetBusMasterDetectionLevel (
+ IN PVOID HwDeviceExtension,
+ IN PCHAR userArgumentString
+ );
+
+BOOLEAN
+AtapiDeviceDMACapable (
+ IN PVOID HwDeviceExtension,
+ IN ULONG deviceNumber
+ );
+
+#if defined (xDBG)
+// Need to link to nt kernel
+void KeQueryTickCount(PLARGE_INTEGER c);
+LONGLONG lastTickCount = 0;
+#define DebugPrintTickCount() _DebugPrintTickCount (__LINE__)
+
+//
+// for performance tuning
+//
+void _DebugPrintTickCount (ULONG lineNumber)
+{
+ LARGE_INTEGER tickCount;
+
+ KeQueryTickCount(&tickCount);
+ DebugPrint ((1, "Line %u: CurrentTick = %u (%u ticks since last check)\n", lineNumber, tickCount.LowPart, (ULONG) (tickCount.QuadPart - lastTickCount)));
+ lastTickCount = tickCount.QuadPart;
+}
+#else
+#define DebugPrintTickCount()
+#endif //DBG
+
+
+
+BOOLEAN
+IssueIdentify(
+ IN PVOID HwDeviceExtension,
+ IN ULONG DeviceNumber,
+ IN ULONG Channel,
+ IN UCHAR Command,
+ IN BOOLEAN InterruptOff
+ )
+
+/*++
+
+Routine Description:
+
+ Issue IDENTIFY command to a device.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ DeviceNumber - Indicates which device.
+ Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY.
+ InterruptOff - should leave interrupt disabled
+
+Return Value:
+
+ TRUE if all goes well.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel] ;
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];
+ ULONG waitCount = 20000;
+ ULONG i,j;
+ UCHAR statusByte;
+ UCHAR signatureLow,
+ signatureHigh;
+ IDENTIFY_DATA fullIdentifyData;
+
+ DebugPrintTickCount();
+
+ //
+ // Select device 0 or 1.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)((DeviceNumber << 4) | 0xA0));
+
+ //
+ // Check that the status register makes sense.
+ //
+
+ GetBaseStatus(baseIoAddress1, statusByte);
+
+ if (Command == IDE_COMMAND_IDENTIFY) {
+
+ //
+ // Mask status byte ERROR bits.
+ //
+
+ statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX);
+
+ DebugPrint((1,
+ "IssueIdentify: Checking for IDE. Status (%x)\n",
+ statusByte));
+
+ //
+ // Check if register value is reasonable.
+ //
+
+ if (statusByte != IDE_STATUS_IDLE) {
+
+ //
+ // Reset the controller.
+ //
+
+ AtapiSoftReset(baseIoAddress1,DeviceNumber, InterruptOff);
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)((DeviceNumber << 4) | 0xA0));
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
+ signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
+
+ if (signatureLow == 0x14 && signatureHigh == 0xEB) {
+
+ //
+ // Device is Atapi.
+ //
+
+ DebugPrintTickCount();
+ return FALSE;
+ }
+
+ DebugPrint((1,
+ "IssueIdentify: Resetting controller.\n"));
+
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl,IDE_DC_RESET_CONTROLLER | IDE_DC_DISABLE_INTERRUPTS);
+ ScsiPortStallExecution(500 * 1000);
+ if (InterruptOff) {
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl, IDE_DC_DISABLE_INTERRUPTS);
+ } else {
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl, IDE_DC_REENABLE_CONTROLLER);
+ }
+
+
+ // We really should wait up to 31 seconds
+ // The ATA spec. allows device 0 to come back from BUSY in 31 seconds!
+ // (30 seconds for device 1)
+ do {
+
+ //
+ // Wait for Busy to drop.
+ //
+
+ ScsiPortStallExecution(100);
+ GetStatus(baseIoAddress1, statusByte);
+
+ } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)((DeviceNumber << 4) | 0xA0));
+
+ //
+ // Another check for signature, to deal with one model Atapi that doesn't assert signature after
+ // a soft reset.
+ //
+
+ signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
+ signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
+
+ if (signatureLow == 0x14 && signatureHigh == 0xEB) {
+
+ //
+ // Device is Atapi.
+ //
+
+ DebugPrintTickCount();
+ return FALSE;
+ }
+
+ statusByte &= ~IDE_STATUS_INDEX;
+
+ if (statusByte != IDE_STATUS_IDLE) {
+
+ //
+ // Give up on this.
+ //
+
+ DebugPrintTickCount();
+ return FALSE;
+ }
+
+ }
+
+ } else {
+
+ DebugPrint((1,
+ "IssueIdentify: Checking for ATAPI. Status (%x)\n",
+ statusByte));
+
+ }
+
+ //
+ // Load CylinderHigh and CylinderLow with number bytes to transfer.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, (0x200 >> 8));
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow, (0x200 & 0xFF));
+
+ for (j = 0; j < 2; j++) {
+
+ //
+ // Send IDENTIFY command.
+ //
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ ScsiPortWritePortUchar(&baseIoAddress1->Command, Command);
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ //
+ // Wait for DRQ.
+ //
+
+ for (i = 0; i < 4; i++) {
+
+ WaitForDrq(baseIoAddress1, statusByte);
+
+ if (statusByte & IDE_STATUS_DRQ) {
+
+ //
+ // Read status to acknowledge any interrupts generated.
+ //
+
+ GetBaseStatus(baseIoAddress1, statusByte);
+
+ //
+ // One last check for Atapi.
+ //
+
+
+ signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
+ signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
+
+ if (signatureLow == 0x14 && signatureHigh == 0xEB) {
+
+ //
+ // Device is Atapi.
+ //
+
+ DebugPrintTickCount();
+ return FALSE;
+ }
+
+ break;
+ }
+
+ if (Command == IDE_COMMAND_IDENTIFY) {
+
+ //
+ // Check the signature. If DRQ didn't come up it's likely Atapi.
+ //
+
+ signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
+ signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
+
+ if (signatureLow == 0x14 && signatureHigh == 0xEB) {
+
+ //
+ // Device is Atapi.
+ //
+
+ DebugPrintTickCount();
+ return FALSE;
+ }
+ }
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+ }
+
+ if (i == 4 && j == 0) {
+
+ //
+ // Device didn't respond correctly. It will be given one more chances.
+ //
+
+ DebugPrint((1,
+ "IssueIdentify: DRQ never asserted (%x). Error reg (%x)\n",
+ statusByte,
+ ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1)));
+
+ AtapiSoftReset(baseIoAddress1, DeviceNumber, InterruptOff);
+
+ GetStatus(baseIoAddress1,statusByte);
+
+ DebugPrint((1,
+ "IssueIdentify: Status after soft reset (%x)\n",
+ statusByte));
+
+ } else {
+
+ break;
+
+ }
+ }
+
+ //
+ // Check for error on really stupid master devices that assert random
+ // patterns of bits in the status register at the slave address.
+ //
+
+ if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) {
+ DebugPrintTickCount();
+ return FALSE;
+ }
+
+ DebugPrint((1,
+ "IssueIdentify: Status before read words %x\n",
+ statusByte));
+
+ //
+ // Suck out 256 words. After waiting for one model that asserts busy
+ // after receiving the Packet Identify command.
+ //
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ if (!(statusByte & IDE_STATUS_DRQ)) {
+ DebugPrintTickCount();
+ return FALSE;
+ }
+
+ ReadBuffer(baseIoAddress1,
+ (PUSHORT)&fullIdentifyData,
+ sizeof (fullIdentifyData) / 2);
+
+ //
+ // Check out a few capabilities / limitations of the device.
+ //
+
+ if (fullIdentifyData.SpecialFunctionsEnabled & 1) {
+
+ //
+ // Determine if this drive supports the MSN functions.
+ //
+
+ DebugPrint((2,"IssueIdentify: Marking drive %d as removable. SFE = %d\n",
+ Channel * 2 + DeviceNumber,
+ fullIdentifyData.SpecialFunctionsEnabled));
+
+
+ deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_REMOVABLE_DRIVE;
+ }
+
+ if (fullIdentifyData.MaximumBlockTransfer) {
+
+ //
+ // Determine max. block transfer for this device.
+ //
+
+ deviceExtension->MaximumBlockXfer[(Channel * 2) + DeviceNumber] =
+ (UCHAR)(fullIdentifyData.MaximumBlockTransfer & 0xFF);
+ }
+
+ ScsiPortMoveMemory(&deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber],&fullIdentifyData,sizeof(IDENTIFY_DATA2));
+
+ if (deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0x20 &&
+ Command != IDE_COMMAND_IDENTIFY) {
+
+ //
+ // This device interrupts with the assertion of DRQ after receiving
+ // Atapi Packet Command
+ //
+
+ deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_INT_DRQ;
+
+ DebugPrint((2,
+ "IssueIdentify: Device interrupts on assertion of DRQ.\n"));
+
+ } else {
+
+ DebugPrint((2,
+ "IssueIdentify: Device does not interrupt on assertion of DRQ.\n"));
+ }
+
+ if (((deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0xF00) == 0x100) &&
+ Command != IDE_COMMAND_IDENTIFY) {
+
+ //
+ // This is a tape.
+ //
+
+ deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_TAPE_DEVICE;
+
+ DebugPrint((2,
+ "IssueIdentify: Device is a tape drive.\n"));
+
+ } else {
+
+ DebugPrint((2,
+ "IssueIdentify: Device is not a tape drive.\n"));
+ }
+
+ //
+ // Work around for some IDE and one model Atapi that will present more than
+ // 256 bytes for the Identify data.
+ //
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ for (i = 0; i < 0x10000; i++) {
+
+ GetStatus(baseIoAddress1,statusByte);
+
+ if (statusByte & IDE_STATUS_DRQ) {
+
+ //
+ // Suck out any remaining bytes and throw away.
+ //
+
+ ScsiPortReadPortUshort(&baseIoAddress1->Data);
+
+ } else {
+
+ break;
+
+ }
+ }
+
+ DebugPrint((3,
+ "IssueIdentify: Status after read words (%x)\n",
+ statusByte));
+
+ DebugPrintTickCount();
+ return TRUE;
+
+} // end IssueIdentify()
+
+
+BOOLEAN
+SetDriveParameters(
+ IN PVOID HwDeviceExtension,
+ IN ULONG DeviceNumber,
+ IN ULONG Channel
+ )
+
+/*++
+
+Routine Description:
+
+ Set drive parameters using the IDENTIFY data.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ DeviceNumber - Indicates which device.
+
+Return Value:
+
+ TRUE if all goes well.
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel];
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];
+ PIDENTIFY_DATA2 identifyData = &deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber];
+ ULONG i;
+ UCHAR statusByte;
+
+ DebugPrint((1,
+ "SetDriveParameters: Number of heads %x\n",
+ identifyData->NumberOfHeads));
+
+ DebugPrint((1,
+ "SetDriveParameters: Sectors per track %x\n",
+ identifyData->SectorsPerTrack));
+
+ //
+ // Set up registers for SET PARAMETER command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((DeviceNumber << 4) | 0xA0) | (identifyData->NumberOfHeads - 1)));
+
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,
+ (UCHAR)identifyData->SectorsPerTrack);
+
+ //
+ // Send SET PARAMETER command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,
+ IDE_COMMAND_SET_DRIVE_PARAMETERS);
+
+ //
+ // Wait for up to 30 milliseconds for ERROR or command complete.
+ //
+
+ for (i=0; i<30 * 1000; i++) {
+
+ UCHAR errorByte;
+
+ GetStatus(baseIoAddress1, statusByte);
+
+ if (statusByte & IDE_STATUS_ERROR) {
+ errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
+ DebugPrint((1,
+ "SetDriveParameters: Error bit set. Status %x, error %x\n",
+ errorByte,
+ statusByte));
+
+ return FALSE;
+ } else if ((statusByte & ~IDE_STATUS_INDEX ) == IDE_STATUS_IDLE) {
+ break;
+ } else {
+ ScsiPortStallExecution(100);
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 30 * 1000) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+
+} // end SetDriveParameters()
+
+
+BOOLEAN
+AtapiResetController(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Reset IDE controller and/or Atapi device.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG numberChannels = deviceExtension->NumberChannels;
+ PIDE_REGISTERS_1 baseIoAddress1;
+ PIDE_REGISTERS_2 baseIoAddress2;
+ BOOLEAN result = FALSE;
+ ULONG i,j;
+ UCHAR statusByte;
+
+ DebugPrint((2,"AtapiResetController: Reset IDE\n"));
+
+ //
+ // Check and see if we are processing an internal srb
+ //
+ if (deviceExtension->OriginalSrb) {
+ deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
+ deviceExtension->OriginalSrb = NULL;
+ }
+
+ //
+ // Check if request is in progress.
+ //
+
+ if (deviceExtension->CurrentSrb) {
+
+ //
+ // Complete outstanding request with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ deviceExtension->CurrentSrb->PathId,
+ deviceExtension->CurrentSrb->TargetId,
+ deviceExtension->CurrentSrb->Lun,
+ (ULONG)SRB_STATUS_BUS_RESET);
+
+ //
+ // Clear request tracking fields.
+ //
+
+ deviceExtension->CurrentSrb = NULL;
+ deviceExtension->WordsLeft = 0;
+ deviceExtension->DataBuffer = NULL;
+
+ //
+ // Indicate ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ }
+
+ //
+ // Clear DMA
+ //
+ if (deviceExtension->DMAInProgress) {
+
+ for (j = 0; j < numberChannels; j++) {
+ UCHAR dmaStatus;
+
+ dmaStatus = ScsiPortReadPortUchar (&deviceExtension->BusMasterPortBase[j]->Status);
+ ScsiPortWritePortUchar (&deviceExtension->BusMasterPortBase[j]->Command, 0); // disable BusMastering
+ ScsiPortWritePortUchar (&deviceExtension->BusMasterPortBase[j]->Status,
+ (UCHAR) (dmaStatus & (BUSMASTER_DEVICE0_DMA_OK | BUSMASTER_DEVICE1_DMA_OK))); // clear interrupt/error
+ }
+ deviceExtension->DMAInProgress = FALSE;
+ }
+
+ //
+ // Clear expecting interrupt flag.
+ //
+
+ deviceExtension->ExpectingInterrupt = FALSE;
+ deviceExtension->RDP = FALSE;
+
+ for (j = 0; j < numberChannels; j++) {
+
+ baseIoAddress1 = deviceExtension->BaseIoAddress1[j];
+ baseIoAddress2 = deviceExtension->BaseIoAddress2[j];
+
+ //
+ // Do special processing for ATAPI and IDE disk devices.
+ //
+
+ for (i = 0; i < 2; i++) {
+
+ //
+ // Check if device present.
+ //
+
+ if (deviceExtension->DeviceFlags[i + (j * 2)] & DFLAGS_DEVICE_PRESENT) {
+
+ //
+ // Check for ATAPI disk.
+ //
+
+ if (deviceExtension->DeviceFlags[i + (j * 2)] & DFLAGS_ATAPI_DEVICE) {
+
+ //
+ // Issue soft reset and issue identify.
+ //
+
+ GetStatus(baseIoAddress1,statusByte);
+ DebugPrint((1,
+ "AtapiResetController: Status before Atapi reset (%x).\n",
+ statusByte));
+
+ AtapiSoftReset(baseIoAddress1,i, FALSE);
+
+ GetStatus(baseIoAddress1,statusByte);
+
+
+ if (statusByte == 0x0) {
+
+ IssueIdentify(HwDeviceExtension,
+ i,
+ j,
+ IDE_COMMAND_ATAPI_IDENTIFY,
+ FALSE);
+ } else {
+
+ DebugPrint((1,
+ "AtapiResetController: Status after soft reset %x\n",
+ statusByte));
+ }
+
+ } else {
+
+ //
+ // Write IDE reset controller bits.
+ //
+
+ IdeHardReset(baseIoAddress1, baseIoAddress2,result);
+
+ if (!result) {
+ return FALSE;
+ }
+
+ //
+ // Set disk geometry parameters.
+ //
+
+ if (!SetDriveParameters(HwDeviceExtension,
+ i,
+ j)) {
+
+ DebugPrint((1,
+ "AtapiResetController: SetDriveParameters failed\n"));
+ }
+
+ // re-enable MSN
+ IdeMediaStatus(TRUE, HwDeviceExtension, j * numberChannels + i);
+ }
+ }
+ }
+ }
+
+ //
+ // Call the HwInitialize routine to setup multi-block.
+ //
+
+ AtapiHwInitialize(HwDeviceExtension);
+
+ return TRUE;
+
+} // end AtapiResetController()
+
+
+
+ULONG
+MapError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps ATAPI and IDE errors to specific SRB statuses.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ SRB status
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
+ ULONG i;
+ UCHAR errorByte;
+ UCHAR srbStatus;
+ UCHAR scsiStatus;
+
+ //
+ // Read the error register.
+ //
+
+ errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
+ DebugPrint((1,
+ "MapError: Error register is %x\n",
+ errorByte));
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
+
+ switch (errorByte >> 4) {
+ case SCSI_SENSE_NO_SENSE:
+
+ DebugPrint((1,
+ "ATAPI: No sense information\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_RECOVERED_ERROR:
+
+ DebugPrint((1,
+ "ATAPI: Recovered error\n"));
+ scsiStatus = 0;
+ srbStatus = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSI_SENSE_NOT_READY:
+
+ DebugPrint((1,
+ "ATAPI: Device not ready\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_MEDIUM_ERROR:
+
+ DebugPrint((1,
+ "ATAPI: Media error\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_HARDWARE_ERROR:
+
+ DebugPrint((1,
+ "ATAPI: Hardware error\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_ILLEGAL_REQUEST:
+
+ DebugPrint((1,
+ "ATAPI: Illegal request\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_UNIT_ATTENTION:
+
+ DebugPrint((1,
+ "ATAPI: Unit attention\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_DATA_PROTECT:
+
+ DebugPrint((1,
+ "ATAPI: Data protect\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_BLANK_CHECK:
+
+ DebugPrint((1,
+ "ATAPI: Blank check\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case SCSI_SENSE_ABORTED_COMMAND:
+ DebugPrint((1,
+ "Atapi: Command Aborted\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ default:
+
+ DebugPrint((1,
+ "ATAPI: Invalid sense information\n"));
+ scsiStatus = 0;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+ }
+
+ } else {
+
+ scsiStatus = 0;
+ //
+ // Save errorByte,to be used by SCSIOP_REQUEST_SENSE.
+ //
+
+ deviceExtension->ReturningMediaStatus = errorByte;
+
+ if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) {
+ DebugPrint((1,
+ "IDE: Media change\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+
+ } else if (errorByte & IDE_ERROR_COMMAND_ABORTED) {
+ DebugPrint((1,
+ "IDE: Command abort\n"));
+ srbStatus = SRB_STATUS_ABORTED;
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ if (Srb->SenseInfoBuffer) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND;
+ senseBuffer->AdditionalSenseCode = 0;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ deviceExtension->ErrorCount++;
+
+ } else if (errorByte & IDE_ERROR_END_OF_MEDIA) {
+
+ DebugPrint((1,
+ "IDE: End of media\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+ if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED)){
+ deviceExtension->ErrorCount++;
+ }
+
+ } else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) {
+
+ DebugPrint((1,
+ "IDE: Illegal length\n"));
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ } else if (errorByte & IDE_ERROR_BAD_BLOCK) {
+
+ DebugPrint((1,
+ "IDE: Bad block\n"));
+ srbStatus = SRB_STATUS_ERROR;
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ if (Srb->SenseInfoBuffer) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
+ senseBuffer->AdditionalSenseCode = 0;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ } else if (errorByte & IDE_ERROR_ID_NOT_FOUND) {
+
+ DebugPrint((1,
+ "IDE: Id not found\n"));
+ srbStatus = SRB_STATUS_ERROR;
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ if (Srb->SenseInfoBuffer) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
+ senseBuffer->AdditionalSenseCode = 0;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ deviceExtension->ErrorCount++;
+
+ } else if (errorByte & IDE_ERROR_MEDIA_CHANGE) {
+
+ DebugPrint((1,
+ "IDE: Media change\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+
+ if (Srb->SenseInfoBuffer) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ } else if (errorByte & IDE_ERROR_DATA_ERROR) {
+
+ DebugPrint((1,
+ "IDE: Data error\n"));
+ scsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR;
+
+ if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED)){
+ deviceExtension->ErrorCount++;
+ }
+
+ //
+ // Build sense buffer
+ //
+
+ if (Srb->SenseInfoBuffer) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
+ senseBuffer->AdditionalSenseCode = 0;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+ }
+
+ if ((deviceExtension->ErrorCount >= MAX_ERRORS) &&
+ (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_USE_DMA))) {
+ deviceExtension->DWordIO = FALSE;
+ deviceExtension->MaximumBlockXfer[Srb->TargetId] = 0;
+
+ DebugPrint((1,
+ "MapError: Disabling 32-bit PIO and Multi-sector IOs\n"));
+
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError( HwDeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ SP_BAD_FW_WARNING,
+ 4);
+ //
+ // Reprogram to not use Multi-sector.
+ //
+
+ for (i = 0; i < 4; i++) {
+ UCHAR statusByte;
+
+ if (deviceExtension->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT &&
+ !(deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE)) {
+
+ //
+ // Select the device.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((i & 0x1) << 4) | 0xA0));
+
+ //
+ // Setup sector count to reflect the # of blocks.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,
+ 0);
+
+ //
+ // Issue the command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,
+ IDE_COMMAND_SET_MULTIPLE);
+
+ //
+ // Wait for busy to drop.
+ //
+
+ WaitOnBaseBusy(baseIoAddress1,statusByte);
+
+ //
+ // Check for errors. Reset the value to 0 (disable MultiBlock) if the
+ // command was aborted.
+ //
+
+ if (statusByte & IDE_STATUS_ERROR) {
+
+ //
+ // Read the error register.
+ //
+
+ errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
+
+ DebugPrint((1,
+ "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n",
+ statusByte,
+ errorByte));
+ //
+ // Adjust the devExt. value, if necessary.
+ //
+
+ deviceExtension->MaximumBlockXfer[i] = 0;
+
+ }
+
+ deviceExtension->DeviceParameters[i].IdeReadCommand = IDE_COMMAND_READ;
+ deviceExtension->DeviceParameters[i].IdeWriteCommand = IDE_COMMAND_WRITE;
+ deviceExtension->DeviceParameters[i].MaxWordPerInterrupt = 256;
+ deviceExtension->MaximumBlockXfer[i] = 0;
+ }
+ }
+ }
+ }
+
+
+ //
+ // Set SCSI status to indicate a check condition.
+ //
+
+ Srb->ScsiStatus = scsiStatus;
+
+ return srbStatus;
+
+} // end MapError()
+
+
+BOOLEAN
+AtapiHwInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress;
+ ULONG i;
+ UCHAR statusByte, errorByte;
+
+
+ for (i = 0; i < 4; i++) {
+ if (deviceExtension->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT) {
+
+ if (!(deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE)) {
+
+ //
+ // Enable media status notification
+ //
+
+ baseIoAddress = deviceExtension->BaseIoAddress1[i >> 1];
+
+ IdeMediaStatus(TRUE,HwDeviceExtension,i);
+
+ //
+ // If supported, setup Multi-block transfers.
+ //
+ if (deviceExtension->MaximumBlockXfer[i]) {
+
+ //
+ // Select the device.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->DriveSelect,
+ (UCHAR)(((i & 0x1) << 4) | 0xA0));
+
+ //
+ // Setup sector count to reflect the # of blocks.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->BlockCount,
+ deviceExtension->MaximumBlockXfer[i]);
+
+ //
+ // Issue the command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Command,
+ IDE_COMMAND_SET_MULTIPLE);
+
+ //
+ // Wait for busy to drop.
+ //
+
+ WaitOnBaseBusy(baseIoAddress,statusByte);
+
+ //
+ // Check for errors. Reset the value to 0 (disable MultiBlock) if the
+ // command was aborted.
+ //
+
+ if (statusByte & IDE_STATUS_ERROR) {
+
+ //
+ // Read the error register.
+ //
+
+ errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress + 1);
+
+ DebugPrint((1,
+ "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n",
+ statusByte,
+ errorByte));
+ //
+ // Adjust the devExt. value, if necessary.
+ //
+
+ deviceExtension->MaximumBlockXfer[i] = 0;
+
+ } else {
+ DebugPrint((2,
+ "AtapiHwInitialize: Using Multiblock on Device %d. Blocks / int - %d\n",
+ i,
+ deviceExtension->MaximumBlockXfer[i]));
+ }
+ }
+ } else if (!(deviceExtension->DeviceFlags[i] & DFLAGS_CHANGER_INITED)){
+
+ ULONG j;
+ BOOLEAN isSanyo = FALSE;
+ UCHAR vendorId[26];
+
+ //
+ // Attempt to identify any special-case devices - psuedo-atapi changers, atapi changers, etc.
+ //
+
+ for (j = 0; j < 13; j += 2) {
+
+ //
+ // Build a buffer based on the identify data.
+ //
+
+ vendorId[j] = ((PUCHAR)deviceExtension->IdentifyData[i].ModelNumber)[j + 1];
+ vendorId[j+1] = ((PUCHAR)deviceExtension->IdentifyData[i].ModelNumber)[j];
+ }
+
+ if (!AtapiStringCmp (vendorId, "CD-ROM CDR", 11)) {
+
+ //
+ // Inquiry string for older model had a '-', newer is '_'
+ //
+
+ if (vendorId[12] == 'C') {
+
+ //
+ // Torisan changer. Set the bit. This will be used in several places
+ // acting like 1) a multi-lun device and 2) building the 'special' TUR's.
+ //
+
+ deviceExtension->DeviceFlags[i] |= (DFLAGS_CHANGER_INITED | DFLAGS_SANYO_ATAPI_CHANGER);
+ deviceExtension->DiscsPresent[i] = 3;
+ isSanyo = TRUE;
+ }
+ }
+ }
+
+ //
+ // We need to get our device ready for action before
+ // returning from this function
+ //
+ // According to the atapi spec 2.5 or 2.6, an atapi device
+ // clears its status BSY bit when it is ready for atapi commands.
+ // However, some devices (Panasonic SQ-TC500N) are still
+ // not ready even when the status BSY is clear. They don't react
+ // to atapi commands.
+ //
+ // Since there is really no other indication that tells us
+ // the drive is really ready for action. We are going to check BSY
+ // is clear and then just wait for an arbitrary amount of time!
+ //
+ if (deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE) {
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[i >> 1];
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[i >> 1];
+ ULONG waitCount;
+
+ // have to get out of the loop sometime!
+ // 10000 * 100us = 1000,000us = 1000ms = 1s
+ waitCount = 10000;
+ GetStatus(baseIoAddress1, statusByte);
+ while ((statusByte & IDE_STATUS_BUSY) && waitCount) {
+ //
+ // Wait for Busy to drop.
+ //
+ ScsiPortStallExecution(100);
+ GetStatus(baseIoAddress1, statusByte);
+ waitCount--;
+ }
+
+ // 5000 * 100us = 500,000us = 500ms = 0.5s
+ waitCount = 5000;
+ do {
+ ScsiPortStallExecution(100);
+ } while (waitCount--);
+ }
+ }
+ }
+
+ return TRUE;
+
+} // end AtapiHwInitialize()
+
+
+VOID
+AtapiHwInitializeChanger (
+ IN PVOID HwDeviceExtension,
+ IN ULONG TargetId,
+ IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus)
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ if (MechanismStatus) {
+ deviceExtension->DiscsPresent[TargetId] = MechanismStatus->NumberAvailableSlots;
+ if (deviceExtension->DiscsPresent[TargetId] > 1) {
+ deviceExtension->DeviceFlags[TargetId] |= DFLAGS_ATAPI_CHANGER;
+ }
+ }
+ return;
+}
+
+
+
+BOOLEAN
+FindDevices(
+ IN PVOID HwDeviceExtension,
+ IN BOOLEAN AtapiOnly,
+ IN ULONG Channel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from AtapiFindController to identify
+ devices attached to an IDE controller.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ AtapiOnly - Indicates that routine should return TRUE only if
+ an ATAPI device is attached to the controller.
+
+Return Value:
+
+ TRUE - True if devices found.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel];
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];
+ BOOLEAN deviceResponded = FALSE,
+ skipSetParameters = FALSE;
+ ULONG waitCount = 10000;
+ ULONG deviceNumber;
+ ULONG i;
+ UCHAR signatureLow,
+ signatureHigh;
+ UCHAR statusByte;
+
+ DebugPrintTickCount();
+
+ //
+ // Clear expecting interrupt flag and current SRB field.
+ //
+
+ deviceExtension->ExpectingInterrupt = FALSE;
+ deviceExtension->CurrentSrb = NULL;
+
+ // We are about to talk to our devices before our interrupt handler is installed
+ // If our device uses sharable level sensitive interrupt, we may assert too
+ // many bogus interrupts
+ // Turn off device interrupt here
+ for (deviceNumber = 0; deviceNumber < 2; deviceNumber++) {
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)((deviceNumber << 4) | 0xA0));
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl, IDE_DC_DISABLE_INTERRUPTS);
+ }
+
+ //
+ // Search for devices.
+ //
+
+ for (deviceNumber = 0; deviceNumber < 2; deviceNumber++) {
+
+ //
+ // Select the device.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)((deviceNumber << 4) | 0xA0));
+
+ //
+ // Check here for some SCSI adapters that incorporate IDE emulation.
+ //
+
+ GetStatus(baseIoAddress1, statusByte);
+ if (statusByte == 0xFF) {
+ continue;
+ }
+
+ DebugPrintTickCount();
+
+ AtapiSoftReset(baseIoAddress1,deviceNumber, TRUE);
+
+ DebugPrintTickCount();
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ DebugPrintTickCount();
+
+ signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
+ signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
+
+ if (signatureLow == 0x14 && signatureHigh == 0xEB) {
+
+ //
+ // ATAPI signature found.
+ // Issue the ATAPI identify command if this
+ // is not for the crash dump utility.
+ //
+
+atapiIssueId:
+
+ if (!deviceExtension->DriverMustPoll) {
+
+ //
+ // Issue ATAPI packet identify command.
+ //
+
+ if (IssueIdentify(HwDeviceExtension,
+ deviceNumber,
+ Channel,
+ IDE_COMMAND_ATAPI_IDENTIFY,
+ TRUE)) {
+
+ //
+ // Indicate ATAPI device.
+ //
+
+ DebugPrint((1,
+ "FindDevices: Device %x is ATAPI\n",
+ deviceNumber));
+
+ deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_ATAPI_DEVICE;
+ deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_DEVICE_PRESENT;
+
+ deviceResponded = TRUE;
+
+ GetStatus(baseIoAddress1, statusByte);
+ if (statusByte & IDE_STATUS_ERROR) {
+ AtapiSoftReset(baseIoAddress1, deviceNumber, TRUE);
+ }
+
+
+ } else {
+
+ //
+ // Indicate no working device.
+ //
+
+ DebugPrint((1,
+ "FindDevices: Device %x not responding\n",
+ deviceNumber));
+
+ deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] &= ~DFLAGS_DEVICE_PRESENT;
+ }
+
+ }
+
+ } else {
+
+ //
+ // Issue IDE Identify. If an Atapi device is actually present, the signature
+ // will be asserted, and the drive will be recognized as such.
+ //
+
+ if (IssueIdentify(HwDeviceExtension,
+ deviceNumber,
+ Channel,
+ IDE_COMMAND_IDENTIFY,
+ TRUE)) {
+
+ //
+ // IDE drive found.
+ //
+
+
+ DebugPrint((1,
+ "FindDevices: Device %x is IDE\n",
+ deviceNumber));
+
+ deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_DEVICE_PRESENT;
+
+ if (!AtapiOnly) {
+ deviceResponded = TRUE;
+ }
+
+ //
+ // Indicate IDE - not ATAPI device.
+ //
+
+ deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] &= ~DFLAGS_ATAPI_DEVICE;
+
+
+ } else {
+
+ //
+ // Look to see if an Atapi device is present.
+ //
+
+ AtapiSoftReset(baseIoAddress1, deviceNumber, TRUE);
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
+ signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
+
+ if (signatureLow == 0x14 && signatureHigh == 0xEB) {
+ goto atapiIssueId;
+ }
+ }
+ }
+
+#if DBG
+ if (deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] & DFLAGS_DEVICE_PRESENT) {
+ {
+ ULONG i;
+ UCHAR string[41];
+
+ for (i=0; i<8; i+=2) {
+ string[i] = deviceExtension->IdentifyData[Channel * MAX_CHANNEL + deviceNumber].FirmwareRevision[i + 1];
+ string[i + 1] = deviceExtension->IdentifyData[Channel * MAX_CHANNEL + deviceNumber].FirmwareRevision[i];
+ }
+ string[i] = 0;
+ DebugPrint((1, "FindDevices: firmware version: %s\n", string));
+
+
+ for (i=0; i<40; i+=2) {
+ string[i] = deviceExtension->IdentifyData[Channel * MAX_CHANNEL + deviceNumber].ModelNumber[i + 1];
+ string[i + 1] = deviceExtension->IdentifyData[Channel * MAX_CHANNEL + deviceNumber].ModelNumber[i];
+ }
+ string[i] = 0;
+ DebugPrint((1, "FindDevices: model number: %s\n", string));
+ }
+ }
+#endif
+ }
+
+ for (i = 0; i < 2; i++) {
+ if ((deviceExtension->DeviceFlags[i + (Channel * 2)] & DFLAGS_DEVICE_PRESENT) &&
+ (!(deviceExtension->DeviceFlags[i + (Channel * 2)] & DFLAGS_ATAPI_DEVICE)) && deviceResponded) {
+
+ //
+ // This hideous hack is to deal with ESDI devices that return
+ // garbage geometry in the IDENTIFY data.
+ // This is ONLY for the crashdump environment as
+ // these are ESDI devices.
+ //
+
+ if (deviceExtension->IdentifyData[i].SectorsPerTrack ==
+ 0x35 &&
+ deviceExtension->IdentifyData[i].NumberOfHeads ==
+ 0x07) {
+
+ DebugPrint((1,
+ "FindDevices: Found nasty Compaq ESDI!\n"));
+
+ //
+ // Change these values to something reasonable.
+ //
+
+ deviceExtension->IdentifyData[i].SectorsPerTrack =
+ 0x34;
+ deviceExtension->IdentifyData[i].NumberOfHeads =
+ 0x0E;
+ }
+
+ if (deviceExtension->IdentifyData[i].SectorsPerTrack ==
+ 0x35 &&
+ deviceExtension->IdentifyData[i].NumberOfHeads ==
+ 0x0F) {
+
+ DebugPrint((1,
+ "FindDevices: Found nasty Compaq ESDI!\n"));
+
+ //
+ // Change these values to something reasonable.
+ //
+
+ deviceExtension->IdentifyData[i].SectorsPerTrack =
+ 0x34;
+ deviceExtension->IdentifyData[i].NumberOfHeads =
+ 0x0F;
+ }
+
+
+ if (deviceExtension->IdentifyData[i].SectorsPerTrack ==
+ 0x36 &&
+ deviceExtension->IdentifyData[i].NumberOfHeads ==
+ 0x07) {
+
+ DebugPrint((1,
+ "FindDevices: Found nasty UltraStor ESDI!\n"));
+
+ //
+ // Change these values to something reasonable.
+ //
+
+ deviceExtension->IdentifyData[i].SectorsPerTrack =
+ 0x3F;
+ deviceExtension->IdentifyData[i].NumberOfHeads =
+ 0x10;
+ skipSetParameters = TRUE;
+ }
+
+
+ if (!skipSetParameters) {
+
+ //
+ // Select the device.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)((i << 4) | 0xA0));
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ if (statusByte & IDE_STATUS_ERROR) {
+
+ //
+ // Reset the device.
+ //
+
+ DebugPrint((2,
+ "FindDevices: Resetting controller before SetDriveParameters.\n"));
+
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl,IDE_DC_RESET_CONTROLLER | IDE_DC_DISABLE_INTERRUPTS);
+ ScsiPortStallExecution(500 * 1000);
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl, IDE_DC_DISABLE_INTERRUPTS);
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)((i << 4) | 0xA0));
+
+ do {
+
+ //
+ // Wait for Busy to drop.
+ //
+
+ ScsiPortStallExecution(100);
+ GetStatus(baseIoAddress1, statusByte);
+
+ } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
+ }
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+ DebugPrint((2,
+ "FindDevices: Status before SetDriveParameters: (%x) (%x)\n",
+ statusByte,
+ ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect)));
+
+ //
+ // Use the IDENTIFY data to set drive parameters.
+ //
+
+ if (!SetDriveParameters(HwDeviceExtension,i,Channel)) {
+
+ DebugPrint((0,
+ "AtapHwInitialize: Set drive parameters for device %d failed\n",
+ i));
+
+ //
+ // Don't use this device as writes could cause corruption.
+ //
+
+ deviceExtension->DeviceFlags[i + Channel] = 0;
+ continue;
+
+ }
+ if (deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] & DFLAGS_REMOVABLE_DRIVE) {
+
+ //
+ // Pick up ALL IDE removable drives that conform to Yosemite V0.2...
+ //
+
+ AtapiOnly = FALSE;
+ }
+
+
+ //
+ // Indicate that a device was found.
+ //
+
+ if (!AtapiOnly) {
+ deviceResponded = TRUE;
+ }
+ }
+ }
+ }
+
+ //
+ // Make sure master device is selected on exit.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 0xA0);
+
+ //
+ // Reset the controller. This is a feeble attempt to leave the ESDI
+ // controllers in a state that ATDISK driver will recognize them.
+ // The problem in ATDISK has to do with timings as it is not reproducible
+ // in debug. The reset should restore the controller to its poweron state
+ // and give the system enough time to settle.
+ //
+
+ if (!deviceResponded) {
+
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl,IDE_DC_RESET_CONTROLLER | IDE_DC_DISABLE_INTERRUPTS);
+ ScsiPortStallExecution(50 * 1000);
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl,IDE_DC_REENABLE_CONTROLLER);
+ }
+
+ // Turn device interrupt back on
+ for (deviceNumber = 0; deviceNumber < 2; deviceNumber++) {
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)((deviceNumber << 4) | 0xA0));
+ // Clear any pending interrupts
+ GetStatus(baseIoAddress1, statusByte);
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl, IDE_DC_REENABLE_CONTROLLER);
+ }
+
+ DebugPrintTickCount();
+
+ return deviceResponded;
+
+} // end FindDevices()
+
+
+ULONG
+AtapiParseArgumentString(
+ IN PCHAR String,
+ IN PCHAR KeyWord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will parse the string for a match on the keyword, then
+ calculate the value for the keyword and return it to the caller.
+
+Arguments:
+
+ String - The ASCII string to parse.
+ KeyWord - The keyword for the value desired.
+
+Return Values:
+
+ Zero if value not found
+ Value converted from ASCII to binary.
+
+--*/
+
+{
+ PCHAR cptr;
+ PCHAR kptr;
+ ULONG value;
+ ULONG stringLength = 0;
+ ULONG keyWordLength = 0;
+ ULONG index;
+
+ if (!String) {
+ return 0;
+ }
+ if (!KeyWord) {
+ return 0;
+ }
+
+ //
+ // Calculate the string length and lower case all characters.
+ //
+
+ cptr = String;
+ while (*cptr) {
+ if (*cptr >= 'A' && *cptr <= 'Z') {
+ *cptr = *cptr + ('a' - 'A');
+ }
+ cptr++;
+ stringLength++;
+ }
+
+ //
+ // Calculate the keyword length and lower case all characters.
+ //
+
+ cptr = KeyWord;
+ while (*cptr) {
+
+ if (*cptr >= 'A' && *cptr <= 'Z') {
+ *cptr = *cptr + ('a' - 'A');
+ }
+ cptr++;
+ keyWordLength++;
+ }
+
+ if (keyWordLength > stringLength) {
+
+ //
+ // Can't possibly have a match.
+ //
+
+ return 0;
+ }
+
+ //
+ // Now setup and start the compare.
+ //
+
+ cptr = String;
+
+ContinueSearch:
+
+ //
+ // The input string may start with white space. Skip it.
+ //
+
+ while (*cptr == ' ' || *cptr == '\t') {
+ cptr++;
+ }
+
+ if (*cptr == '\0') {
+
+ //
+ // end of string.
+ //
+
+ return 0;
+ }
+
+ kptr = KeyWord;
+ while (*cptr++ == *kptr++) {
+
+ if (*(cptr - 1) == '\0') {
+
+ //
+ // end of string
+ //
+
+ return 0;
+ }
+ }
+
+ if (*(kptr - 1) == '\0') {
+
+ //
+ // May have a match backup and check for blank or equals.
+ //
+
+ cptr--;
+ while (*cptr == ' ' || *cptr == '\t') {
+ cptr++;
+ }
+
+ //
+ // Found a match. Make sure there is an equals.
+ //
+
+ if (*cptr != '=') {
+
+ //
+ // Not a match so move to the next semicolon.
+ //
+
+ while (*cptr) {
+ if (*cptr++ == ';') {
+ goto ContinueSearch;
+ }
+ }
+ return 0;
+ }
+
+ //
+ // Skip the equals sign.
+ //
+
+ cptr++;
+
+ //
+ // Skip white space.
+ //
+
+ while ((*cptr == ' ') || (*cptr == '\t')) {
+ cptr++;
+ }
+
+ if (*cptr == '\0') {
+
+ //
+ // Early end of string, return not found
+ //
+
+ return 0;
+ }
+
+ if (*cptr == ';') {
+
+ //
+ // This isn't it either.
+ //
+
+ cptr++;
+ goto ContinueSearch;
+ }
+
+ value = 0;
+ if ((*cptr == '0') && (*(cptr + 1) == 'x')) {
+
+ //
+ // Value is in Hex. Skip the "0x"
+ //
+
+ cptr += 2;
+ for (index = 0; *(cptr + index); index++) {
+
+ if (*(cptr + index) == ' ' ||
+ *(cptr + index) == '\t' ||
+ *(cptr + index) == ';') {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
+ value = (16 * value) + (*(cptr + index) - '0');
+ } else {
+ if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
+ value = (16 * value) + (*(cptr + index) - 'a' + 10);
+ } else {
+
+ //
+ // Syntax error, return not found.
+ //
+ return 0;
+ }
+ }
+ }
+ } else {
+
+ //
+ // Value is in Decimal.
+ //
+
+ for (index = 0; *(cptr + index); index++) {
+
+ if (*(cptr + index) == ' ' ||
+ *(cptr + index) == '\t' ||
+ *(cptr + index) == ';') {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
+ value = (10 * value) + (*(cptr + index) - '0');
+ } else {
+
+ //
+ // Syntax error return not found.
+ //
+ return 0;
+ }
+ }
+ }
+
+ return value;
+ } else {
+
+ //
+ // Not a match check for ';' to continue search.
+ //
+
+ while (*cptr) {
+ if (*cptr++ == ';') {
+ goto ContinueSearch;
+ }
+ }
+
+ return 0;
+ }
+}
+
+
+
+BOOLEAN
+AtapiAllocateIoBase (
+ IN PVOID HwDeviceExtension,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PFIND_STATE FindState,
+ OUT PIDE_REGISTERS_1 CmdLogicalBasePort[2],
+ OUT PIDE_REGISTERS_2 CtrlLogicalBasePort[2],
+ OUT PIDE_BUS_MASTER_REGISTERS BmLogicalBasePort[2],
+ OUT ULONG *NumIdeChannel,
+ OUT PBOOLEAN PreConfig
+)
+/*++
+
+Routine Description:
+
+ Return ide controller io addresses for device detection
+
+ This function populate these PORT_CONFIGURATION_INFORMATION
+ entries
+
+ 1st ACCESS_RANGE - first channel command block register base
+ 2nd ACCESS_RANGE - first channel control block register base
+ 3rd ACCESS_RANGE - second channel command block register base
+ 4th ACCESS_RANGE - second channel control block register base
+ 5th ACCESS_RANGE - first channel bus master register base
+ 6th ACCESS_RANGE - second channel bus master register base
+
+ InterruptMode - first channel interrupt mode
+ BusInterruptLevel - first channel interrupt level
+ InterruptMode2 - second channel interrupt mode
+ BusInterruptLevel2 - second channel interrupt level
+ AdapterInterfaceType
+ AtdiskPrimaryClaimed
+ AtdiskSecondaryClaimed
+
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ArgumentString - registry user arugment
+ ConfigInfo = Scsi Port Config. Structure
+ FindState - Keep track of what addresses has been returned
+ CmdLogicalBasePort - command block register logical base address
+ CtrlLogicalBasePort - control block register logical base address
+ BmLogicalBasePort - bus master register logical base address
+ NumIdeChannel - number of IDE channel base address returned
+ PreConfig - the reutrned address is user configured
+
+Return Value:
+
+ TRUE - io address is returned.
+ FASLE - no more io address to return.
+
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ ULONG cmdBasePort[2] = {0, 0};
+ ULONG ctrlBasePort[2] = {0, 0};
+ ULONG bmBasePort[2] = {0, 0};
+ BOOLEAN getDeviceBaseFailed;
+
+
+ CmdLogicalBasePort[0] = 0;
+ CmdLogicalBasePort[1] = 0;
+ CtrlLogicalBasePort[0] = 0;
+ CtrlLogicalBasePort[1] = 0;
+ BmLogicalBasePort[0] = 0;
+ BmLogicalBasePort[1] = 0;
+ *PreConfig = FALSE;
+
+ //
+ // check for pre-config controller (pcmcia)
+ //
+ cmdBasePort[0] = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
+ ctrlBasePort[0] = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
+ if (cmdBasePort[0] != 0) {
+ *PreConfig = TRUE;
+ *NumIdeChannel = 1;
+
+ if (!ctrlBasePort[0]) {
+ //
+ // The pre-config init is really made for pcmcia ata disk
+ // When we get pre-config data, both io access ranges are lumped together
+ // the command registers are mapped to the first 7 address locations, and
+ // the control registers are mapped to the 0xE th location
+ //
+ ctrlBasePort[0] = cmdBasePort[0] + 0xe;
+ }
+
+ DebugPrint ((2, "AtapiAllocateIoBase: found pre-config pcmcia controller\n"));
+ }
+
+ //
+ // check for user defined controller (made for IBM Caroline ppc)
+ //
+ if ((cmdBasePort[0] == 0) && ArgumentString) {
+
+ ULONG irq;
+
+ irq = AtapiParseArgumentString(ArgumentString, "Interrupt");
+ cmdBasePort[0] = AtapiParseArgumentString(ArgumentString, "BaseAddress");
+ if (irq && cmdBasePort[0]) {
+
+ *NumIdeChannel = 1;
+
+ // the control register offset is implied!!
+ ctrlBasePort[0] = cmdBasePort[0] + 0x206;
+
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->BusInterruptLevel = irq;
+
+ DebugPrint ((2, "AtapiAllocateIoBase: found user config controller\n"));
+ }
+ }
+
+ //
+ // PCI controller
+ //
+ if (cmdBasePort[0] == 0 &&
+ (ConfigInfo->AdapterInterfaceType == Isa)) {
+
+ PCI_SLOT_NUMBER pciSlot;
+ PUCHAR vendorStrPtr;
+ PUCHAR deviceStrPtr;
+ UCHAR vendorString[5];
+ UCHAR deviceString[5];
+
+ ULONG pciBusNumber;
+ ULONG slotNumber;
+ ULONG logicalDeviceNumber;
+ ULONG ideChannel;
+ PCI_COMMON_CONFIG pciData;
+ ULONG cIndex;
+ UCHAR bmStatus;
+ BOOLEAN foundController;
+
+ pciBusNumber = FindState->BusNumber;
+ slotNumber = FindState->SlotNumber;
+ logicalDeviceNumber = FindState->LogicalDeviceNumber;
+ ideChannel = FindState->IdeChannel;
+ foundController = FALSE;
+ *NumIdeChannel = 1;
+
+ for (;pciBusNumber < 256 && !(cmdBasePort[0]); pciBusNumber++, slotNumber=logicalDeviceNumber=0) {
+ pciSlot.u.AsULONG = 0;
+
+ for (;slotNumber < PCI_MAX_DEVICES && !(cmdBasePort[0]); slotNumber++, logicalDeviceNumber=0) {
+ pciSlot.u.bits.DeviceNumber = slotNumber;
+
+ for (;logicalDeviceNumber < PCI_MAX_FUNCTION && !(cmdBasePort[0]); logicalDeviceNumber++, ideChannel=0) {
+
+ pciSlot.u.bits.FunctionNumber = logicalDeviceNumber;
+
+ for (;ideChannel < MAX_CHANNEL && !(cmdBasePort[0]); ideChannel++) {
+
+ if (!GetPciBusData(HwDeviceExtension,
+ pciBusNumber,
+ pciSlot,
+ &pciData,
+ offsetof (PCI_COMMON_CONFIG, DeviceSpecific))) {
+ break;
+ }
+
+ if (pciData.VendorID == PCI_INVALID_VENDORID) {
+ break;
+ }
+
+ //
+ // Translate hex ids to strings.
+ //
+ vendorStrPtr = vendorString;
+ deviceStrPtr = deviceString;
+ AtapiHexToString(pciData.VendorID, &vendorStrPtr);
+ AtapiHexToString(pciData.DeviceID, &deviceStrPtr);
+
+ DebugPrint((2,
+ "AtapiAllocateIoBase: Bus %x Slot %x Function %x Vendor %s Product %s\n",
+ pciBusNumber,
+ slotNumber,
+ logicalDeviceNumber,
+ vendorString,
+ deviceString));
+
+ //
+ // Search for controller we know about
+ //
+ ConfigInfo->AdapterInterfaceType = Isa;
+ foundController = FALSE;
+ *NumIdeChannel = 1;
+ for (cIndex = 0; cIndex < NUMBER_OF_PCI_CONTROLLER; cIndex++) {
+
+ if ((!AtapiStringCmp(vendorString,
+ FindState->ControllerParameters[cIndex].VendorId,
+ FindState->ControllerParameters[cIndex].VendorIdLength) &&
+ !AtapiStringCmp(deviceString,
+ FindState->ControllerParameters[cIndex].DeviceId,
+ FindState->ControllerParameters[cIndex].DeviceIdLength))) {
+
+ foundController = TRUE;
+ deviceExtension->BMTimingControl = FindState->ControllerParameters[cIndex].TimingControl;
+ deviceExtension->IsChannelEnabled = FindState->ControllerParameters[cIndex].IsChannelEnabled;
+
+ if (FindState->ControllerParameters[cIndex].SingleFIFO) {
+ DebugPrint ((0, "AtapiAllocateIoBase: hardcoded single FIFO pci controller\n"));
+ *NumIdeChannel = 2;
+ }
+ break;
+ }
+ }
+
+ //
+ // Look for generic IDE controller
+ //
+ if (cIndex >= NUMBER_OF_PCI_CONTROLLER) {
+ if (pciData.BaseClass == 0x1) { // Mass Storage Device
+ if (pciData.SubClass == 0x1) { // IDE Controller
+
+ DebugPrint ((0, "AtapiAllocateIoBase: found an unknown pci ide controller\n"));
+ deviceExtension->BMTimingControl = NULL;
+ deviceExtension->IsChannelEnabled = ChannelIsAlwaysEnabled;
+ foundController = TRUE;
+ }
+ }
+ }
+
+ if (foundController) {
+
+ DebugPrint ((2, "AtapiAllocateIoBase: found pci ide controller 0x%4x 0x%4x\n", pciData.VendorID, pciData.DeviceID));
+
+ GetPciBusData(HwDeviceExtension,
+ pciBusNumber,
+ pciSlot,
+ &pciData,
+ sizeof (PCI_COMMON_CONFIG));
+
+ //
+ // Record pci device location
+ //
+ deviceExtension->PciBusNumber = pciBusNumber;
+ deviceExtension->PciDeviceNumber = slotNumber;
+ deviceExtension->PciLogDevNumber = logicalDeviceNumber;
+
+#if defined (DBG)
+ {
+ ULONG i, j;
+
+ DebugPrint ((2, "AtapiAllocateIoBase: PCI Configuration Data\n"));
+ for (i=0; i<sizeof(PCI_COMMON_CONFIG); i+=16) {
+ DebugPrint ((2, "AtapiAllocateIoBase: "));
+ for (j=0; j<16; j++) {
+ if ((i + j) < sizeof(PCI_COMMON_CONFIG)) {
+ DebugPrint ((2, "%02x ", ((PUCHAR)&pciData)[i + j]));
+ } else {
+ break;
+ }
+ }
+ DebugPrint ((2, "\n"));
+ }
+ }
+#endif //DBG
+
+ if (!AtapiPlaySafe) {
+ //
+ // Try to turn on the bus master bit in PCI space if it is not already on
+ //
+ if ((pciData.Command & PCI_ENABLE_BUS_MASTER) == 0) {
+
+ DebugPrint ((0, "ATAPI: Turning on PCI Bus Master bit\n"));
+
+ pciData.Command |= PCI_ENABLE_BUS_MASTER;
+
+ SetPciBusData (HwDeviceExtension,
+ pciBusNumber,
+ pciSlot,
+ &pciData.Command,
+ offsetof (PCI_COMMON_CONFIG, Command),
+ sizeof(pciData.Command));
+
+ GetPciBusData(HwDeviceExtension,
+ pciBusNumber,
+ pciSlot,
+ &pciData,
+ offsetof (PCI_COMMON_CONFIG, DeviceSpecific)
+ );
+
+ if (pciData.Command & PCI_ENABLE_BUS_MASTER) {
+ DebugPrint ((0, "ATAPI: If we play safe, we would NOT detect this IDE controller is busmaster capable\n"));
+ }
+ }
+ }
+
+ //
+ // Check to see if the controller is bus master capable
+ //
+ bmStatus = 0;
+ if ((pciData.Command & PCI_ENABLE_BUS_MASTER) &&
+ (pciData.ProgIf & 0x80) &&
+ deviceExtension->UseBusMasterController) {
+
+ PIDE_BUS_MASTER_REGISTERS bmLogicalBasePort;
+
+ bmBasePort[0] = pciData.u.type0.BaseAddresses[4] & 0xfffffffc;
+ if ((bmBasePort[0] != 0) && (bmBasePort[0] != 0xffffffff)) {
+
+ bmLogicalBasePort = (PIDE_BUS_MASTER_REGISTERS) ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(bmBasePort[0]),
+ 8,
+ TRUE);
+
+ if (bmLogicalBasePort) {
+
+ // Some controller (ALi M5219) doesn't implement the readonly simplex bit
+ // We will try to clear it. If it works, we will assume simplex bit
+ // is not set
+ bmStatus = ScsiPortReadPortUchar(&bmLogicalBasePort->Status);
+ ScsiPortWritePortUchar(&bmLogicalBasePort->Status, (UCHAR) (bmStatus & ~BUSMASTER_DMA_SIMPLEX_BIT));
+
+
+ bmStatus = ScsiPortReadPortUchar(&bmLogicalBasePort->Status);
+ ScsiPortFreeDeviceBase(HwDeviceExtension, bmLogicalBasePort);
+
+ DebugPrint ((2, "AtapiAllocateIoBase: controller is capable of bus mastering\n"));
+ } else {
+ bmBasePort[0] = 0;
+ DebugPrint ((2, "AtapiAllocateIoBase: controller is NOT capable of bus mastering\n"));
+ }
+ } else {
+ bmBasePort[0] = 0;
+ DebugPrint ((2, "AtapiAllocateIoBase: controller is NOT capable of bus mastering\n"));
+ }
+
+ } else {
+ bmBasePort[0] = 0;
+ DebugPrint ((2, "AtapiAllocateIoBase: controller is NOT capable of bus mastering\n"));
+ }
+
+ if (bmStatus & BUSMASTER_DMA_SIMPLEX_BIT) {
+ DebugPrint ((0, "AtapiAllocateIoBase: simplex bit is set. single FIFO pci controller\n"));
+ *NumIdeChannel = 2;
+ }
+
+ if (*NumIdeChannel == 2) {
+ if (!((*deviceExtension->IsChannelEnabled) (&pciData,
+ 0) &&
+ (*deviceExtension->IsChannelEnabled) (&pciData,
+ 0))) {
+ //
+ // if we have a single FIFO controller, but one of the channels
+ // is not turned on. We don't need to sync. access the both channels
+ // We can pretend we have a single channel controller
+ //
+ *NumIdeChannel = 1;
+ }
+ }
+
+ //
+ // figure out what io address the controller is using
+ // If it is in native mode, get the address out of the PCI
+ // config space. If it is in legacy mode, it will be hard
+ // wired to use standard primary (0x1f0) or secondary
+ // (0x170) channel addresses
+ //
+ if (ideChannel == 0) {
+
+ if ((*deviceExtension->IsChannelEnabled) (&pciData,
+ ideChannel)) {
+
+ //
+ // check to see if the controller has a single FIFO for both
+ // IDE channel
+ //
+ if (bmStatus & BUSMASTER_DMA_SIMPLEX_BIT) {
+ DebugPrint ((0, "AtapiAllocateIoBase: simplex bit is set. single FIFO pci controller\n"));
+ *NumIdeChannel = 2;
+ }
+
+ if ((pciData.ProgIf & 0x3) == 0x3) {
+ // Native Mode
+ cmdBasePort[0] = pciData.u.type0.BaseAddresses[0] & 0xfffffffc;
+ ctrlBasePort[0] = (pciData.u.type0.BaseAddresses[1] & 0xfffffffc) + 2;
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+ ConfigInfo->BusInterruptVector =
+ ConfigInfo->BusInterruptLevel = pciData.u.type0.InterruptLine;
+ ConfigInfo->AdapterInterfaceType = PCIBus;
+
+ } else {
+ // Legacy Mode
+ cmdBasePort[0] = 0x1f0;
+ ctrlBasePort[0] = 0x1f0 + 0x206;
+
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->BusInterruptLevel = 14;
+ }
+ }
+ if (*NumIdeChannel == 2) {
+
+ // grab both channels
+ ideChannel++;
+
+ if ((*deviceExtension->IsChannelEnabled) (&pciData,
+ ideChannel)) {
+
+ if (bmBasePort[0]) {
+ bmBasePort[1] = bmBasePort[0] + 8;
+ }
+
+ if ((pciData.ProgIf & 0xc) == 0xc) {
+ // Native Mode
+ cmdBasePort[1] = pciData.u.type0.BaseAddresses[2] & 0xfffffffc;
+ ctrlBasePort[1] = (pciData.u.type0.BaseAddresses[3] & 0xfffffffc) + 2;
+ } else {
+ // Legacy Mode
+ cmdBasePort[1] = 0x170;
+ ctrlBasePort[1] = 0x170 + 0x206;
+
+ ConfigInfo->InterruptMode2 = Latched;
+ ConfigInfo->BusInterruptLevel2 = 15;
+ }
+ }
+ }
+ } else if (ideChannel == 1) {
+
+ if ((*deviceExtension->IsChannelEnabled) (&pciData,
+ ideChannel)) {
+
+ if (bmBasePort[0]) {
+ bmBasePort[0] += 8;
+ }
+
+ if ((pciData.ProgIf & 0xc) == 0xc) {
+ // Native Mode
+ cmdBasePort[0] = pciData.u.type0.BaseAddresses[2] & 0xfffffffc;
+ ctrlBasePort[0] = (pciData.u.type0.BaseAddresses[3] & 0xfffffffc) + 2;
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+ ConfigInfo->BusInterruptVector =
+ ConfigInfo->BusInterruptLevel = pciData.u.type0.InterruptLine;
+ ConfigInfo->AdapterInterfaceType = PCIBus;
+
+ } else {
+ // Legacy Mode
+ cmdBasePort[0] = 0x170;
+ ctrlBasePort[0] = 0x170 + 0x206;
+
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->BusInterruptLevel = 15;
+ }
+ }
+ }
+ } else {
+ ideChannel = MAX_CHANNEL;
+ }
+ if (cmdBasePort[0])
+ break;
+ }
+ if (cmdBasePort[0])
+ break;
+ }
+ if (cmdBasePort[0])
+ break;
+ }
+ if (cmdBasePort[0])
+ break;
+ }
+ FindState->BusNumber = pciBusNumber;
+ FindState->SlotNumber = slotNumber;
+ FindState->LogicalDeviceNumber = logicalDeviceNumber;
+ FindState->IdeChannel = ideChannel + 1;
+ }
+
+ //
+ // look for legacy controller
+ //
+ if (cmdBasePort[0] == 0) {
+ ULONG i;
+
+ for (i = 0; FindState->DefaultIoPort[i]; i++) {
+ if (FindState->IoAddressUsed[i] != TRUE) {
+
+ *NumIdeChannel = 1;
+ cmdBasePort[0] = FindState->DefaultIoPort[i];
+ ctrlBasePort[0] = FindState->DefaultIoPort[i] + 0x206;
+ bmBasePort[0] = 0;
+
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->BusInterruptLevel = FindState->DefaultInterrupt[i];
+ break;
+ }
+ }
+ }
+
+ if (cmdBasePort[0]) {
+ ULONG i;
+
+ // Mark io addresses used
+ for (i = 0; FindState->DefaultIoPort[i]; i++) {
+ if (FindState->DefaultIoPort[i] == cmdBasePort[0]) {
+ FindState->IoAddressUsed[i] = TRUE;
+ }
+ if (FindState->DefaultIoPort[i] == cmdBasePort[1]) {
+ FindState->IoAddressUsed[i] = TRUE;
+ }
+ }
+
+
+ if (cmdBasePort[0] == 0x1f0) {
+ ConfigInfo->AtdiskPrimaryClaimed = TRUE;
+ deviceExtension->PrimaryAddress = TRUE;
+ } else if (cmdBasePort[0] == 0x170) {
+ ConfigInfo->AtdiskSecondaryClaimed = TRUE;
+ deviceExtension->PrimaryAddress = FALSE;
+ }
+
+ if (cmdBasePort[1] == 0x1f0) {
+ ConfigInfo->AtdiskPrimaryClaimed = TRUE;
+ } else if (cmdBasePort[1] == 0x170) {
+ ConfigInfo->AtdiskSecondaryClaimed = TRUE;
+ }
+
+ if (*PreConfig == FALSE) {
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(cmdBasePort[0]);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = 8;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ (*ConfigInfo->AccessRanges)[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(ctrlBasePort[0]);
+ (*ConfigInfo->AccessRanges)[1].RangeLength = 1;
+ (*ConfigInfo->AccessRanges)[1].RangeInMemory = FALSE;
+
+ if (cmdBasePort[1]) {
+ (*ConfigInfo->AccessRanges)[2].RangeStart = ScsiPortConvertUlongToPhysicalAddress(cmdBasePort[1]);
+ (*ConfigInfo->AccessRanges)[2].RangeLength = 8;
+ (*ConfigInfo->AccessRanges)[2].RangeInMemory = FALSE;
+
+ (*ConfigInfo->AccessRanges)[3].RangeStart = ScsiPortConvertUlongToPhysicalAddress(ctrlBasePort[1]);
+ (*ConfigInfo->AccessRanges)[3].RangeLength = 1;
+ (*ConfigInfo->AccessRanges)[3].RangeInMemory = FALSE;
+ }
+
+ if (bmBasePort[0]) {
+ (*ConfigInfo->AccessRanges)[4].RangeStart = ScsiPortConvertUlongToPhysicalAddress(bmBasePort[0]);
+ (*ConfigInfo->AccessRanges)[4].RangeLength = 8;
+ (*ConfigInfo->AccessRanges)[4].RangeInMemory = FALSE;
+ }
+
+ if (bmBasePort[1]) {
+ (*ConfigInfo->AccessRanges)[5].RangeStart = ScsiPortConvertUlongToPhysicalAddress(bmBasePort[1]);
+ (*ConfigInfo->AccessRanges)[5].RangeLength = 8;
+ (*ConfigInfo->AccessRanges)[5].RangeInMemory = FALSE;
+ }
+ }
+
+
+ //
+ // map all raw io addresses to logical io addresses
+ //
+ getDeviceBaseFailed = FALSE;
+ CmdLogicalBasePort[0] = (PIDE_REGISTERS_1) ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ (*ConfigInfo->AccessRanges)[0].RangeStart,
+ (*ConfigInfo->AccessRanges)[0].RangeLength,
+ (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory));
+ if (!CmdLogicalBasePort[0]) {
+ getDeviceBaseFailed = TRUE;
+ }
+
+ if (*PreConfig) {
+ CtrlLogicalBasePort[0] = (PIDE_REGISTERS_2) ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(ctrlBasePort[0]),
+ 1,
+ (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory));
+
+ } else {
+ CtrlLogicalBasePort[0] = (PIDE_REGISTERS_2) ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ (*ConfigInfo->AccessRanges)[1].RangeStart,
+ (*ConfigInfo->AccessRanges)[1].RangeLength,
+ (BOOLEAN) !((*ConfigInfo->AccessRanges)[1].RangeInMemory));
+ }
+ if (!CtrlLogicalBasePort[0]) {
+ getDeviceBaseFailed = TRUE;
+ }
+
+ if (cmdBasePort[1]) {
+ CmdLogicalBasePort[1] = (PIDE_REGISTERS_1) ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ (*ConfigInfo->AccessRanges)[2].RangeStart,
+ (*ConfigInfo->AccessRanges)[2].RangeLength,
+ (BOOLEAN) !((*ConfigInfo->AccessRanges)[2].RangeInMemory));
+ if (!CmdLogicalBasePort[0]) {
+ getDeviceBaseFailed = TRUE;
+ }
+
+ CtrlLogicalBasePort[1] = (PIDE_REGISTERS_2) ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ (*ConfigInfo->AccessRanges)[3].RangeStart,
+ (*ConfigInfo->AccessRanges)[3].RangeLength,
+ (BOOLEAN) !((*ConfigInfo->AccessRanges)[3].RangeInMemory));
+ if (!CtrlLogicalBasePort[0]) {
+ getDeviceBaseFailed = TRUE;
+ }
+ }
+
+ if (bmBasePort[0]) {
+ BmLogicalBasePort[0] = (PIDE_BUS_MASTER_REGISTERS) ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ (*ConfigInfo->AccessRanges)[4].RangeStart,
+ (*ConfigInfo->AccessRanges)[4].RangeLength,
+ (BOOLEAN) !((*ConfigInfo->AccessRanges)[4].RangeInMemory));
+ if (!BmLogicalBasePort[0]) {
+ getDeviceBaseFailed = TRUE;
+ }
+ }
+ if (bmBasePort[1]) {
+ BmLogicalBasePort[1] = (PIDE_BUS_MASTER_REGISTERS) ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ (*ConfigInfo->AccessRanges)[5].RangeStart,
+ (*ConfigInfo->AccessRanges)[5].RangeLength,
+ (BOOLEAN) !((*ConfigInfo->AccessRanges)[5].RangeInMemory));
+ if (!BmLogicalBasePort[1]) {
+ getDeviceBaseFailed = TRUE;
+ }
+ }
+
+ if (!getDeviceBaseFailed)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOLEAN
+AtapiFreeIoBase (
+ IN PVOID HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PFIND_STATE FindState,
+ OUT PIDE_REGISTERS_1 CmdLogicalBasePort[2],
+ OUT PIDE_REGISTERS_2 CtrlLogicalBasePort[2],
+ OUT PIDE_BUS_MASTER_REGISTERS BmLogicalBasePort[2]
+)
+/*++
+
+Routine Description:
+
+ free logical io addresses.
+
+ This function is called when no device found on the io addresses
+
+ This function clears these PORT_CONFIGURATION_INFORMATION entries
+
+ AccessRanges
+ BusInterruptLevel
+ BusInterruptLevel2
+ AtdiskPrimaryClaimed
+ AtdiskSecondaryClaimed
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo = Scsi Port Config. Structure
+ FindState - Keep track of what addresses has been returned
+ CmdLogicalBasePort - command block register logical base address
+ CtrlLogicalBasePort - control block register logical base address
+ BmLogicalBasePort - bus master register logical base address
+
+Return Value:
+
+ TRUE - always
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ if (CmdLogicalBasePort[0]) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ CmdLogicalBasePort[0]);
+ (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
+ CmdLogicalBasePort[0] = 0;
+ }
+ if (CmdLogicalBasePort[1]) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ CmdLogicalBasePort[1]);
+ (*ConfigInfo->AccessRanges)[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
+ CmdLogicalBasePort[1] = 0;
+ }
+ if (CtrlLogicalBasePort[0]) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ CtrlLogicalBasePort[0]);
+ (*ConfigInfo->AccessRanges)[2].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
+ CtrlLogicalBasePort[0] = 0;
+ }
+ if (CtrlLogicalBasePort[1]) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ CtrlLogicalBasePort[1]);
+ (*ConfigInfo->AccessRanges)[3].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
+ CtrlLogicalBasePort[1] = 0;
+ }
+ if (BmLogicalBasePort[0]) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ BmLogicalBasePort[0]);
+ (*ConfigInfo->AccessRanges)[4].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
+ BmLogicalBasePort[0] = 0;
+ }
+ if (BmLogicalBasePort[1]) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ BmLogicalBasePort[1]);
+ (*ConfigInfo->AccessRanges)[5].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
+ BmLogicalBasePort[1] = 0;
+ }
+
+ ConfigInfo->AtdiskPrimaryClaimed = FALSE;
+ ConfigInfo->AtdiskSecondaryClaimed = FALSE;
+ ConfigInfo->BusInterruptLevel = 0;
+ ConfigInfo->BusInterruptLevel2 = 0;
+ deviceExtension->PrimaryAddress = FALSE;
+ deviceExtension->BMTimingControl = NULL;
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+AtapiAllocatePRDT(
+ IN OUT PVOID HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ )
+/*++
+
+Routine Description:
+
+ allocate scatter/gather list for PCI IDE controller call
+ Physical Region Descriptor Table (PRDT)
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo = Scsi Port Config. Structure
+
+Return Value:
+
+ TRUE - if successful
+ FASLE - if failed
+
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG bytesMapped;
+ ULONG totalBytesMapped;
+ PUCHAR buffer;
+ PHYSICAL_ADDRESS physAddr;
+ ULONG uncachedExtensionSize;
+ INTERFACE_TYPE oldAdapterInterfaceType;
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+ ConfigInfo->DmaWidth = Width16Bits;
+
+ //
+ // word align
+ //
+ ConfigInfo->AlignmentMask = 1;
+
+ //
+ // PRDT cannot cross a page boundary, so number of physical breaks
+ // are limited by page size
+ //
+ ConfigInfo->NumberOfPhysicalBreaks = PAGE_SIZE / sizeof(PHYSICAL_REGION_DESCRIPTOR);
+
+ //
+ // MAX_TRANSFER_SIZE_PER_SRB can spread over
+ // (MAX_TRANSFER_SIZE_PER_SRB / PAGE_SIZE) + 2 pages
+ // Each page requires 8 bytes in the bus master descriptor table
+ // To guarantee we will have a buffer that is big enough and does not
+ // cross a page boundary, we will allocate twice of what we need.
+ // Half of that will always be big enough and will not cross
+ // any page boundary
+ //
+ uncachedExtensionSize = (MAX_TRANSFER_SIZE_PER_SRB / PAGE_SIZE) + 2;
+ uncachedExtensionSize *= sizeof (PHYSICAL_REGION_DESCRIPTOR);
+ uncachedExtensionSize *= 2;
+
+ //
+ // ScsiPortGetUncachedExtension() will allocate Adapter object,
+ // change the AdapterInterfaceType to PCI temporarily so that
+ // we don't inherit ISA DMA limitation.
+ // We can't keep the AdapterInterfaceType to PCI because the
+ // irq resources we are asking for are ISA resources
+ //
+ oldAdapterInterfaceType = ConfigInfo->AdapterInterfaceType;
+ ConfigInfo->AdapterInterfaceType = PCIBus;
+
+ buffer = ScsiPortGetUncachedExtension(HwDeviceExtension,
+ ConfigInfo,
+ uncachedExtensionSize);
+
+ ConfigInfo->AdapterInterfaceType = oldAdapterInterfaceType;
+
+ if (buffer) {
+
+ deviceExtension->DataBufferDescriptionTableSize = 0;
+ totalBytesMapped = 0;
+ while (totalBytesMapped < uncachedExtensionSize) {
+ physAddr = ScsiPortGetPhysicalAddress(HwDeviceExtension,
+ NULL,
+ buffer,
+ &bytesMapped);
+ if (bytesMapped == 0) {
+ break;
+ }
+
+ //
+ // Find the biggest chuck of physically contiguous memory
+ //
+ totalBytesMapped += bytesMapped;
+ while (bytesMapped) {
+ ULONG chunkSize;
+
+ chunkSize = PAGE_SIZE - (ScsiPortConvertPhysicalAddressToUlong(physAddr) & (PAGE_SIZE-1));
+ if (chunkSize > bytesMapped)
+ chunkSize = bytesMapped;
+
+ if (chunkSize > deviceExtension->DataBufferDescriptionTableSize) {
+ deviceExtension->DataBufferDescriptionTableSize = chunkSize;
+ deviceExtension->DataBufferDescriptionTablePtr = (PPHYSICAL_REGION_DESCRIPTOR) buffer;
+ deviceExtension->DataBufferDescriptionTablePhysAddr = physAddr;
+ }
+ buffer += chunkSize;
+ physAddr = ScsiPortConvertUlongToPhysicalAddress
+ (ScsiPortConvertPhysicalAddressToUlong(physAddr) + chunkSize);
+ bytesMapped -= chunkSize;
+ }
+ }
+ // Did we get at least the minimal amount (half of what we ask for)?
+ if (deviceExtension->DataBufferDescriptionTableSize < (uncachedExtensionSize / 2)) {
+ buffer = NULL;
+ }
+ }
+
+ if (buffer) {
+ return TRUE;
+ } else {
+ DebugPrint ((0, "atapi: unable to get buffer for physical descriptor table!\n"));
+ ConfigInfo->ScatterGather = FALSE;
+ ConfigInfo->Master = FALSE;
+ ConfigInfo->Dma32BitAddresses = FALSE;
+ return FALSE;
+ }
+}
+
+
+ULONG
+AtapiFindController(
+ IN PVOID HwDeviceExtension,
+ IN PFIND_STATE FindState,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - Address of findstate
+ ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
+ ConfigInfo - Configuration information structure describing HBA
+ Again - Indicates search for adapters to continue
+
+Return Value:
+
+ ULONG
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG i,j;
+ ULONG retryCount;
+ PCI_SLOT_NUMBER slotData;
+ PPCI_COMMON_CONFIG pciData;
+ ULONG pciBuffer;
+ BOOLEAN atapiOnly;
+ UCHAR statusByte;
+ ULONG ideChannel;
+ BOOLEAN foundDevice = FALSE;
+
+ PIDE_REGISTERS_1 cmdLogicalBasePort[2];
+ PIDE_REGISTERS_2 ctrlLogicalBasePort[2];
+ PIDE_BUS_MASTER_REGISTERS bmLogicalBasePort[2];
+ ULONG numIdeChannel;
+ BOOLEAN preConfig = FALSE;
+ PCHAR userArgumentString;
+
+
+ if (!deviceExtension) {
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // set the dma detection level
+ //
+ SetBusMasterDetectionLevel (HwDeviceExtension, ArgumentString);
+
+ *Again = TRUE;
+ userArgumentString = ArgumentString;
+ while (AtapiAllocateIoBase (HwDeviceExtension,
+ userArgumentString,
+ ConfigInfo,
+ FindState,
+ cmdLogicalBasePort,
+ ctrlLogicalBasePort,
+ bmLogicalBasePort,
+ &numIdeChannel,
+ &preConfig)) {
+
+ // only use user argument string once
+ userArgumentString = NULL;
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->MaximumNumberOfTargets = (UCHAR) (2 * numIdeChannel);
+ deviceExtension->NumberChannels = numIdeChannel;
+
+ for (i = 0; i < 4; i++) {
+ deviceExtension->DeviceFlags[i] &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | DFLAGS_TAPE_DEVICE);
+ }
+
+ for (ideChannel = 0; ideChannel < numIdeChannel; ideChannel++) {
+
+ retryCount = 4;
+
+ retryIdentifier:
+
+ //
+ // Select master.
+ //
+
+ ScsiPortWritePortUchar(&cmdLogicalBasePort[ideChannel]->DriveSelect, 0xA0);
+
+ //
+ // Check if card at this address.
+ //
+
+ ScsiPortWritePortUchar(&cmdLogicalBasePort[ideChannel]->CylinderLow, 0xAA);
+
+ //
+ // Check if indentifier can be read back.
+ //
+
+ if ((statusByte = ScsiPortReadPortUchar(&cmdLogicalBasePort[ideChannel]->CylinderLow)) != 0xAA) {
+
+ DebugPrint((2,
+ "AtapiFindController: Identifier read back from Master (%x)\n",
+ statusByte));
+
+ statusByte = ScsiPortReadPortUchar(&cmdLogicalBasePort[ideChannel]->Command);
+
+ if (statusByte & IDE_STATUS_BUSY) {
+
+ i = 0;
+
+ //
+ // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
+ // warm boots don't clear.
+ //
+
+ do {
+ ScsiPortStallExecution(1000);
+ statusByte = ScsiPortReadPortUchar(&cmdLogicalBasePort[ideChannel]->Command);
+ DebugPrint((3,
+ "AtapiFindController: First access to status %x\n",
+ statusByte));
+ } while ((statusByte & IDE_STATUS_BUSY) && ++i < 10);
+
+ if (retryCount-- && (!(statusByte & IDE_STATUS_BUSY))) {
+ goto retryIdentifier;
+ }
+ }
+
+ //
+ // Select slave.
+ //
+
+ ScsiPortWritePortUchar(&cmdLogicalBasePort[ideChannel]->DriveSelect, 0xB0);
+
+ //
+ // See if slave is present.
+ //
+
+ ScsiPortWritePortUchar(&cmdLogicalBasePort[ideChannel]->CylinderLow, 0xAA);
+
+ if ((statusByte = ScsiPortReadPortUchar(&cmdLogicalBasePort[ideChannel]->CylinderLow)) != 0xAA) {
+
+ DebugPrint((2,
+ "AtapiFindController: Identifier read back from Slave (%x)\n",
+ statusByte));
+
+ //
+ //
+ // No controller at this base address.
+ //
+ continue;
+ }
+ }
+
+ //
+ // Record base IO address.
+ //
+
+ deviceExtension->BaseIoAddress1[ideChannel] = cmdLogicalBasePort[ideChannel];
+ deviceExtension->BaseIoAddress2[ideChannel] = ctrlLogicalBasePort[ideChannel];
+ deviceExtension->BusMasterPortBase[ideChannel] = bmLogicalBasePort[ideChannel];
+ if (bmLogicalBasePort[ideChannel]) {
+ deviceExtension->ControllerFlags |= CFLAGS_BUS_MASTERING;
+ } else {
+ deviceExtension->ControllerFlags &= ~CFLAGS_BUS_MASTERING;
+ }
+
+ DebugPrint ((2, "atapi: command register logical base port: 0x%x\n", deviceExtension->BaseIoAddress1[ideChannel]));
+ DebugPrint ((2, "atapi: control register logical base port: 0x%x\n", deviceExtension->BaseIoAddress2[ideChannel]));
+ DebugPrint ((2, "atapi: busmaster register logical base port: 0x%x\n", deviceExtension->BusMasterPortBase[ideChannel]));
+
+ //
+ // Indicate maximum transfer length is 64k.
+ //
+ ConfigInfo->MaximumTransferLength = MAX_TRANSFER_SIZE_PER_SRB;
+
+ DebugPrint((1,
+ "AtapiFindController: Found IDE at %x\n",
+ deviceExtension->BaseIoAddress1[ideChannel]));
+
+
+ //
+ // For Daytona, the atdisk driver gets the first shot at the
+ // primary and secondary controllers.
+ //
+
+ if (preConfig == FALSE) {
+
+ if (ConfigInfo->AtdiskPrimaryClaimed || ConfigInfo->AtdiskSecondaryClaimed) {
+
+ //
+ // Determine whether this driver is being initialized by the
+ // system or as a crash dump driver.
+ //
+
+ if (ArgumentString) {
+
+ if (AtapiParseArgumentString(ArgumentString, "dump") == 1) {
+ DebugPrint((3,
+ "AtapiFindController: Crash dump\n"));
+ atapiOnly = FALSE;
+ deviceExtension->DriverMustPoll = TRUE;
+ } else {
+ DebugPrint((3,
+ "AtapiFindController: Atapi Only\n"));
+ atapiOnly = TRUE;
+ deviceExtension->DriverMustPoll = FALSE;
+ }
+ } else {
+
+ DebugPrint((3,
+ "AtapiFindController: Atapi Only\n"));
+ atapiOnly = TRUE;
+ deviceExtension->DriverMustPoll = FALSE;
+ }
+
+ } else {
+ atapiOnly = FALSE;
+ }
+
+ //
+ // If this is a PCI machine, pick up all devices.
+ //
+
+
+ pciData = (PPCI_COMMON_CONFIG)&pciBuffer;
+
+ slotData.u.bits.DeviceNumber = 0;
+ slotData.u.bits.FunctionNumber = 0;
+
+ if (ScsiPortGetBusData(deviceExtension,
+ PCIConfiguration,
+ 0, // BusNumber
+ slotData.u.AsULONG,
+ pciData,
+ sizeof(ULONG))) {
+
+ atapiOnly = FALSE;
+
+ //
+ // Wait on doing this, until a reliable method
+ // of determining support is found.
+ //
+
+ #if 0
+ deviceExtension->DWordIO = TRUE;
+ #endif
+
+ } else {
+ deviceExtension->DWordIO = FALSE;
+ }
+
+ } else {
+
+ atapiOnly = FALSE;
+ deviceExtension->DriverMustPoll = FALSE;
+
+ }// preConfig check
+
+ //
+ // Save the Interrupe Mode for later use
+ //
+ deviceExtension->InterruptMode = ConfigInfo->InterruptMode;
+
+ //
+ // Search for devices on this controller.
+ //
+
+ if (FindDevices(HwDeviceExtension, atapiOnly, ideChannel)) {
+ foundDevice = TRUE;
+ }
+ }
+
+ if (!foundDevice) {
+ AtapiFreeIoBase (HwDeviceExtension,
+ ConfigInfo,
+ FindState,
+ cmdLogicalBasePort,
+ ctrlLogicalBasePort,
+ bmLogicalBasePort);
+ } else {
+
+ ULONG deviceNumber;
+
+ DeviceSpecificInitialize(HwDeviceExtension);
+
+ for (deviceNumber = 0; deviceNumber < 4; deviceNumber++) {
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_DEVICE_PRESENT) {
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_USE_DMA) {
+ ConfigInfo->NeedPhysicalAddresses = TRUE;
+ } else {
+ ConfigInfo->MapBuffers = TRUE;
+ }
+ break;
+ }
+ }
+ if (ConfigInfo->NeedPhysicalAddresses) {
+ if (!AtapiAllocatePRDT(HwDeviceExtension, ConfigInfo)) {
+ // Unable to get buffer descriptor table,
+ // go back to PIO mode
+ deviceExtension->ControllerFlags &= ~CFLAGS_BUS_MASTERING;
+ DeviceSpecificInitialize(HwDeviceExtension);
+ ConfigInfo->NeedPhysicalAddresses = FALSE;
+ ConfigInfo->MapBuffers = TRUE;
+ }
+ }
+
+ if (!AtapiPlaySafe &&
+ (deviceExtension->ControllerFlags & CFLAGS_BUS_MASTERING) &&
+ (deviceExtension->BMTimingControl)) {
+ (*deviceExtension->BMTimingControl) (deviceExtension);
+ }
+
+ return(SP_RETURN_FOUND);
+ }
+ }
+
+ //
+ // The entire table has been searched and no adapters have been found.
+ // There is no need to call again and the device base can now be freed.
+ // Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+
+ return(SP_RETURN_NOT_FOUND);
+
+} // end AtapiFindController()
+
+
+VOID
+DeviceSpecificInitialize(
+ IN PVOID HwDeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ software-initialize devices on the ide bus
+
+ figure out
+ if the attached devices are dma capable
+ if the attached devices are LBA ready
+
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ none
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG deviceNumber;
+ BOOLEAN pioDevicePresent;
+ IDENTIFY_DATA2 * identifyData;
+ struct _DEVICE_PARAMETERS * deviceParameters;
+ BOOLEAN dmaCapable;
+ ULONG pioCycleTime;
+ ULONG standardPioCycleTime;
+ ULONG dmaCycleTime;
+ ULONG standardDmaCycleTime;
+
+ //
+ // Figure out who can do DMA and who cannot
+ //
+ for (deviceNumber = 0; deviceNumber < 4; deviceNumber++) {
+
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_DEVICE_PRESENT) {
+
+ //
+ // check LBA capabilities
+ //
+ deviceExtension->DeviceFlags[deviceNumber] &= ~DFLAGS_LBA;
+
+ // Some drives lie about their ability to do LBA
+ // we don't want to do LBA unless we have to (>8G drive)
+// if (deviceExtension->IdentifyData[targetId].Capabilities & IDENTIFY_CAPABILITIES_LBA_SUPPORTED) {
+// deviceExtension->DeviceFlags[targetId] |= DFLAGS_LBA;
+// }
+ if (deviceExtension->IdentifyData[deviceNumber].UserAddressableSectors > MAX_NUM_CHS_ADDRESSABLE_SECTORS) {
+ // some device has a bogus value in the UserAddressableSectors field
+ // make sure these 3 fields are max. out as defined in ATA-3 (X3T10 Rev. 6)
+ if ((deviceExtension->IdentifyData[deviceNumber].NumberOfCylinders == 16383) &&
+ (deviceExtension->IdentifyData[deviceNumber].NumberOfHeads == 16) &&
+ (deviceExtension->IdentifyData[deviceNumber].SectorsPerTrack == 63)) {
+ deviceExtension->DeviceFlags[deviceNumber] |= DFLAGS_LBA;
+ }
+ }
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_LBA) {
+ DebugPrint ((1, "atapi: target %d supports LBA\n", deviceNumber));
+ }
+
+ //
+ // Try to enable DMA
+ //
+ dmaCapable = FALSE;
+
+ if (deviceExtension->ControllerFlags & CFLAGS_BUS_MASTERING) {
+ UCHAR dmaStatus;
+ dmaStatus = ScsiPortReadPortUchar (&deviceExtension->BusMasterPortBase[deviceNumber >> 1]->Status);
+ if (deviceNumber & 1) {
+ if (dmaStatus & BUSMASTER_DEVICE1_DMA_OK) {
+ DebugPrint ((1, "atapi: target %d busmaster status 0x%x DMA capable bit is set\n", deviceNumber, dmaStatus));
+ dmaCapable = TRUE;
+ }
+ } else {
+ if (dmaStatus & BUSMASTER_DEVICE0_DMA_OK) {
+ DebugPrint ((1, "atapi: target %d busmaster status 0x%x DMA capable bit is set\n", deviceNumber, dmaStatus));
+ dmaCapable = TRUE;
+ }
+ }
+ }
+
+ //
+ // figure out the shortest PIO cycle time the deivce supports
+ //
+ deviceExtension->DeviceParameters[deviceNumber].BestPIOMode = INVALID_PIO_MODE;
+ deviceExtension->DeviceParameters[deviceNumber].BestSingleWordDMAMode = INVALID_SWDMA_MODE;
+ deviceExtension->DeviceParameters[deviceNumber].BestMultiWordDMAMode = INVALID_MWDMA_MODE;
+ pioCycleTime = standardPioCycleTime = UNINITIALIZED_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].IoReadyEnabled = FALSE;
+
+ if (deviceExtension->IdentifyData[deviceNumber].TranslationFieldsValid & (1 << 1)) {
+ if (deviceExtension->IdentifyData[deviceNumber].MinimumPIOCycleTimeIORDY) {
+ pioCycleTime = deviceExtension->IdentifyData[deviceNumber].MinimumPIOCycleTimeIORDY;
+ }
+ }
+
+ if (deviceExtension->IdentifyData[deviceNumber].TranslationFieldsValid & (1 << 1)) {
+ if (deviceExtension->IdentifyData[deviceNumber].AdvancedPIOModes & (1 << 1)) {
+ standardPioCycleTime = PIO_MODE4_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestPIOMode = 4;
+ } else if (deviceExtension->IdentifyData[deviceNumber].AdvancedPIOModes & (1 << 0)) {
+ standardPioCycleTime = PIO_MODE3_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestPIOMode = 3;
+ }
+ if (pioCycleTime == UNINITIALIZED_CYCLE_TIME) {
+ pioCycleTime = standardPioCycleTime;
+ }
+
+ } else {
+
+ if ((deviceExtension->IdentifyData[deviceNumber].PioCycleTimingMode & 0x00ff) == 2) {
+ standardPioCycleTime = PIO_MODE2_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestPIOMode = 2;
+ } else if ((deviceExtension->IdentifyData[deviceNumber].PioCycleTimingMode & 0x00ff) == 1) {
+ standardPioCycleTime = PIO_MODE1_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestPIOMode = 1;
+ } else {
+ standardPioCycleTime = PIO_MODE0_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestPIOMode = 0;
+ }
+
+ if (pioCycleTime == UNINITIALIZED_CYCLE_TIME) {
+ pioCycleTime = standardPioCycleTime;
+ }
+ }
+
+ deviceExtension->DeviceParameters[deviceNumber].PioCycleTime = pioCycleTime;
+ if (deviceExtension->IdentifyData[deviceNumber].Capabilities & IDENTIFY_CAPABILITIES_IOREADY_SUPPORTED) {
+ deviceExtension->DeviceParameters[deviceNumber].IoReadyEnabled = TRUE;
+ }
+
+ //
+ // figure out the shortest DMA cycle time the device supports
+ //
+ // check min cycle time
+ //
+ dmaCycleTime = standardDmaCycleTime = UNINITIALIZED_CYCLE_TIME;
+ if (deviceExtension->IdentifyData[deviceNumber].TranslationFieldsValid & (1 << 1)) {
+ DebugPrint ((1, "atapi: target %d IdentifyData word 64-70 are valid\n", deviceNumber));
+
+ if (deviceExtension->IdentifyData[deviceNumber].MinimumMWXferCycleTime &&
+ deviceExtension->IdentifyData[deviceNumber].RecommendedMWXferCycleTime) {
+ DebugPrint ((1,
+ "atapi: target %d IdentifyData MinimumMWXferCycleTime = 0x%x\n",
+ deviceNumber,
+ deviceExtension->IdentifyData[deviceNumber].MinimumMWXferCycleTime));
+ DebugPrint ((1,
+ "atapi: target %d IdentifyData RecommendedMWXferCycleTime = 0x%x\n",
+ deviceNumber,
+ deviceExtension->IdentifyData[deviceNumber].RecommendedMWXferCycleTime));
+ dmaCycleTime = deviceExtension->IdentifyData[deviceNumber].RecommendedMWXferCycleTime;
+ }
+ }
+ //
+ // check mulitword DMA timing
+ //
+ if (deviceExtension->IdentifyData[deviceNumber].MultiWordDMASupport) {
+ DebugPrint ((1,
+ "atapi: target %d IdentifyData MultiWordDMASupport = 0x%x\n",
+ deviceNumber,
+ deviceExtension->IdentifyData[deviceNumber].MultiWordDMASupport));
+ DebugPrint ((1,
+ "atapi: target %d IdentifyData MultiWordDMAActive = 0x%x\n",
+ deviceNumber,
+ deviceExtension->IdentifyData[deviceNumber].MultiWordDMAActive));
+
+ if (deviceExtension->IdentifyData[deviceNumber].MultiWordDMASupport & (1 << 2)) {
+ standardDmaCycleTime = MWDMA_MODE2_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestMultiWordDMAMode = 2;
+
+ } else if (deviceExtension->IdentifyData[deviceNumber].MultiWordDMASupport & (1 << 1)) {
+ standardDmaCycleTime = MWDMA_MODE1_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestMultiWordDMAMode = 1;
+
+ } else if (deviceExtension->IdentifyData[deviceNumber].MultiWordDMASupport & (1 << 0)) {
+ standardDmaCycleTime = MWDMA_MODE0_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestMultiWordDMAMode = 0;
+ }
+ if (dmaCycleTime == UNINITIALIZED_CYCLE_TIME) {
+ dmaCycleTime = standardDmaCycleTime;
+ }
+ }
+
+ //
+ // check singleword DMA timing
+ //
+ if (deviceExtension->IdentifyData[deviceNumber].SingleWordDMASupport) {
+ DebugPrint ((1,
+ "atapi: target %d IdentifyData SingleWordDMASupport = 0x%x\n",
+ deviceNumber,
+ deviceExtension->IdentifyData[deviceNumber].SingleWordDMASupport));
+ DebugPrint ((1,
+ "atapi: target %d IdentifyData SingleWordDMAActive = 0x%x\n",
+ deviceNumber,
+ deviceExtension->IdentifyData[deviceNumber].SingleWordDMAActive));
+
+ if (deviceExtension->IdentifyData[deviceNumber].SingleWordDMASupport & (1 << 2)) {
+ standardDmaCycleTime = SWDMA_MODE2_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestSingleWordDMAMode = 2;
+
+ } else if (deviceExtension->IdentifyData[deviceNumber].SingleWordDMASupport & (1 << 1)) {
+ standardDmaCycleTime = SWDMA_MODE1_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestSingleWordDMAMode = 1;
+
+ } else if (deviceExtension->IdentifyData[deviceNumber].SingleWordDMASupport & (1 << 0)) {
+ standardDmaCycleTime = SWDMA_MODE0_CYCLE_TIME;
+ deviceExtension->DeviceParameters[deviceNumber].BestSingleWordDMAMode = 0;
+ }
+ if (dmaCycleTime == UNINITIALIZED_CYCLE_TIME) {
+ dmaCycleTime = standardDmaCycleTime;
+ }
+ }
+
+ deviceExtension->DeviceParameters[deviceNumber].DmaCycleTime = dmaCycleTime;
+
+//
+// Study shows that even dma cycle time may be larger than pio cycle time, dma
+// can still give better data throughput
+//
+// if (dmaCycleTime > pioCycleTime) {
+// DebugPrint ((0, "atapi: target %d can do PIO (%d) faster than DMA (%d). Turning off DMA...\n", deviceNumber, pioCycleTime, dmaCycleTime));
+// dmaCapable = FALSE;
+// } else {
+// if (!AtapiPlaySafe) {
+// if (dmaCapable == FALSE) {
+// DebugPrint ((0, "atapi: If we play safe, we would NOT detect target %d is DMA capable\n", deviceNumber));
+// }
+// dmaCapable = TRUE;
+// }
+// }
+
+ if ((deviceExtension->IdentifyData[deviceNumber].SingleWordDMAActive == 0) &&
+ (deviceExtension->IdentifyData[deviceNumber].MultiWordDMAActive == 0)) {
+ dmaCapable = FALSE;
+ } else {
+ if (!AtapiPlaySafe) {
+ if (dmaCapable == FALSE) {
+ DebugPrint ((0, "atapi: If we play safe, we would NOT detect target %d is DMA capable\n", deviceNumber));
+ }
+ dmaCapable = TRUE;
+ }
+ }
+
+ //
+ // Check for bad devices
+ //
+ if (AtapiDeviceDMACapable (deviceExtension, deviceNumber) == FALSE) {
+ dmaCapable = FALSE;
+ }
+
+ if ((deviceExtension->ControllerFlags & CFLAGS_BUS_MASTERING) && dmaCapable) {
+ deviceExtension->DeviceFlags[deviceNumber] |= DFLAGS_USE_DMA;
+ } else {
+ deviceExtension->DeviceFlags[deviceNumber] &= ~DFLAGS_USE_DMA;
+ }
+ }
+ }
+
+
+
+
+ //
+ // Default everyone to pio if anyone of them cannot do DMA
+ // We can remove this if it is ok to mix DMA and PIO devices on the same channel
+ //
+ // If we are going to allow mixing DMA and PIO, we need to change SCSIPORT
+ // to allow setting both NeedPhysicalAddresses and MapBuffers to TRUE in
+ // PORT_CONFIGURATION_INFORMATION
+ //
+ pioDevicePresent = FALSE;
+ for (deviceNumber = 0; deviceNumber < 4 && !pioDevicePresent; deviceNumber++) {
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_DEVICE_PRESENT) {
+ if (!(deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_USE_DMA)) {
+ pioDevicePresent = TRUE; // bummer!
+ }
+ }
+ }
+
+ if (pioDevicePresent) {
+ for (deviceNumber = 0; deviceNumber < 4; deviceNumber++) {
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_DEVICE_PRESENT) {
+ deviceExtension->DeviceFlags[deviceNumber] &= ~DFLAGS_USE_DMA;
+ }
+ }
+ }
+
+
+ //
+ // pick out the ATA or ATAPI r/w command we are going to use
+ //
+ for (deviceNumber = 0; deviceNumber < 4; deviceNumber++) {
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_DEVICE_PRESENT) {
+
+ DebugPrint ((0, "ATAPI: Base=0x%x Device %d is going to do ", deviceExtension->BaseIoAddress1[deviceNumber >> 1], deviceNumber));
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_USE_DMA) {
+ DebugPrint ((0, "DMA\n"));
+ } else {
+ DebugPrint ((0, "PIO\n"));
+ }
+
+
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_ATAPI_DEVICE) {
+
+ deviceExtension->DeviceParameters[deviceNumber].MaxWordPerInterrupt = 256;
+
+ } else {
+
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_USE_DMA) {
+
+ DebugPrint ((2, "ATAPI: ATA Device (%d) is going to do DMA\n", deviceNumber));
+ deviceExtension->DeviceParameters[deviceNumber].IdeReadCommand = IDE_COMMAND_READ_DMA;
+ deviceExtension->DeviceParameters[deviceNumber].IdeWriteCommand = IDE_COMMAND_WRITE_DMA;
+ deviceExtension->DeviceParameters[deviceNumber].MaxWordPerInterrupt = MAX_TRANSFER_SIZE_PER_SRB / 2;
+
+ } else {
+
+ if (deviceExtension->MaximumBlockXfer[deviceNumber]) {
+
+ DebugPrint ((2, "ATAPI: ATA Device (%d) is going to do PIO Multiple\n", deviceNumber));
+ deviceExtension->DeviceParameters[deviceNumber].IdeReadCommand = IDE_COMMAND_READ_MULTIPLE;
+ deviceExtension->DeviceParameters[deviceNumber].IdeWriteCommand = IDE_COMMAND_WRITE_MULTIPLE;
+ deviceExtension->DeviceParameters[deviceNumber].MaxWordPerInterrupt =
+ deviceExtension->MaximumBlockXfer[deviceNumber] * 256;
+ } else {
+
+ DebugPrint ((2, "ATAPI: ATA Device (%d) is going to do PIO Single\n", deviceNumber));
+ deviceExtension->DeviceParameters[deviceNumber].IdeReadCommand = IDE_COMMAND_READ;
+ deviceExtension->DeviceParameters[deviceNumber].IdeWriteCommand = IDE_COMMAND_WRITE;
+ deviceExtension->DeviceParameters[deviceNumber].MaxWordPerInterrupt = 256;
+ }
+ }
+ }
+ }
+ }
+
+}
+
+
+ULONG
+Atapi2Scsi(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN char *DataBuffer,
+ IN ULONG ByteCount
+ )
+/*++
+
+Routine Description:
+
+ Convert atapi cdb and mode sense data to scsi format
+
+Arguments:
+
+ Srb - SCSI request block
+ DataBuffer - mode sense data
+ ByteCount - mode sense data length
+
+Return Value:
+
+ word adjust
+
+--*/
+{
+ ULONG bytesAdjust = 0;
+ if (Srb->Cdb[0] == ATAPI_MODE_SENSE) {
+
+ PMODE_PARAMETER_HEADER_10 header_10 = (PMODE_PARAMETER_HEADER_10)DataBuffer;
+ PMODE_PARAMETER_HEADER header = (PMODE_PARAMETER_HEADER)DataBuffer;
+
+ header->ModeDataLength = header_10->ModeDataLengthLsb;
+ header->MediumType = header_10->MediumType;
+
+ //
+ // ATAPI Mode Parameter Header doesn't have these fields.
+ //
+
+ header->DeviceSpecificParameter = header_10->Reserved[0];
+ header->BlockDescriptorLength = header_10->Reserved[1];
+
+ ByteCount -= sizeof(MODE_PARAMETER_HEADER_10);
+ if (ByteCount > 0)
+ ScsiPortMoveMemory(DataBuffer+sizeof(MODE_PARAMETER_HEADER),
+ DataBuffer+sizeof(MODE_PARAMETER_HEADER_10),
+ ByteCount);
+
+ //
+ // Change ATAPI_MODE_SENSE opcode back to SCSIOP_MODE_SENSE
+ // so that we don't convert again.
+ //
+
+ Srb->Cdb[0] = SCSIOP_MODE_SENSE;
+
+ bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) -
+ sizeof(MODE_PARAMETER_HEADER);
+
+
+ }
+
+ //
+ // Convert to words.
+ //
+
+ return bytesAdjust >> 1;
+}
+
+
+VOID
+AtapiCallBack(
+ IN PVOID HwDeviceExtension
+ )
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCSI_REQUEST_BLOCK srb = deviceExtension->CurrentSrb;
+ PATAPI_REGISTERS_1 baseIoAddress1;
+ UCHAR statusByte;
+
+ //
+ // If the last command was DSC restrictive, see if it's set. If so, the device is
+ // ready for a new request. Otherwise, reset the timer and come back to here later.
+ //
+
+ if (srb && (!(deviceExtension->ExpectingInterrupt))) {
+#if DBG
+ if (!IS_RDP((srb->Cdb[0]))) {
+ DebugPrint((1,
+ "AtapiCallBack: Invalid CDB marked as RDP - %x\n",
+ srb->Cdb[0]));
+ }
+#endif
+
+ baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[srb->TargetId >> 1];
+ if (deviceExtension->RDP) {
+ GetStatus(baseIoAddress1, statusByte);
+ if (statusByte & IDE_STATUS_DSC) {
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ //
+ // Clear current SRB.
+ //
+
+ deviceExtension->CurrentSrb = NULL;
+ deviceExtension->RDP = FALSE;
+
+ //
+ // Ask for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+
+ return;
+
+ } else {
+
+ DebugPrint((3,
+ "AtapiCallBack: Requesting another timer for Op %x\n",
+ deviceExtension->CurrentSrb->Cdb[0]));
+
+ ScsiPortNotification(RequestTimerCall,
+ HwDeviceExtension,
+ AtapiCallBack,
+ 1000);
+ return;
+ }
+ }
+ }
+
+ DebugPrint((2,
+ "AtapiCallBack: Calling ISR directly due to BUSY\n"));
+ AtapiInterrupt(HwDeviceExtension);
+}
+
+
+BOOLEAN
+AtapiInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for ATAPI IDE miniport driver.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if expecting an interrupt.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCSI_REQUEST_BLOCK srb = deviceExtension->CurrentSrb;
+ PATAPI_REGISTERS_1 baseIoAddress1;
+ PATAPI_REGISTERS_2 baseIoAddress2;
+ ULONG wordCount = 0, wordsThisInterrupt = 256;
+ ULONG status;
+ ULONG i;
+ UCHAR statusByte,interruptReason;
+ BOOLEAN commandComplete = FALSE;
+ BOOLEAN atapiDev = FALSE;
+ UCHAR dmaStatus;
+
+ if (srb) {
+ // PCI Busmaster IDE Controller spec defines a bit in its status
+ // register which indicates pending interrupt. However,
+ // CMD 646 (maybe some other one, too) doesn't always do that if
+ // the interrupt is from a atapi device. (strange, but true!)
+ // Since we have to look at the interrupt bit only if we are sharing
+ // interrupt, we will do just that
+ if (deviceExtension->InterruptMode == LevelSensitive) {
+ if (deviceExtension->ControllerFlags & CFLAGS_BUS_MASTERING) {
+ dmaStatus = ScsiPortReadPortUchar (&deviceExtension->BusMasterPortBase[srb->TargetId >> 1]->Status);
+ if ((dmaStatus & BUSMASTER_INTERRUPT) == 0) {
+ return FALSE;
+ }
+ }
+ }
+
+ baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[srb->TargetId >> 1];
+ baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[srb->TargetId >> 1];
+ } else {
+ DebugPrint((2,
+ "AtapiInterrupt: CurrentSrb is NULL\n"));
+ //
+ // We can only support one ATAPI IDE master on Carolina, so find
+ // the base address that is non NULL and clear its interrupt before
+ // returning.
+ //
+
+#ifdef _PPC_
+
+ if ((PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0] != NULL) {
+ baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0];
+ } else {
+ baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1];
+ }
+
+ GetBaseStatus(baseIoAddress1, statusByte);
+#else
+
+ if (deviceExtension->InterruptMode == LevelSensitive) {
+ if (deviceExtension->BaseIoAddress1[0] != NULL) {
+ baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0];
+ GetBaseStatus(baseIoAddress1, statusByte);
+ }
+ if (deviceExtension->BaseIoAddress1[1] != NULL) {
+ baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1];
+ GetBaseStatus(baseIoAddress1, statusByte);
+ }
+ }
+#endif
+ return FALSE;
+ }
+
+ if (!(deviceExtension->ExpectingInterrupt)) {
+
+ DebugPrint((3,
+ "AtapiInterrupt: Unexpected interrupt.\n"));
+ return FALSE;
+ }
+
+ //
+ // Clear interrupt by reading status.
+ //
+
+ GetBaseStatus(baseIoAddress1, statusByte);
+
+ DebugPrint((3,
+ "AtapiInterrupt: Entered with status (%x)\n",
+ statusByte));
+
+
+ if (statusByte & IDE_STATUS_BUSY) {
+ if (deviceExtension->DriverMustPoll) {
+
+ //
+ // Crashdump is polling and we got caught with busy asserted.
+ // Just go away, and we will be polled again shortly.
+ //
+
+ DebugPrint((3,
+ "AtapiInterrupt: Hit BUSY while polling during crashdump.\n"));
+
+ return TRUE;
+ }
+
+ //
+ // Ensure BUSY is non-asserted.
+ //
+
+ for (i = 0; i < 10; i++) {
+
+ GetBaseStatus(baseIoAddress1, statusByte);
+ if (!(statusByte & IDE_STATUS_BUSY)) {
+ break;
+ }
+ ScsiPortStallExecution(5000);
+ }
+
+ if (i == 10) {
+
+ DebugPrint((2,
+ "AtapiInterrupt: BUSY on entry. Status %x, Base IO %x\n",
+ statusByte,
+ baseIoAddress1));
+
+ ScsiPortNotification(RequestTimerCall,
+ HwDeviceExtension,
+ AtapiCallBack,
+ 500);
+ return TRUE;
+ }
+ }
+
+
+ if (deviceExtension->DMAInProgress) {
+ deviceExtension->DMAInProgress = FALSE;
+ dmaStatus = ScsiPortReadPortUchar (&deviceExtension->BusMasterPortBase[srb->TargetId >> 1]->Status);
+ ScsiPortWritePortUchar (&deviceExtension->BusMasterPortBase[srb->TargetId >> 1]->Command,
+ 0); // disable BusMastering
+ ScsiPortWritePortUchar (&deviceExtension->BusMasterPortBase[srb->TargetId >> 1]->Status,
+ (UCHAR) (dmaStatus | BUSMASTER_INTERRUPT | BUSMASTER_ERROR)); // clear interrupt/error
+
+ deviceExtension->WordsLeft = 0;
+
+ if ((dmaStatus & (BUSMASTER_INTERRUPT | BUSMASTER_ERROR | BUSMASTER_ACTIVE)) != BUSMASTER_INTERRUPT) { // dma ok?
+ status = SRB_STATUS_ERROR;
+ goto CompleteRequest;
+ } else {
+ deviceExtension->WordsLeft = 0;
+ }
+
+ }
+
+ //
+ // Check for error conditions.
+ //
+
+ if (statusByte & IDE_STATUS_ERROR) {
+
+ if (srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
+
+ //
+ // Fail this request.
+ //
+
+ status = SRB_STATUS_ERROR;
+ goto CompleteRequest;
+ }
+ }
+
+ //
+ // check reason for this interrupt.
+ //
+
+
+ if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
+
+ interruptReason = (ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason) & 0x3);
+ atapiDev = TRUE;
+ wordsThisInterrupt = 256;
+
+ } else {
+
+ if (statusByte & IDE_STATUS_DRQ) {
+
+ if (deviceExtension->MaximumBlockXfer[srb->TargetId]) {
+ wordsThisInterrupt = 256 * deviceExtension->MaximumBlockXfer[srb->TargetId];
+
+ }
+
+ if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ interruptReason = 0x2;
+
+ } else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+ interruptReason = 0x0;
+
+ } else {
+ status = SRB_STATUS_ERROR;
+ goto CompleteRequest;
+ }
+
+ } else if (statusByte & IDE_STATUS_BUSY) {
+
+ return FALSE;
+
+ } else {
+
+ if (deviceExtension->WordsLeft) {
+
+ ULONG k;
+
+ //
+ // Funky behaviour seen with PCI IDE (not all, just one).
+ // The ISR hits with DRQ low, but comes up later.
+ //
+
+ for (k = 0; k < 5000; k++) {
+ GetStatus(baseIoAddress1,statusByte);
+ if (!(statusByte & IDE_STATUS_DRQ)) {
+ ScsiPortStallExecution(100);
+ } else {
+ break;
+ }
+ }
+
+ if (k == 5000) {
+
+ //
+ // reset the controller.
+ //
+
+ DebugPrint((1,
+ "AtapiInterrupt: Resetting due to DRQ not up. Status %x, Base IO %x\n",
+ statusByte,
+ baseIoAddress1));
+
+ AtapiResetController(HwDeviceExtension,srb->PathId);
+ return TRUE;
+ } else {
+
+ interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x2 : 0x0;
+ }
+
+ } else {
+
+ //
+ // Command complete - verify, write, or the SMART enable/disable.
+ //
+ // Also get_media_status
+
+ interruptReason = 0x3;
+ }
+ }
+ }
+
+ if (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) {
+
+ //
+ // Write the packet.
+ //
+
+ DebugPrint((2,
+ "AtapiInterrupt: Writing Atapi packet.\n"));
+
+ //
+ // Send CDB to device.
+ //
+
+ WriteBuffer(baseIoAddress1,
+ (PUSHORT)srb->Cdb,
+ 6);
+
+ switch (srb->Cdb[0]) {
+
+ case SCSIOP_RECEIVE:
+ case SCSIOP_SEND:
+ case SCSIOP_READ:
+ case SCSIOP_WRITE:
+ if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_USE_DMA) {
+ EnableBusMastering(HwDeviceExtension, srb);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+
+ } else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) {
+
+ //
+ // Write the data.
+ //
+
+ if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
+
+ //
+ // Pick up bytes to transfer and convert to words.
+ //
+
+ wordCount =
+ ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow);
+
+ wordCount |=
+ ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8;
+
+ //
+ // Covert bytes to words.
+ //
+
+ wordCount >>= 1;
+
+ if (wordCount != deviceExtension->WordsLeft) {
+ DebugPrint((3,
+ "AtapiInterrupt: %d words requested; %d words xferred\n",
+ deviceExtension->WordsLeft,
+ wordCount));
+ }
+
+ //
+ // Verify this makes sense.
+ //
+
+ if (wordCount > deviceExtension->WordsLeft) {
+ wordCount = deviceExtension->WordsLeft;
+ }
+
+ } else {
+
+ //
+ // IDE path. Check if words left is at least 256.
+ //
+
+ if (deviceExtension->WordsLeft < wordsThisInterrupt) {
+
+ //
+ // Transfer only words requested.
+ //
+
+ wordCount = deviceExtension->WordsLeft;
+
+ } else {
+
+ //
+ // Transfer next block.
+ //
+
+ wordCount = wordsThisInterrupt;
+ }
+ }
+
+ //
+ // Ensure that this is a write command.
+ //
+
+ if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ DebugPrint((3,
+ "AtapiInterrupt: Write interrupt\n"));
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ if (atapiDev || !deviceExtension->DWordIO) {
+
+ WriteBuffer(baseIoAddress1,
+ deviceExtension->DataBuffer,
+ wordCount);
+ } else {
+
+ PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1;
+
+ WriteBuffer2(address3,
+ (PULONG)(deviceExtension->DataBuffer),
+ wordCount / 2);
+ }
+ } else {
+
+ DebugPrint((1,
+ "AtapiInterrupt: Int reason %x, but srb is for a write %x.\n",
+ interruptReason,
+ srb));
+
+ //
+ // Fail this request.
+ //
+
+ status = SRB_STATUS_ERROR;
+ goto CompleteRequest;
+ }
+
+
+ //
+ // Advance data buffer pointer and bytes left.
+ //
+
+ deviceExtension->DataBuffer += wordCount;
+ deviceExtension->WordsLeft -= wordCount;
+
+ return TRUE;
+
+ } else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) {
+
+
+ if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
+
+ //
+ // Pick up bytes to transfer and convert to words.
+ //
+
+ wordCount =
+ ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow);
+
+ wordCount |=
+ ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8;
+
+ //
+ // Covert bytes to words.
+ //
+
+ wordCount >>= 1;
+
+ if (wordCount != deviceExtension->WordsLeft) {
+ DebugPrint((3,
+ "AtapiInterrupt: %d words requested; %d words xferred\n",
+ deviceExtension->WordsLeft,
+ wordCount));
+ }
+
+ //
+ // Verify this makes sense.
+ //
+
+ if (wordCount > deviceExtension->WordsLeft) {
+ wordCount = deviceExtension->WordsLeft;
+ }
+
+ } else {
+
+ //
+ // Check if words left is at least 256.
+ //
+
+ if (deviceExtension->WordsLeft < wordsThisInterrupt) {
+
+ //
+ // Transfer only words requested.
+ //
+
+ wordCount = deviceExtension->WordsLeft;
+
+ } else {
+
+ //
+ // Transfer next block.
+ //
+
+ wordCount = wordsThisInterrupt;
+ }
+ }
+
+ //
+ // Ensure that this is a read command.
+ //
+
+ if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ DebugPrint((3,
+ "AtapiInterrupt: Read interrupt\n"));
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ if (atapiDev || !deviceExtension->DWordIO) {
+ ReadBuffer(baseIoAddress1,
+ deviceExtension->DataBuffer,
+ wordCount);
+
+ } else {
+ PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1;
+
+ ReadBuffer2(address3,
+ (PULONG)(deviceExtension->DataBuffer),
+ wordCount / 2);
+ }
+ } else {
+
+ DebugPrint((1,
+ "AtapiInterrupt: Int reason %x, but srb is for a read %x.\n",
+ interruptReason,
+ srb));
+
+ //
+ // Fail this request.
+ //
+
+ status = SRB_STATUS_ERROR;
+ goto CompleteRequest;
+ }
+
+ //
+ // Translate ATAPI data back to SCSI data if needed
+ //
+
+ if (srb->Cdb[0] == ATAPI_MODE_SENSE &&
+ deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
+
+ //
+ //convert and adjust the wordCount
+ //
+
+ wordCount -= Atapi2Scsi(srb, (char *)deviceExtension->DataBuffer,
+ wordCount << 1);
+ }
+ //
+ // Advance data buffer pointer and bytes left.
+ //
+
+ deviceExtension->DataBuffer += wordCount;
+ deviceExtension->WordsLeft -= wordCount;
+
+ //
+ // Check for read command complete.
+ //
+
+ if (deviceExtension->WordsLeft == 0) {
+
+ if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
+
+ //
+ // Work around to make many atapi devices return correct sector size
+ // of 2048. Also certain devices will have sector count == 0x00, check
+ // for that also.
+ //
+
+ if ((srb->Cdb[0] == 0x25) &&
+ ((deviceExtension->IdentifyData[srb->TargetId].GeneralConfiguration >> 8) & 0x1f) == 0x05) {
+
+ deviceExtension->DataBuffer -= wordCount;
+ if (deviceExtension->DataBuffer[0] == 0x00) {
+
+ *((ULONG *) &(deviceExtension->DataBuffer[0])) = 0xFFFFFF7F;
+
+ }
+
+ *((ULONG *) &(deviceExtension->DataBuffer[2])) = 0x00080000;
+ deviceExtension->DataBuffer += wordCount;
+ }
+ } else {
+
+ //
+ // Completion for IDE drives.
+ //
+
+
+ if (deviceExtension->WordsLeft) {
+
+ status = SRB_STATUS_DATA_OVERRUN;
+
+ } else {
+
+ status = SRB_STATUS_SUCCESS;
+
+ }
+
+ goto CompleteRequest;
+
+ }
+ }
+
+ return TRUE;
+
+ } else if (interruptReason == 0x3 && !(statusByte & IDE_STATUS_DRQ)) {
+
+ //
+ // Command complete.
+ //
+
+ if (deviceExtension->WordsLeft) {
+
+ status = SRB_STATUS_DATA_OVERRUN;
+
+ } else {
+
+ status = SRB_STATUS_SUCCESS;
+
+ }
+
+CompleteRequest:
+
+ //
+ // Check and see if we are processing our secret (mechanism status/request sense) srb
+ //
+ if (deviceExtension->OriginalSrb) {
+
+ ULONG srbStatus;
+
+ if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
+
+ if (status == SRB_STATUS_SUCCESS) {
+ // Bingo!!
+ AtapiHwInitializeChanger (HwDeviceExtension,
+ srb->TargetId,
+ (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer);
+
+ // Get ready to issue the original srb
+ srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
+ deviceExtension->OriginalSrb = NULL;
+
+ } else {
+ // failed! Get the sense key and maybe try again
+ srb = deviceExtension->CurrentSrb = BuildRequestSenseSrb (
+ HwDeviceExtension,
+ deviceExtension->OriginalSrb->PathId,
+ deviceExtension->OriginalSrb->TargetId);
+ }
+
+ srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb);
+ if (srbStatus == SRB_STATUS_PENDING) {
+ return TRUE;
+ }
+
+ } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE)
+
+ PSENSE_DATA senseData = (PSENSE_DATA) srb->DataBuffer;
+
+ if (status == SRB_STATUS_DATA_OVERRUN) {
+ // Check to see if we at least get mininum number of bytes
+ if ((srb->DataTransferLength - deviceExtension->WordsLeft) >
+ (offsetof (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) {
+ status = SRB_STATUS_SUCCESS;
+ }
+ }
+
+ if (status == SRB_STATUS_SUCCESS) {
+ if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) &&
+ deviceExtension->MechStatusRetryCount) {
+
+ // The sense key doesn't say the last request is illegal, so try again
+ deviceExtension->MechStatusRetryCount--;
+ srb = deviceExtension->CurrentSrb = BuildMechanismStatusSrb (
+ HwDeviceExtension,
+ deviceExtension->OriginalSrb->PathId,
+ deviceExtension->OriginalSrb->TargetId);
+ } else {
+
+ // last request was illegal. No point trying again
+
+ AtapiHwInitializeChanger (HwDeviceExtension,
+ srb->TargetId,
+ (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
+
+ // Get ready to issue the original srb
+ srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
+ deviceExtension->OriginalSrb = NULL;
+ }
+
+ srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb);
+ if (srbStatus == SRB_STATUS_PENDING) {
+ return TRUE;
+ }
+ }
+ }
+
+ // If we get here, it means AtapiSendCommand() has failed
+ // Can't recover. Pretend the original srb has failed and complete it.
+
+ if (deviceExtension->OriginalSrb) {
+ AtapiHwInitializeChanger (HwDeviceExtension,
+ srb->TargetId,
+ (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
+ srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
+ deviceExtension->OriginalSrb = NULL;
+ }
+
+ // fake an error and read no data
+ status = SRB_STATUS_ERROR;
+ srb->ScsiStatus = 0;
+ deviceExtension->DataBuffer = srb->DataBuffer;
+ deviceExtension->WordsLeft = srb->DataTransferLength;
+ deviceExtension->RDP = FALSE;
+
+ } else if (status == SRB_STATUS_ERROR) {
+
+ //
+ // Map error to specific SRB status and handle request sense.
+ //
+
+ status = MapError(deviceExtension,
+ srb);
+
+ deviceExtension->RDP = FALSE;
+
+ } else {
+
+ //
+ // Wait for busy to drop.
+ //
+
+ for (i = 0; i < 30; i++) {
+ GetStatus(baseIoAddress1,statusByte);
+ if (!(statusByte & IDE_STATUS_BUSY)) {
+ break;
+ }
+ ScsiPortStallExecution(500);
+ }
+
+ if (i == 30) {
+
+ //
+ // reset the controller.
+ //
+
+ DebugPrint((1,
+ "AtapiInterrupt: Resetting due to BSY still up - %x. Base Io %x\n",
+ statusByte,
+ baseIoAddress1));
+ AtapiResetController(HwDeviceExtension,srb->PathId);
+ return TRUE;
+ }
+
+ //
+ // Check to see if DRQ is still up.
+ //
+
+ if (statusByte & IDE_STATUS_DRQ) {
+
+ for (i = 0; i < 500; i++) {
+ GetStatus(baseIoAddress1,statusByte);
+ if (!(statusByte & IDE_STATUS_DRQ)) {
+ break;
+ }
+ ScsiPortStallExecution(100);
+
+ }
+
+ if (i == 500) {
+
+ //
+ // reset the controller.
+ //
+
+ DebugPrint((1,
+ "AtapiInterrupt: Resetting due to DRQ still up - %x\n",
+ statusByte));
+ AtapiResetController(HwDeviceExtension,srb->PathId);
+ return TRUE;
+ }
+
+ }
+ }
+
+
+ //
+ // Clear interrupt expecting flag.
+ //
+
+ deviceExtension->ExpectingInterrupt = FALSE;
+
+ //
+ // Sanity check that there is a current request.
+ //
+
+ if (srb != NULL) {
+
+ //
+ // Set status in SRB.
+ //
+
+ srb->SrbStatus = (UCHAR)status;
+
+ //
+ // Check for underflow.
+ //
+
+ if (deviceExtension->WordsLeft) {
+
+ //
+ // Subtract out residual words and update if filemark hit,
+ // setmark hit , end of data, end of media...
+ //
+
+ if (!(deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_TAPE_DEVICE)) {
+ if (status == SRB_STATUS_DATA_OVERRUN) {
+ srb->DataTransferLength -= deviceExtension->WordsLeft;
+ } else {
+ srb->DataTransferLength = 0;
+ }
+ } else {
+ srb->DataTransferLength -= deviceExtension->WordsLeft;
+ }
+ }
+
+ if (srb->Function != SRB_FUNCTION_IO_CONTROL) {
+
+ //
+ // Indicate command complete.
+ //
+
+ if (!(deviceExtension->RDP)) {
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ }
+ } else {
+
+ PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+ UCHAR error = 0;
+
+ if (status != SRB_STATUS_SUCCESS) {
+ error = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
+ }
+
+ //
+ // Build the SMART status block depending upon the completion status.
+ //
+
+ cmdOutParameters->cBufferSize = wordCount;
+ cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
+ cmdOutParameters->DriverStatus.bIDEError = error;
+
+ //
+ // If the sub-command is return smart status, jam the value from cylinder low and high, into the
+ // data buffer.
+ //
+
+ if (deviceExtension->SmartCommand == RETURN_SMART_STATUS) {
+ cmdOutParameters->bBuffer[0] = RETURN_SMART_STATUS;
+ cmdOutParameters->bBuffer[1] = ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason);
+ cmdOutParameters->bBuffer[2] = ScsiPortReadPortUchar(&baseIoAddress1->Unused1);
+ cmdOutParameters->bBuffer[3] = ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow);
+ cmdOutParameters->bBuffer[4] = ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh);
+ cmdOutParameters->bBuffer[5] = ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect);
+ cmdOutParameters->bBuffer[6] = SMART_CMD;
+ cmdOutParameters->cBufferSize = 8;
+ }
+
+ //
+ // Indicate command complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ }
+
+ } else {
+
+ DebugPrint((1,
+ "AtapiInterrupt: No SRB!\n"));
+ }
+
+ //
+ // Indicate ready for next request.
+ //
+
+ if (!(deviceExtension->RDP)) {
+
+ //
+ // Clear current SRB.
+ //
+
+ deviceExtension->CurrentSrb = NULL;
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ } else {
+
+ ScsiPortNotification(RequestTimerCall,
+ HwDeviceExtension,
+ AtapiCallBack,
+ 2000);
+ }
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Unexpected int.
+ //
+
+ DebugPrint((3,
+ "AtapiInterrupt: Unexpected interrupt. InterruptReason %x. Status %x.\n",
+ interruptReason,
+ statusByte));
+ return FALSE;
+ }
+
+ return TRUE;
+
+} // end AtapiInterrupt()
+
+
+ULONG
+IdeSendSmartCommand(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles SMART enable, disable, read attributes and threshold commands.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ SRB status
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
+ PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+ SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+ PIDEREGS regs = &cmdInParameters.irDriveRegs;
+ ULONG i;
+ UCHAR statusByte,targetId;
+
+
+ if (cmdInParameters.irDriveRegs.bCommandReg == SMART_CMD) {
+
+ targetId = cmdInParameters.bDriveNumber;
+
+ //TODO optimize this check
+
+ if ((!(deviceExtension->DeviceFlags[targetId] & DFLAGS_DEVICE_PRESENT)) ||
+ (deviceExtension->DeviceFlags[targetId] & DFLAGS_ATAPI_DEVICE)) {
+
+ return SRB_STATUS_SELECTION_TIMEOUT;
+ }
+
+ deviceExtension->SmartCommand = cmdInParameters.irDriveRegs.bFeaturesReg;
+
+ //
+ // Determine which of the commands to carry out.
+ //
+
+ if ((cmdInParameters.irDriveRegs.bFeaturesReg == READ_ATTRIBUTES) ||
+ (cmdInParameters.irDriveRegs.bFeaturesReg == READ_THRESHOLDS)) {
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ if (statusByte & IDE_STATUS_BUSY) {
+ DebugPrint((1,
+ "IdeSendSmartCommand: Returning BUSY status\n"));
+ return SRB_STATUS_BUSY;
+ }
+
+ //
+ // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same).
+ //
+
+ for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1); i++) {
+ ((PUCHAR)cmdOutParameters)[i] = 0;
+ }
+
+ //
+ // Set data buffer pointer and words left.
+ //
+
+ deviceExtension->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
+ deviceExtension->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2;
+
+ //
+ // Indicate expecting an interrupt.
+ //
+
+ deviceExtension->ExpectingInterrupt = TRUE;
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,(UCHAR)(((targetId & 0x1) << 4) | 0xA0));
+ ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,regs->bFeaturesReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,regs->bSectorCountReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,regs->bSectorNumberReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,regs->bCylLowReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,regs->bCylHighReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,regs->bCommandReg);
+
+ //
+ // Wait for interrupt.
+ //
+
+ return SRB_STATUS_PENDING;
+
+ } else if ((cmdInParameters.irDriveRegs.bFeaturesReg == ENABLE_SMART) ||
+ (cmdInParameters.irDriveRegs.bFeaturesReg == DISABLE_SMART) ||
+ (cmdInParameters.irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) ||
+ (cmdInParameters.irDriveRegs.bFeaturesReg == ENABLE_DISABLE_AUTOSAVE) ||
+ (cmdInParameters.irDriveRegs.bFeaturesReg == EXECUTE_OFFLINE_DIAGS) ||
+ (cmdInParameters.irDriveRegs.bFeaturesReg == SAVE_ATTRIBUTE_VALUES)) {
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ if (statusByte & IDE_STATUS_BUSY) {
+ DebugPrint((1,
+ "IdeSendSmartCommand: Returning BUSY status\n"));
+ return SRB_STATUS_BUSY;
+ }
+
+ //
+ // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same).
+ //
+
+ for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) - 1); i++) {
+ ((PUCHAR)cmdOutParameters)[i] = 0;
+ }
+
+ //
+ // Set data buffer pointer and indicate no data transfer.
+ //
+
+ deviceExtension->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
+ deviceExtension->WordsLeft = 0;
+
+ //
+ // Indicate expecting an interrupt.
+ //
+
+ deviceExtension->ExpectingInterrupt = TRUE;
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,(UCHAR)(((targetId & 0x1) << 4) | 0xA0));
+ ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,regs->bFeaturesReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,regs->bSectorCountReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,regs->bSectorNumberReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,regs->bCylLowReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,regs->bCylHighReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,regs->bCommandReg);
+
+ //
+ // Wait for interrupt.
+ //
+
+ return SRB_STATUS_PENDING;
+ }
+ }
+
+ return SRB_STATUS_INVALID_REQUEST;
+
+} // end IdeSendSmartCommand()
+
+
+ULONG
+IdeReadWrite(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles IDE read and writes.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ SRB status
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
+ ULONG startingSector,i;
+ ULONG wordCount;
+ UCHAR statusByte,statusByte2;
+ UCHAR cylinderHigh,cylinderLow,drvSelect,sectorNumber;
+
+ //
+ // Select device 0 or 1.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
+
+ WaitOnBusy(baseIoAddress1,statusByte2);
+
+ if (statusByte2 & IDE_STATUS_BUSY) {
+ DebugPrint((1,
+ "IdeReadWrite: Returning BUSY status\n"));
+ return SRB_STATUS_BUSY;
+ }
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_USE_DMA) {
+ if (!PrepareForBusMastering(HwDeviceExtension, Srb))
+ return SRB_STATUS_ERROR;
+ }
+
+ //
+ // Set data buffer pointer and words left.
+ //
+
+ deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
+ deviceExtension->WordsLeft = Srb->DataTransferLength / 2;
+
+ //
+ // Indicate expecting an interrupt.
+ //
+
+ deviceExtension->ExpectingInterrupt = TRUE;
+
+ //
+ // Set up sector count register. Round up to next block.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,
+ (UCHAR)((Srb->DataTransferLength + 0x1FF) / 0x200));
+
+ //
+ // Get starting sector number from CDB.
+ //
+
+ startingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+
+ DebugPrint((2,
+ "IdeReadWrite: Starting sector is %x, Number of bytes %x\n",
+ startingSector,
+ Srb->DataTransferLength));
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_LBA) {
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR) (((Srb->TargetId & 0x1) << 4) |
+ 0xA0 |
+ IDE_LBA_MODE |
+ ((startingSector & 0x0f000000) >> 24)));
+
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,
+ (UCHAR) ((startingSector & 0x000000ff) >> 0));
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,
+ (UCHAR) ((startingSector & 0x0000ff00) >> 8));
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,
+ (UCHAR) ((startingSector & 0x00ff0000) >> 16));
+
+ } else { //CHS
+
+ //
+ // Set up sector number register.
+ //
+
+ sectorNumber = (UCHAR)((startingSector % deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) + 1);
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,sectorNumber);
+
+ //
+ // Set up cylinder low register.
+ //
+
+ cylinderLow = (UCHAR)(startingSector / (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads));
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,cylinderLow);
+
+ //
+ // Set up cylinder high register.
+ //
+
+ cylinderHigh = (UCHAR)((startingSector / (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)) >> 8);
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,cylinderHigh);
+
+ //
+ // Set up head and drive select register.
+ //
+
+ drvSelect = (UCHAR)(((startingSector / deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) %
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads) |((Srb->TargetId & 0x1) << 4) | 0xA0);
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,drvSelect);
+
+ DebugPrint((2,
+ "IdeReadWrite: Cylinder %x Head %x Sector %x\n",
+ startingSector /
+ (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads),
+ (startingSector /
+ deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) %
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads,
+ startingSector %
+ deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack + 1));
+ }
+
+ //
+ // Check if write request.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ //
+ // Send read command.
+ //
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,
+ deviceExtension->DeviceParameters[Srb->TargetId].IdeReadCommand);
+
+ } else {
+
+
+ //
+ // Send write command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,
+ deviceExtension->DeviceParameters[Srb->TargetId].IdeWriteCommand);
+
+ if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_USE_DMA)) {
+
+ if (deviceExtension->WordsLeft < deviceExtension->DeviceParameters[Srb->TargetId].MaxWordPerInterrupt) {
+ wordCount = deviceExtension->WordsLeft;
+ } else {
+ wordCount = deviceExtension->DeviceParameters[Srb->TargetId].MaxWordPerInterrupt;
+ }
+ //
+ // Wait for BSY and DRQ.
+ //
+
+ WaitOnBaseBusy(baseIoAddress1,statusByte);
+
+ if (statusByte & IDE_STATUS_BUSY) {
+
+ DebugPrint((1,
+ "IdeReadWrite 2: Returning BUSY status %x\n",
+ statusByte));
+ return SRB_STATUS_BUSY;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ GetBaseStatus(baseIoAddress1, statusByte);
+ if (statusByte & IDE_STATUS_DRQ) {
+ break;
+ }
+ ScsiPortStallExecution(200);
+
+ }
+
+ if (!(statusByte & IDE_STATUS_DRQ)) {
+
+ DebugPrint((1,
+ "IdeReadWrite: DRQ never asserted (%x) original status (%x)\n",
+ statusByte,
+ statusByte2));
+
+ deviceExtension->WordsLeft = 0;
+
+ //
+ // Clear interrupt expecting flag.
+ //
+
+ deviceExtension->ExpectingInterrupt = FALSE;
+
+ //
+ // Clear current SRB.
+ //
+
+ deviceExtension->CurrentSrb = NULL;
+
+ return SRB_STATUS_TIMEOUT;
+ }
+
+ //
+ // Write next 256 words.
+ //
+
+ WriteBuffer(baseIoAddress1,
+ deviceExtension->DataBuffer,
+ wordCount);
+
+ //
+ // Adjust buffer address and words left count.
+ //
+
+ deviceExtension->WordsLeft -= wordCount;
+ deviceExtension->DataBuffer += wordCount;
+
+ }
+ }
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_USE_DMA) {
+ EnableBusMastering(HwDeviceExtension, Srb);
+ }
+
+ //
+ // Wait for interrupt.
+ //
+
+ return SRB_STATUS_PENDING;
+
+} // end IdeReadWrite()
+
+
+
+ULONG
+IdeVerify(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles IDE Verify.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ SRB status
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
+ ULONG startingSector;
+ ULONG sectors;
+ ULONG endSector;
+ USHORT sectorCount;
+
+ //
+ // Drive has these number sectors.
+ //
+
+ sectors = deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders;
+
+ DebugPrint((3,
+ "IdeVerify: Total sectors %x\n",
+ sectors));
+
+ //
+ // Get starting sector number from CDB.
+ //
+
+ startingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+
+ DebugPrint((3,
+ "IdeVerify: Starting sector %x. Number of blocks %x\n",
+ startingSector,
+ ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb));
+
+ sectorCount = (USHORT)(((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb );
+ endSector = startingSector + sectorCount;
+
+ DebugPrint((3,
+ "IdeVerify: Ending sector %x\n",
+ endSector));
+
+ if (endSector > sectors) {
+
+ //
+ // Too big, round down.
+ //
+
+ DebugPrint((1,
+ "IdeVerify: Truncating request to %x blocks\n",
+ sectors - startingSector - 1));
+
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,
+ (UCHAR)(sectors - startingSector - 1));
+
+ } else {
+
+ //
+ // Set up sector count register. Round up to next block.
+ //
+
+ if (sectorCount > 0xFF) {
+ sectorCount = (USHORT)0xFF;
+ }
+
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,(UCHAR)sectorCount);
+ }
+
+ //
+ // Set data buffer pointer and words left.
+ //
+
+ deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
+ deviceExtension->WordsLeft = Srb->DataTransferLength / 2;
+
+ //
+ // Indicate expecting an interrupt.
+ //
+
+ deviceExtension->ExpectingInterrupt = TRUE;
+
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_LBA) { // LBA
+
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,
+ (UCHAR) ((startingSector & 0x000000ff) >> 0));
+
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,
+ (UCHAR) ((startingSector & 0x0000ff00) >> 8));
+
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,
+ (UCHAR) ((startingSector & 0x00ff0000) >> 16));
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR) (((Srb->TargetId & 0x1) << 4) |
+ 0xA0 |
+ IDE_LBA_MODE |
+ (startingSector & 0x0f000000 >> 24)));
+
+ DebugPrint((2,
+ "IdeVerify: LBA: startingSector %x\n",
+ startingSector));
+
+ } else { //CHS
+
+ //
+ // Set up sector number register.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,
+ (UCHAR)((startingSector %
+ deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) + 1));
+
+ //
+ // Set up cylinder low register.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,
+ (UCHAR)(startingSector /
+ (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)));
+
+ //
+ // Set up cylinder high register.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,
+ (UCHAR)((startingSector /
+ (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)) >> 8));
+
+ //
+ // Set up head and drive select register.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((startingSector /
+ deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) %
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads) |
+ ((Srb->TargetId & 0x1) << 4) | 0xA0));
+
+ DebugPrint((2,
+ "IdeVerify: CHS: Cylinder %x Head %x Sector %x\n",
+ startingSector /
+ (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads),
+ (startingSector /
+ deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) %
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads,
+ startingSector %
+ deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack + 1));
+ }
+
+ //
+ // Send verify command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,
+ IDE_COMMAND_VERIFY);
+
+ //
+ // Wait for interrupt.
+ //
+
+ return SRB_STATUS_PENDING;
+
+} // end IdeVerify()
+
+
+VOID
+Scsi2Atapi(
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Convert SCSI packet command to Atapi packet command.
+
+Arguments:
+
+ Srb - IO request packet
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Change the cdb length
+ //
+
+ Srb->CdbLength = 12;
+
+ switch (Srb->Cdb[0]) {
+ case SCSIOP_MODE_SENSE: {
+ PMODE_SENSE_10 modeSense10 = (PMODE_SENSE_10)Srb->Cdb;
+ UCHAR PageCode = ((PCDB)Srb->Cdb)->MODE_SENSE.PageCode;
+ UCHAR Length = ((PCDB)Srb->Cdb)->MODE_SENSE.AllocationLength;
+
+ AtapiZeroMemory(Srb->Cdb,MAXIMUM_CDB_SIZE);
+
+ modeSense10->OperationCode = ATAPI_MODE_SENSE;
+ modeSense10->PageCode = PageCode;
+ modeSense10->ParameterListLengthMsb = 0;
+ modeSense10->ParameterListLengthLsb = Length;
+ break;
+ }
+
+ case SCSIOP_MODE_SELECT: {
+ PMODE_SELECT_10 modeSelect10 = (PMODE_SELECT_10)Srb->Cdb;
+ UCHAR Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength;
+
+ //
+ // Zero the original cdb
+ //
+
+ AtapiZeroMemory(Srb->Cdb,MAXIMUM_CDB_SIZE);
+
+ modeSelect10->OperationCode = ATAPI_MODE_SELECT;
+ modeSelect10->PFBit = 1;
+ modeSelect10->ParameterListLengthMsb = 0;
+ modeSelect10->ParameterListLengthLsb = Length;
+ break;
+ }
+
+ case SCSIOP_FORMAT_UNIT:
+ Srb->Cdb[0] = ATAPI_FORMAT_UNIT;
+ break;
+ }
+}
+
+
+
+ULONG
+AtapiSendCommand(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Send ATAPI packet command to device.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PATAPI_REGISTERS_1 baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
+ PATAPI_REGISTERS_2 baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
+ ULONG i;
+ ULONG flags;
+ UCHAR statusByte,byteCountLow,byteCountHigh;
+
+ //
+ // We need to know how many platters our atapi cd-rom device might have.
+ // Before anyone tries to send a srb to our target for the first time,
+ // we must "secretly" send down a separate mechanism status srb in order to
+ // initialize our device extension changer data. That's how we know how
+ // many platters our target has.
+ //
+ if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_CHANGER_INITED) &&
+ !deviceExtension->OriginalSrb) {
+
+ ULONG srbStatus;
+
+ //
+ // Set this flag now. If the device hangs on the mech. status
+ // command, we will not have the change to set it.
+ //
+ deviceExtension->DeviceFlags[Srb->TargetId] |= DFLAGS_CHANGER_INITED;
+
+ deviceExtension->MechStatusRetryCount = 3;
+ deviceExtension->CurrentSrb = BuildMechanismStatusSrb (
+ HwDeviceExtension,
+ Srb->PathId,
+ Srb->TargetId);
+ deviceExtension->OriginalSrb = Srb;
+
+ srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb);
+ if (srbStatus == SRB_STATUS_PENDING) {
+ return srbStatus;
+ } else {
+ deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
+ deviceExtension->OriginalSrb = NULL;
+ AtapiHwInitializeChanger (HwDeviceExtension,
+ Srb->TargetId,
+ (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
+ // fall out
+ }
+ }
+
+ DebugPrint((2,
+ "AtapiSendCommand: Command %x to TargetId %d lun %d\n",
+ Srb->Cdb[0],
+ Srb->TargetId,
+ Srb->Lun));
+
+ //
+ // Make sure command is to ATAPI device.
+ //
+
+ flags = deviceExtension->DeviceFlags[Srb->TargetId];
+ if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
+ if ((Srb->Lun) > (deviceExtension->DiscsPresent[Srb->TargetId] - 1)) {
+
+ //
+ // Indicate no device found at this address.
+ //
+
+ return SRB_STATUS_SELECTION_TIMEOUT;
+ }
+ } else if (Srb->Lun > 0) {
+ return SRB_STATUS_SELECTION_TIMEOUT;
+ }
+
+ if (!(flags & DFLAGS_ATAPI_DEVICE)) {
+ return SRB_STATUS_SELECTION_TIMEOUT;
+ }
+
+ //
+ // Select device 0 or 1.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
+
+ //
+ // Verify that controller is ready for next command.
+ //
+
+ GetStatus(baseIoAddress1,statusByte);
+
+ DebugPrint((2,
+ "AtapiSendCommand: Entered with status %x\n",
+ statusByte));
+
+ if (statusByte & IDE_STATUS_BUSY) {
+ DebugPrint((1,
+ "AtapiSendCommand: Device busy (%x)\n",
+ statusByte));
+ return SRB_STATUS_BUSY;
+
+ }
+
+ if (statusByte & IDE_STATUS_ERROR) {
+ if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
+
+ DebugPrint((1,
+ "AtapiSendCommand: Error on entry: (%x)\n",
+ statusByte));
+ //
+ // Read the error reg. to clear it and fail this request.
+ //
+
+ return MapError(deviceExtension,
+ Srb);
+ }
+ }
+
+ //
+ // If a tape drive has doesn't have DSC set and the last command is restrictive, don't send
+ // the next command. See discussion of Restrictive Delayed Process commands in QIC-157.
+ //
+
+ if ((!(statusByte & IDE_STATUS_DSC)) &&
+ (flags & DFLAGS_TAPE_DEVICE) && deviceExtension->RDP) {
+ ScsiPortStallExecution(1000);
+ DebugPrint((2,"AtapiSendCommand: DSC not set. %x\n",statusByte));
+ return SRB_STATUS_BUSY;
+ }
+
+ if (IS_RDP(Srb->Cdb[0])) {
+
+ deviceExtension->RDP = TRUE;
+
+ DebugPrint((3,
+ "AtapiSendCommand: %x mapped as DSC restrictive\n",
+ Srb->Cdb[0]));
+
+ } else {
+
+ deviceExtension->RDP = FALSE;
+ }
+
+ if (statusByte & IDE_STATUS_DRQ) {
+
+ DebugPrint((1,
+ "AtapiSendCommand: Entered with status (%x). Attempting to recover.\n",
+ statusByte));
+ //
+ // Try to drain the data that one preliminary device thinks that it has
+ // to transfer. Hopefully this random assertion of DRQ will not be present
+ // in production devices.
+ //
+
+ for (i = 0; i < 0x10000; i++) {
+
+ GetStatus(baseIoAddress1, statusByte);
+
+ if (statusByte & IDE_STATUS_DRQ) {
+
+ ScsiPortReadPortUshort(&baseIoAddress1->Data);
+
+ } else {
+
+ break;
+ }
+ }
+
+ if (i == 0x10000) {
+
+ DebugPrint((1,
+ "AtapiSendCommand: DRQ still asserted.Status (%x)\n",
+ statusByte));
+
+ AtapiSoftReset(baseIoAddress1,Srb->TargetId, FALSE);
+
+ DebugPrint((1,
+ "AtapiSendCommand: Issued soft reset to Atapi device. \n"));
+
+ //
+ // Re-initialize Atapi device.
+ //
+
+ IssueIdentify(HwDeviceExtension,
+ (Srb->TargetId & 0x1),
+ (Srb->TargetId >> 1),
+ IDE_COMMAND_ATAPI_IDENTIFY,
+ FALSE);
+
+ //
+ // Inform the port driver that the bus has been reset.
+ //
+
+ ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
+
+ //
+ // Clean up device extension fields that AtapiStartIo won't.
+ //
+
+ deviceExtension->ExpectingInterrupt = FALSE;
+ deviceExtension->RDP = FALSE;
+
+ return SRB_STATUS_BUS_RESET;
+
+ }
+ }
+
+ if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
+
+ //
+ // As the cdrom driver sets the LUN field in the cdb, it must be removed.
+ //
+
+ Srb->Cdb[1] &= ~0xE0;
+
+ if ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY) && (flags & DFLAGS_SANYO_ATAPI_CHANGER)) {
+
+ //
+ // Torisan changer. TUR's are overloaded to be platter switches.
+ //
+
+ Srb->Cdb[7] = Srb->Lun;
+
+ }
+ }
+
+ switch (Srb->Cdb[0]) {
+
+ //
+ // Convert SCSI to ATAPI commands if needed
+ //
+ case SCSIOP_MODE_SENSE:
+ case SCSIOP_MODE_SELECT:
+ case SCSIOP_FORMAT_UNIT:
+ if (!(flags & DFLAGS_TAPE_DEVICE)) {
+ Scsi2Atapi(Srb);
+ }
+
+ break;
+
+ case SCSIOP_RECEIVE:
+ case SCSIOP_SEND:
+ case SCSIOP_READ:
+ case SCSIOP_WRITE:
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_USE_DMA) {
+ if (!PrepareForBusMastering(HwDeviceExtension, Srb))
+ return SRB_STATUS_ERROR;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+
+ //
+ // Set data buffer pointer and words left.
+ //
+
+ deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
+ deviceExtension->WordsLeft = Srb->DataTransferLength / 2;
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ //
+ // Write transfer byte count to registers.
+ //
+
+ byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
+ byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
+
+ if (Srb->DataTransferLength >= 0x10000) {
+ byteCountLow = byteCountHigh = 0xFF;
+ }
+
+ ScsiPortWritePortUchar(&baseIoAddress1->ByteCountLow,byteCountLow);
+ ScsiPortWritePortUchar(&baseIoAddress1->ByteCountHigh, byteCountHigh);
+
+ ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,0);
+ if ((Srb->Cdb[0] == SCSIOP_READ) ||
+ (Srb->Cdb[0] == SCSIOP_WRITE) ||
+ (Srb->Cdb[0] == SCSIOP_SEND) ||
+ (Srb->Cdb[0] == SCSIOP_RECEIVE)) {
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_USE_DMA) {
+ ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1, 0x1);
+ }
+ }
+
+ if (flags & DFLAGS_INT_DRQ) {
+
+ //
+ // This device interrupts when ready to receive the packet.
+ //
+ // Write ATAPI packet command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,
+ IDE_COMMAND_ATAPI_PACKET);
+
+ DebugPrint((3,
+ "AtapiSendCommand: Wait for int. to send packet. Status (%x)\n",
+ statusByte));
+
+ deviceExtension->ExpectingInterrupt = TRUE;
+
+ return SRB_STATUS_PENDING;
+
+ } else {
+
+ //
+ // Write ATAPI packet command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,
+ IDE_COMMAND_ATAPI_PACKET);
+
+ //
+ // Wait for DRQ.
+ //
+
+ WaitOnBusy(baseIoAddress1, statusByte);
+ WaitForDrq(baseIoAddress1, statusByte);
+
+ if (!(statusByte & IDE_STATUS_DRQ)) {
+
+ DebugPrint((1,
+ "AtapiSendCommand: DRQ never asserted (%x)\n",
+ statusByte));
+ return SRB_STATUS_ERROR;
+ }
+ }
+
+ //
+ // Need to read status register.
+ //
+
+ GetBaseStatus(baseIoAddress1, statusByte);
+
+ //
+ // Send CDB to device.
+ //
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ WriteBuffer(baseIoAddress1,
+ (PUSHORT)Srb->Cdb,
+ 6);
+
+ //
+ // Indicate expecting an interrupt and wait for it.
+ //
+
+ deviceExtension->ExpectingInterrupt = TRUE;
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_RECEIVE:
+ case SCSIOP_SEND:
+ case SCSIOP_READ:
+ case SCSIOP_WRITE:
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_USE_DMA) {
+ EnableBusMastering(HwDeviceExtension, Srb);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return SRB_STATUS_PENDING;
+
+} // end AtapiSendCommand()
+
+ULONG
+IdeSendCommand(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Program ATA registers for IDE disk transfer.
+
+Arguments:
+
+ HwDeviceExtension - ATAPI driver storage.
+ Srb - System request block.
+
+Return Value:
+
+ SRB status (pending if all goes well).
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
+ PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
+ PCDB cdb;
+
+ UCHAR statusByte,errorByte;
+ ULONG status;
+ ULONG i;
+ PMODE_PARAMETER_HEADER modeData;
+
+ DebugPrint((2,
+ "IdeSendCommand: Command %x to device %d\n",
+ Srb->Cdb[0],
+ Srb->TargetId));
+
+
+
+ switch (Srb->Cdb[0]) {
+ case SCSIOP_INQUIRY:
+
+ //
+ // Filter out all TIDs but 0 and 1 since this is an IDE interface
+ // which support up to two devices.
+ //
+
+ if ((Srb->Lun != 0) ||
+ (!deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
+
+ //
+ // Indicate no device found at this address.
+ //
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ } else {
+
+ PINQUIRYDATA inquiryData = Srb->DataBuffer;
+ PIDENTIFY_DATA2 identifyData = &deviceExtension->IdentifyData[Srb->TargetId];
+
+ //
+ // Zero INQUIRY data structure.
+ //
+
+ for (i = 0; i < Srb->DataTransferLength; i++) {
+ ((PUCHAR)Srb->DataBuffer)[i] = 0;
+ }
+
+ //
+ // Standard IDE interface only supports disks.
+ //
+
+ inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+
+ //
+ // Set the removable bit, if applicable.
+ //
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_REMOVABLE_DRIVE) {
+ inquiryData->RemovableMedia = 1;
+ }
+
+ //
+ // Fill in vendor identification fields.
+ //
+
+ for (i = 0; i < 20; i += 2) {
+ inquiryData->VendorId[i] =
+ ((PUCHAR)identifyData->ModelNumber)[i + 1];
+ inquiryData->VendorId[i+1] =
+ ((PUCHAR)identifyData->ModelNumber)[i];
+ }
+
+ //
+ // Initialize unused portion of product id.
+ //
+
+ for (i = 0; i < 4; i++) {
+ inquiryData->ProductId[12+i] = ' ';
+ }
+
+ //
+ // Move firmware revision from IDENTIFY data to
+ // product revision in INQUIRY data.
+ //
+
+ for (i = 0; i < 4; i += 2) {
+ inquiryData->ProductRevisionLevel[i] =
+ ((PUCHAR)identifyData->FirmwareRevision)[i+1];
+ inquiryData->ProductRevisionLevel[i+1] =
+ ((PUCHAR)identifyData->FirmwareRevision)[i];
+ }
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SCSIOP_MODE_SENSE:
+
+ //
+ // This is used to determine of the media is write-protected.
+ // Since IDE does not support mode sense then we will modify just the portion we need
+ // so the higher level driver can determine if media is protected.
+ //
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_GET_MEDIA_STATUS);
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ if (!(statusByte & IDE_STATUS_ERROR)){
+
+ //
+ // no error occured return success, media is not protected
+ //
+
+ deviceExtension->ExpectingInterrupt = FALSE;
+ status = SRB_STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // error occured, handle it locally, clear interrupt
+ //
+
+ errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
+
+ GetBaseStatus(baseIoAddress1, statusByte);
+ deviceExtension->ExpectingInterrupt = FALSE;
+ status = SRB_STATUS_SUCCESS;
+
+ if (errorByte & IDE_ERROR_DATA_ERROR) {
+
+ //
+ //media is write-protected, set bit in mode sense buffer
+ //
+
+ modeData = (PMODE_PARAMETER_HEADER)Srb->DataBuffer;
+
+ Srb->DataTransferLength = sizeof(MODE_PARAMETER_HEADER);
+ modeData->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
+ }
+ }
+ status = SRB_STATUS_SUCCESS;
+ } else {
+ status = SRB_STATUS_INVALID_REQUEST;
+ }
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
+
+ //
+ // Select device 0 or 1.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_GET_MEDIA_STATUS);
+
+ //
+ // Wait for busy. If media has not changed, return success
+ //
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ if (!(statusByte & IDE_STATUS_ERROR)){
+ deviceExtension->ExpectingInterrupt = FALSE;
+ status = SRB_STATUS_SUCCESS;
+ } else {
+ errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
+ if (errorByte == IDE_ERROR_DATA_ERROR){
+
+ //
+ // Special case: If current media is write-protected,
+ // the 0xDA command will always fail since the write-protect bit
+ // is sticky,so we can ignore this error
+ //
+
+ GetBaseStatus(baseIoAddress1, statusByte);
+ deviceExtension->ExpectingInterrupt = FALSE;
+ status = SRB_STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Request sense buffer to be build
+ //
+ deviceExtension->ExpectingInterrupt = TRUE;
+ status = SRB_STATUS_PENDING;
+ }
+ }
+ } else {
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SCSIOP_READ_CAPACITY:
+
+ //
+ // Claim 512 byte blocks (big-endian).
+ //
+
+ ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000;
+
+ //
+ // Calculate last sector.
+ //
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_LBA) {
+ // LBA device
+ i = deviceExtension->IdentifyData[Srb->TargetId].UserAddressableSectors - 1;
+
+ DebugPrint((1,
+ "IDE LBA disk %x - total # of sectors = 0x%x\n",
+ Srb->TargetId,
+ deviceExtension->IdentifyData[Srb->TargetId].UserAddressableSectors));
+
+ } else {
+ // CHS device
+ i = (deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads *
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders *
+ deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) - 1;
+
+ DebugPrint((1,
+ "IDE CHS disk %x - #sectors %x, #heads %x, #cylinders %x\n",
+ Srb->TargetId,
+ deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack,
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads,
+ deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders));
+
+ }
+
+ ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress =
+ (((PUCHAR)&i)[0] << 24) | (((PUCHAR)&i)[1] << 16) |
+ (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3];
+
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSIOP_VERIFY:
+ status = IdeVerify(HwDeviceExtension,Srb);
+
+ break;
+
+ case SCSIOP_READ:
+ case SCSIOP_WRITE:
+
+ status = IdeReadWrite(HwDeviceExtension,
+ Srb);
+ break;
+
+ case SCSIOP_START_STOP_UNIT:
+
+ //
+ //Determine what type of operation we should perform
+ //
+ cdb = (PCDB)Srb->Cdb;
+
+ if (cdb->START_STOP.LoadEject == 1){
+
+ //
+ // Eject media,
+ // first select device 0 or 1.
+ //
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_MEDIA_EJECT);
+ }
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSIOP_MEDIUM_REMOVAL:
+
+ cdb = (PCDB)Srb->Cdb;
+
+ WaitOnBusy(baseIoAddress1,statusByte);
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
+ (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
+ if (cdb->MEDIA_REMOVAL.Prevent == TRUE) {
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_DOOR_LOCK);
+ } else {
+ ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_DOOR_UNLOCK);
+ }
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSIOP_REQUEST_SENSE:
+ // this function makes sense buffers to report the results
+ // of the original GET_MEDIA_STATUS command
+
+ if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
+ status = IdeBuildSenseBuffer(HwDeviceExtension,Srb);
+ break;
+ }
+
+ // ATA_PASSTHORUGH
+ case SCSIOP_ATA_PASSTHROUGH:
+ {
+ PIDEREGS pIdeReg;
+ pIdeReg = (PIDEREGS) &(Srb->Cdb[2]);
+
+ pIdeReg->bDriveHeadReg &= 0x0f;
+ pIdeReg->bDriveHeadReg |= (UCHAR) (((Srb->TargetId & 0x1) << 4) | 0xA0);
+
+ if (pIdeReg->bReserved == 0) { // execute ATA command
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, pIdeReg->bDriveHeadReg);
+ ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1, pIdeReg->bFeaturesReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockCount, pIdeReg->bSectorCountReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber, pIdeReg->bSectorNumberReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow, pIdeReg->bCylLowReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, pIdeReg->bCylHighReg);
+ ScsiPortWritePortUchar(&baseIoAddress1->Command, pIdeReg->bCommandReg);
+
+ ScsiPortStallExecution(1); // wait for busy to be set
+ WaitOnBusy(baseIoAddress1,statusByte); // wait for busy to be clear
+ GetBaseStatus(baseIoAddress1, statusByte);
+ if (statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
+
+ if (Srb->SenseInfoBuffer) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND;
+ senseBuffer->AdditionalSenseCode = 0;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ }
+ status = SRB_STATUS_ERROR;
+ } else {
+
+ if (statusByte & IDE_STATUS_DRQ) {
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ReadBuffer(baseIoAddress1,
+ (PUSHORT) Srb->DataBuffer,
+ Srb->DataTransferLength / 2);
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+ WriteBuffer(baseIoAddress1,
+ (PUSHORT) Srb->DataBuffer,
+ Srb->DataTransferLength / 2);
+ }
+ }
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ } else { // read task register
+
+ ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, pIdeReg->bDriveHeadReg);
+
+ pIdeReg = (PIDEREGS) Srb->DataBuffer;
+ pIdeReg->bDriveHeadReg = ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect);
+ pIdeReg->bFeaturesReg = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
+ pIdeReg->bSectorCountReg = ScsiPortReadPortUchar(&baseIoAddress1->BlockCount);
+ pIdeReg->bSectorNumberReg = ScsiPortReadPortUchar(&baseIoAddress1->BlockNumber);
+ pIdeReg->bCylLowReg = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
+ pIdeReg->bCylHighReg = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
+ pIdeReg->bCommandReg = ScsiPortReadPortUchar(&baseIoAddress1->Command);
+ status = SRB_STATUS_SUCCESS;
+ }
+ }
+ break;
+
+ default:
+
+ DebugPrint((1,
+ "IdeSendCommand: Unsupported command %x\n",
+ Srb->Cdb[0]));
+
+ status = SRB_STATUS_INVALID_REQUEST;
+
+ } // end switch
+
+ return status;
+
+} // end IdeSendCommand()
+
+VOID
+IdeMediaStatus(
+ BOOLEAN EnableMSN,
+ IN PVOID HwDeviceExtension,
+ ULONG Channel
+ )
+/*++
+
+Routine Description:
+
+ Enables disables media status notification
+
+Arguments:
+
+HwDeviceExtension - ATAPI driver storage.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_REGISTERS_1 baseIoAddress = deviceExtension->BaseIoAddress1[Channel >> 1];
+ UCHAR statusByte,errorByte;
+
+
+ if (EnableMSN == TRUE){
+
+ //
+ // If supported enable Media Status Notification support
+ //
+
+ if ((deviceExtension->DeviceFlags[Channel] & DFLAGS_REMOVABLE_DRIVE)) {
+
+ //
+ // enable
+ //
+ ScsiPortWritePortUchar(&baseIoAddress->DriveSelect,
+ (UCHAR)(((Channel & 0x1) << 4) | 0xA0));
+ ScsiPortWritePortUchar((PUCHAR)baseIoAddress + 1,(UCHAR) (0x95));
+ ScsiPortWritePortUchar(&baseIoAddress->Command,
+ IDE_COMMAND_ENABLE_MEDIA_STATUS);
+
+ WaitOnBaseBusy(baseIoAddress,statusByte);
+
+ if (statusByte & IDE_STATUS_ERROR) {
+ //
+ // Read the error register.
+ //
+ errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress + 1);
+
+ DebugPrint((1,
+ "IdeMediaStatus: Error enabling media status. Status %x, error byte %x\n",
+ statusByte,
+ errorByte));
+ } else {
+ deviceExtension->DeviceFlags[Channel] |= DFLAGS_MEDIA_STATUS_ENABLED;
+ DebugPrint((1,"IdeMediaStatus: Media Status Notification Supported\n"));
+ deviceExtension->ReturningMediaStatus = 0;
+
+ }
+
+ }
+ } else { // end if EnableMSN == TRUE
+
+ //
+ // disable if previously enabled
+ //
+ if ((deviceExtension->DeviceFlags[Channel] & DFLAGS_MEDIA_STATUS_ENABLED)) {
+
+ ScsiPortWritePortUchar(&baseIoAddress->DriveSelect,
+ (UCHAR)(((Channel & 0x1) << 4) | 0xA0));
+ ScsiPortWritePortUchar((PUCHAR)baseIoAddress + 1,(UCHAR) (0x31));
+ ScsiPortWritePortUchar(&baseIoAddress->Command,
+ IDE_COMMAND_ENABLE_MEDIA_STATUS);
+
+ WaitOnBaseBusy(baseIoAddress,statusByte);
+ deviceExtension->DeviceFlags[Channel] &= ~DFLAGS_MEDIA_STATUS_ENABLED;
+ }
+
+
+ }
+
+
+
+}
+
+ULONG
+IdeBuildSenseBuffer(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Builts an artificial sense buffer to report the results of a GET_MEDIA_STATUS
+ command. This function is invoked to satisfy the SCSIOP_REQUEST_SENSE.
+Arguments:
+
+ HwDeviceExtension - ATAPI driver storage.
+ Srb - System request block.
+
+Return Value:
+
+ SRB status (ALWAYS SUCCESS).
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG status;
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->DataBuffer;
+
+
+ if (senseBuffer){
+
+
+ if(deviceExtension->ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE) {
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+ } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE_REQ) {
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+ } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_END_OF_MEDIA) {
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+ } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_DATA_ERROR) {
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_DATA_PROTECT;
+ senseBuffer->AdditionalSenseCode = 0;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+ }
+ return SRB_STATUS_SUCCESS;
+ }
+ return SRB_STATUS_ERROR;
+
+}// End of IdeBuildSenseBuffer
+
+
+
+
+BOOLEAN
+AtapiStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to start an IO request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG status;
+
+ //
+ // Determine which function.
+ //
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Sanity check. Only one request can be outstanding on a
+ // controller.
+ //
+
+ if (deviceExtension->CurrentSrb) {
+
+ DebugPrint((1,
+ "AtapiStartIo: Already have a request!\n"));
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ return FALSE;
+ }
+
+ //
+ // Indicate that a request is active on the controller.
+ //
+
+ deviceExtension->CurrentSrb = Srb;
+
+ //
+ // Send command to device.
+ //
+
+ // ATA_PASSTHORUGH
+ if (Srb->Cdb[0] == SCSIOP_ATA_PASSTHROUGH) {
+
+ status = IdeSendCommand(HwDeviceExtension,
+ Srb);
+
+ } else if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
+
+ status = AtapiSendCommand(HwDeviceExtension,
+ Srb);
+
+ } else if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) {
+
+ status = IdeSendCommand(HwDeviceExtension,
+ Srb);
+ } else {
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ }
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ if (!deviceExtension->CurrentSrb) {
+
+ DebugPrint((1, "AtapiStartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ status = SRB_STATUS_ABORT_FAILED;
+
+ break;
+ }
+
+ //
+ // Abort function indicates that a request timed out.
+ // Call reset routine. Card will only be reset if
+ // status indicates something is wrong.
+ // Fall through to reset code.
+ //
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset Atapi and SCSI bus.
+ //
+
+ DebugPrint((1, "AtapiStartIo: Reset bus request received\n"));
+
+ if (!AtapiResetController(deviceExtension,
+ Srb->PathId)) {
+
+ DebugPrint((1,"AtapiStartIo: Reset bus failed\n"));
+
+ //
+ // Log reset failure.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 5 << 8
+ );
+
+ status = SRB_STATUS_ERROR;
+
+ } else {
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SRB_FUNCTION_IO_CONTROL:
+
+ if (deviceExtension->CurrentSrb) {
+
+ DebugPrint((1,
+ "AtapiStartIo: Already have a request!\n"));
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ return FALSE;
+ }
+
+ //
+ // Indicate that a request is active on the controller.
+ //
+
+ deviceExtension->CurrentSrb = Srb;
+
+ if (AtapiStringCmp( ((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature,"SCSIDISK",strlen("SCSIDISK"))) {
+
+ DebugPrint((1,
+ "AtapiStartIo: IoControl signature incorrect. Send %s, expected %s\n",
+ ((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature,
+ "SCSIDISK"));
+
+ status = SRB_STATUS_INVALID_REQUEST;
+ break;
+ }
+
+ switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
+
+ case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
+
+ PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+ UCHAR deviceNumber;
+
+ //
+ // Version and revision per SMART 1.03
+ //
+
+ versionParameters->bVersion = 1;
+ versionParameters->bRevision = 1;
+ versionParameters->bReserved = 0;
+
+ //
+ // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
+ //
+
+ versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
+
+ //
+ // This is done because of how the IOCTL_SCSI_MINIPORT
+ // determines 'targetid's'. Disk.sys places the real target id value
+ // in the DeviceMap field. Once we do some parameter checking, the value passed
+ // back to the application will be determined.
+ //
+
+ deviceNumber = versionParameters->bIDEDeviceMap;
+
+ if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) ||
+ (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE)) {
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // NOTE: This will only set the bit
+ // corresponding to this drive's target id.
+ // The bit mask is as follows:
+ //
+ // Sec Pri
+ // S M S M
+ // 3 2 1 0
+ //
+
+ if (deviceExtension->NumberChannels == 1) {
+ if (deviceExtension->PrimaryAddress) {
+ deviceNumber = 1 << Srb->TargetId;
+ } else {
+ deviceNumber = 4 << Srb->TargetId;
+ }
+ } else {
+ deviceNumber = 1 << Srb->TargetId;
+ }
+
+ versionParameters->bIDEDeviceMap = deviceNumber;
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+ }
+
+ case IOCTL_SCSI_MINIPORT_IDENTIFY: {
+
+ PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+ SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+ ULONG i;
+ UCHAR targetId;
+
+
+ if (cmdInParameters.irDriveRegs.bCommandReg == ID_CMD) {
+
+ //
+ // Extract the target.
+ //
+
+ targetId = cmdInParameters.bDriveNumber;
+
+ if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) ||
+ (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE)) {
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Zero the output buffer
+ //
+
+ for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1); i++) {
+ ((PUCHAR)cmdOutParameters)[i] = 0;
+ }
+
+ //
+ // Build status block.
+ //
+
+ cmdOutParameters->cBufferSize = IDENTIFY_BUFFER_SIZE;
+ cmdOutParameters->DriverStatus.bDriverError = 0;
+ cmdOutParameters->DriverStatus.bIDEError = 0;
+
+ //
+ // Extract the identify data from the device extension.
+ //
+
+ ScsiPortMoveMemory (cmdOutParameters->bBuffer, &deviceExtension->IdentifyData[targetId], IDENTIFY_DATA_SIZE);
+
+ status = SRB_STATUS_SUCCESS;
+
+
+ } else {
+ status = SRB_STATUS_INVALID_REQUEST;
+ }
+ break;
+ }
+
+ case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
+ case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
+ case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
+ case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
+ case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
+ case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
+ case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
+ case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
+
+ status = IdeSendSmartCommand(HwDeviceExtension,Srb);
+ break;
+
+ default :
+
+ status = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ }
+
+ break;
+
+ default:
+
+ //
+ // Indicate unsupported command.
+ //
+
+ status = SRB_STATUS_INVALID_REQUEST;
+
+ break;
+
+ } // end switch
+
+ //
+ // Check if command complete.
+ //
+
+ if (status != SRB_STATUS_PENDING) {
+
+ DebugPrint((2,
+ "AtapiStartIo: Srb %x complete with status %x\n",
+ Srb,
+ status));
+
+ //
+ // Clear current SRB.
+ //
+
+ deviceExtension->CurrentSrb = NULL;
+
+ //
+ // Set status in SRB.
+ //
+
+ Srb->SrbStatus = (UCHAR)status;
+
+ //
+ // Indicate command complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ //
+ // Indicate ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ }
+
+ return TRUE;
+
+} // end AtapiStartIo()
+
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+// ULONG adapterCount;
+ ULONG i;
+ ULONG statusToReturn, newStatus;
+ FIND_STATE findState;
+ ULONG AdapterAddresses[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0};
+ ULONG InterruptLevels[5] = { 14, 15, 11, 10, 0};
+ BOOLEAN IoAddressUsed[5] = {FALSE, FALSE, FALSE, FALSE, 0};
+
+ DebugPrint((1,"\n\nATAPI IDE MiniPort Driver\n"));
+
+ DebugPrintTickCount();
+
+ statusToReturn = 0xffffffff;
+
+ //
+ // Zero out structure.
+ //
+
+ AtapiZeroMemory(((PUCHAR)&hwInitializationData), sizeof(HW_INITIALIZATION_DATA));
+
+ AtapiZeroMemory(((PUCHAR)&findState), sizeof(FIND_STATE));
+
+
+ findState.DefaultIoPort = AdapterAddresses;
+ findState.DefaultInterrupt = InterruptLevels;
+ findState.IoAddressUsed = IoAddressUsed;
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = AtapiHwInitialize;
+ hwInitializationData.HwResetBus = AtapiResetController;
+ hwInitializationData.HwStartIo = AtapiStartIo;
+ hwInitializationData.HwInterrupt = AtapiInterrupt;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
+
+ hwInitializationData.NumberOfAccessRanges = 6;
+ hwInitializationData.HwFindAdapter = AtapiFindController;
+
+ hwInitializationData.AdapterInterfaceType = Isa;
+ findState.ControllerParameters = PciControllerParameters;
+
+ newStatus = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &findState);
+ if (newStatus < statusToReturn)
+ statusToReturn = newStatus;
+
+
+ //
+ // Set up for MCA
+ //
+
+ hwInitializationData.AdapterInterfaceType = MicroChannel;
+
+ newStatus = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &findState);
+ if (newStatus < statusToReturn)
+ statusToReturn = newStatus;
+
+ DebugPrintTickCount();
+
+ return statusToReturn;
+
+} // end DriverEntry()
+
+
+
+LONG
+AtapiStringCmp (
+ PCHAR FirstStr,
+ PCHAR SecondStr,
+ ULONG Count
+ )
+{
+ UCHAR first ,last;
+
+ if (Count) {
+ do {
+
+ //
+ // Get next char.
+ //
+
+ first = *FirstStr++;
+ last = *SecondStr++;
+
+ if (first != last) {
+
+ //
+ // If no match, try lower-casing.
+ //
+
+ if (first>='A' && first<='Z') {
+ first = first - 'A' + 'a';
+ }
+ if (last>='A' && last<='Z') {
+ last = last - 'A' + 'a';
+ }
+ if (first != last) {
+
+ //
+ // No match
+ //
+
+ return first - last;
+ }
+ }
+ }while (--Count && first);
+ }
+
+ return 0;
+}
+
+
+VOID
+AtapiZeroMemory(
+ IN PCHAR Buffer,
+ IN ULONG Count
+ )
+{
+ ULONG i;
+
+ for (i = 0; i < Count; i++) {
+ Buffer[i] = 0;
+ }
+}
+
+
+VOID
+AtapiHexToString (
+ IN ULONG Value,
+ IN OUT PCHAR *Buffer
+ )
+{
+ PCHAR string;
+ PCHAR firstdig;
+ CHAR temp;
+ ULONG i;
+ USHORT digval;
+
+ string = *Buffer;
+
+ firstdig = string;
+
+ for (i = 0; i < 4; i++) {
+ digval = (USHORT)(Value % 16);
+ Value /= 16;
+
+ //
+ // convert to ascii and store. Note this will create
+ // the buffer with the digits reversed.
+ //
+
+ if (digval > 9) {
+ *string++ = (char) (digval - 10 + 'a');
+ } else {
+ *string++ = (char) (digval + '0');
+ }
+
+ }
+
+ //
+ // Reverse the digits.
+ //
+
+ *string-- = '\0';
+
+ do {
+ temp = *string;
+ *string = *firstdig;
+ *firstdig = temp;
+ --string;
+ ++firstdig;
+ } while (firstdig < string);
+}
+
+
+
+PSCSI_REQUEST_BLOCK
+BuildMechanismStatusSrb (
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId,
+ IN ULONG TargetId
+ )
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ PCDB cdb;
+
+ srb = &deviceExtension->InternalSrb;
+
+ AtapiZeroMemory((PUCHAR) srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ srb->PathId = (UCHAR) PathId;
+ srb->TargetId = (UCHAR) TargetId;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+
+ //
+ // Set flags to disable synchronous negociation.
+ //
+ srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ //
+ // Set timeout to 2 seconds.
+ //
+ srb->TimeOutValue = 4;
+
+ srb->CdbLength = 6;
+ srb->DataBuffer = &deviceExtension->MechStatusData;
+ srb->DataTransferLength = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
+
+ //
+ // Set CDB operation code.
+ //
+ cdb = (PCDB)srb->Cdb;
+ cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS;
+ cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
+
+ return srb;
+}
+
+
+PSCSI_REQUEST_BLOCK
+BuildRequestSenseSrb (
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId,
+ IN ULONG TargetId
+ )
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ PCDB cdb;
+
+ srb = &deviceExtension->InternalSrb;
+
+ AtapiZeroMemory((PUCHAR) srb, sizeof(SCSI_REQUEST_BLOCK));
+
+ srb->PathId = (UCHAR) PathId;
+ srb->TargetId = (UCHAR) TargetId;
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+
+ //
+ // Set flags to disable synchronous negociation.
+ //
+ srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ //
+ // Set timeout to 2 seconds.
+ //
+ srb->TimeOutValue = 4;
+
+ srb->CdbLength = 6;
+ srb->DataBuffer = &deviceExtension->MechStatusSense;
+ srb->DataTransferLength = sizeof(SENSE_DATA);
+
+ //
+ // Set CDB operation code.
+ //
+ cdb = (PCDB)srb->Cdb;
+ cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
+ cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
+
+ return srb;
+}
+
+
+BOOLEAN
+PrepareForBusMastering(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+/*++
+
+Routine Description:
+
+ Get ready for IDE bus mastering
+
+ init. PDRT
+ init. bus master controller but keep it disabled
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - scsi request block
+
+Return Value:
+
+ TRUE if successful
+ FALSE if failed
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ SCSI_PHYSICAL_ADDRESS physAddr;
+ ULONG bytesMapped;
+ ULONG bytes;
+ PUCHAR buffer;
+ PPHYSICAL_REGION_DESCRIPTOR physAddrTablePtr;
+ ULONG physAddrTableIndex;
+ PIDE_BUS_MASTER_REGISTERS busMasterBase;
+
+ busMasterBase = deviceExtension->BusMasterPortBase[Srb->TargetId >> 1];
+
+ buffer = Srb->DataBuffer;
+ physAddrTablePtr = deviceExtension->DataBufferDescriptionTablePtr;
+ physAddrTableIndex = 0;
+ bytesMapped = 0;
+ DebugPrint ((2, "ATAPI: Mapping 0x%x bytes\n", Srb->DataTransferLength));
+
+ //
+ // PDRT has these limitation
+ // each entry maps up to is 64K bytes
+ // each physical block mapped cannot cross 64K page boundary
+ //
+ while (bytesMapped < Srb->DataTransferLength) {
+ ULONG bytesLeft;
+ ULONG nextPhysicalAddr;
+ ULONG bytesLeftInCurrent64KPage;
+
+ physAddr = ScsiPortGetPhysicalAddress(HwDeviceExtension,
+ Srb,
+ buffer,
+ &bytes);
+
+ bytesLeft = bytes;
+ nextPhysicalAddr = ScsiPortConvertPhysicalAddressToUlong(physAddr);
+ while (bytesLeft > 0) {
+ physAddrTablePtr[physAddrTableIndex].PhyscialAddress = nextPhysicalAddr;
+
+ bytesLeftInCurrent64KPage = (0x10000 - (nextPhysicalAddr & 0xffff));
+
+ if (bytesLeftInCurrent64KPage < bytesLeft) {
+
+ //
+ // Are we crossing 64K page
+ // got to break it up. Map up to the 64k boundary
+ //
+ physAddrTablePtr[physAddrTableIndex].ByteCount = bytesLeftInCurrent64KPage;
+ bytesLeft -= bytesLeftInCurrent64KPage;
+ nextPhysicalAddr += bytesLeftInCurrent64KPage;
+ DebugPrint ((3, "PrepareForBusMastering: buffer crossing 64K Page!\n"));
+
+ } else if (bytesLeft <= 0x10000) {
+ //
+ // got a perfect page, map all of it
+ //
+ physAddrTablePtr[physAddrTableIndex].ByteCount = bytesLeft & 0xfffe;
+ bytesLeft = 0;
+ nextPhysicalAddr += bytesLeft;
+
+ } else {
+ //
+ // got a perfectly aligned 64k page, map all of it but the count
+ // need to be 0
+ //
+ physAddrTablePtr[physAddrTableIndex].ByteCount = 0; // 64K
+ bytesLeft -= 0x10000;
+ nextPhysicalAddr += 0x10000;
+ }
+ physAddrTablePtr[physAddrTableIndex].EndOfTable = 0; // not end of table
+ physAddrTableIndex++;
+ }
+ bytesMapped += bytes;
+ buffer += bytes;
+ }
+
+ //
+ // the bus master circutry need to know it hits the end of the PRDT
+ //
+ physAddrTablePtr[physAddrTableIndex - 1].EndOfTable = 1; // end of table
+
+ //
+ // init bus master contoller, but keep it disabled
+ //
+ ScsiPortWritePortUchar (&busMasterBase->Command, 0); // disable BM
+ ScsiPortWritePortUchar (&busMasterBase->Status, 0x6); // clear errors
+ ScsiPortWritePortUlong (&busMasterBase->DescriptionTable,
+ ScsiPortConvertPhysicalAddressToUlong(deviceExtension->DataBufferDescriptionTablePhysAddr));
+
+ return TRUE;
+}
+
+
+BOOLEAN
+EnableBusMastering(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+/*++
+
+Routine Description:
+
+ Enable bus mastering contoller
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - scsi request block
+
+Return Value:
+
+ always TRUE
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PIDE_BUS_MASTER_REGISTERS busMasterBase;
+ UCHAR bmStatus = 0;
+
+ busMasterBase = deviceExtension->BusMasterPortBase[Srb->TargetId >> 1];
+
+ deviceExtension->DMAInProgress = TRUE;
+
+ //
+ // inidcate we are doing DMA
+ //
+ if (Srb->TargetId == 0)
+ bmStatus = BUSMASTER_DEVICE0_DMA_OK;
+ else
+ bmStatus = BUSMASTER_DEVICE1_DMA_OK;
+
+ //
+ // clear the status bit
+ //
+ bmStatus |= BUSMASTER_INTERRUPT | BUSMASTER_ERROR;
+
+ ScsiPortWritePortUchar (&busMasterBase->Status, bmStatus);
+
+ //
+ // on your mark...get set...go!!
+ //
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ScsiPortWritePortUchar (&busMasterBase->Command, 0x09); // enable BM read
+ } else {
+ ScsiPortWritePortUchar (&busMasterBase->Command, 0x01); // enable BM write
+ }
+
+ DebugPrint ((2, "ATAPI: BusMaster Status = 0x%x\n", ScsiPortReadPortUchar (&busMasterBase->Status)));
+
+ return TRUE;
+}
+
+
+
+ULONG
+GetPciBusData(
+ IN PVOID HwDeviceExtension,
+ IN ULONG SystemIoBusNumber,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ OUT PVOID PciConfigBuffer,
+ IN ULONG NumByte
+ )
+/*++
+
+Routine Description:
+
+ read PCI bus data
+
+ we can't always use ScsiPortSetBusDataByOffset directly because many Intel PIIXs
+ are "hidden" from the function. The PIIX is usually the second
+ function of some other pci device (PCI-ISA bridge). However, the
+ mulit-function bit of the PCI-Isa bridge is not set. ScsiportGetBusData
+ will not be able to find it.
+
+ This function will try to figure out if we have the "bad" PCI-ISA bridge,
+ and read the PIIX PCI space directly if necessary
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ SystemIoBusNumber - bus number
+ SlotNumber - pci slot and function numbers
+ PciConfigBuffer = pci data pointer
+
+Return Value:
+
+ byte returned
+
+--*/
+{
+ ULONG byteRead;
+ PULONG pciAddrReg;
+ PULONG pciDataReg;
+ ULONG i;
+ ULONG j;
+ ULONG data;
+ PULONG dataBuffer;
+
+ USHORT vendorId;
+ USHORT deviceId;
+ UCHAR headerType;
+
+ //
+ // If we have a hidden PIIX, it is always a function 1 of
+ // some device (PCI-ISA bridge (0x8086\0x122e)
+ // If we are NOT looking at function 1, skip the extra work
+ //
+ if (!AtapiPlaySafe && (SlotNumber.u.bits.FunctionNumber == 1)) {
+
+ pciAddrReg = (PULONG) ScsiPortGetDeviceBase(HwDeviceExtension,
+ PCIBus,
+ 0,
+ ScsiPortConvertUlongToPhysicalAddress(PCI_ADDR_PORT),
+ 4,
+ TRUE);
+ pciDataReg = (PULONG) ScsiPortGetDeviceBase(HwDeviceExtension,
+ PCIBus,
+ 0,
+ ScsiPortConvertUlongToPhysicalAddress(PCI_DATA_PORT),
+ 4,
+ TRUE);
+ } else {
+ pciAddrReg = pciDataReg = NULL;
+ }
+
+ if (pciAddrReg && pciDataReg) {
+ //
+ // get the vendor id and device id of the previous function
+ //
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber - 1, // looking at last function
+ 0));
+ data = ScsiPortReadPortUlong(pciDataReg);
+ vendorId = (USHORT) ((data >> 0) & 0xffff);
+ deviceId = (USHORT) ((data >> 16) & 0xffff);
+
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber - 1, // looking at last function
+ 3));
+ data = ScsiPortReadPortUlong(pciDataReg);
+ headerType = (UCHAR) ((data >> 16) & 0xff);
+
+ } else {
+ vendorId = PCI_INVALID_VENDORID;
+ }
+
+ //
+ // The hidden PIIX is the pci function after the PCI-ISA bridge
+ // When it is hidden, the PCI-ISA bridge PCI_MULTIFUNCTION bit is not set
+ //
+ byteRead = 0;
+ if ((vendorId == 0x8086) && // Intel
+ (deviceId == 0x122e) && // PCI-ISA Bridge
+ !(headerType & PCI_MULTIFUNCTION)) {
+
+ DebugPrint ((1, "ATAPI: found the hidden PIIX\n"));
+
+ if (pciDataReg && pciAddrReg) {
+
+ for (i=0, dataBuffer = (PULONG) PciConfigBuffer;
+ i < NumByte / 4;
+ i++, dataBuffer++) {
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber,
+ i));
+ dataBuffer[0] = ScsiPortReadPortUlong(pciDataReg);
+ }
+
+ if (NumByte % 4) {
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber,
+ i));
+ data = ScsiPortReadPortUlong(pciDataReg);
+
+ for (j=0; j <NumByte%4; j++) {
+ ((PUCHAR)dataBuffer)[j] = (UCHAR) (data & 0xff);
+ data = data >> 8;
+ }
+ }
+ byteRead = NumByte;
+ }
+
+ if ((((PPCI_COMMON_CONFIG)PciConfigBuffer)->VendorID != 0x8086) || // Intel
+ (((PPCI_COMMON_CONFIG)PciConfigBuffer)->DeviceID != 0x1230)) { // PIIX
+
+ //
+ // If the hidden device is not Intel PIIX, don't
+ // show it
+ //
+ byteRead = 0;
+ } else {
+ DebugPrint ((0, "If we play safe, we would NOT detect hidden PIIX controller\n"));
+ }
+
+ }
+
+ if (!byteRead) {
+ //
+ // Didn't find any hidden PIIX. Get the PCI
+ // data via the normal call (ScsiPortGetBusData)
+ //
+ byteRead = ScsiPortGetBusData(HwDeviceExtension,
+ PCIConfiguration,
+ SystemIoBusNumber,
+ SlotNumber.u.AsULONG,
+ PciConfigBuffer,
+ NumByte);
+ }
+
+ if (pciAddrReg)
+ ScsiPortFreeDeviceBase(HwDeviceExtension, pciAddrReg);
+ if (pciDataReg)
+ ScsiPortFreeDeviceBase(HwDeviceExtension, pciDataReg);
+
+ return byteRead;
+}
+
+
+ULONG
+SetPciBusData(
+ IN PVOID HwDeviceExtension,
+ IN ULONG SystemIoBusNumber,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ set PCI bus data
+
+ we can't always use ScsiPortSetBusDataByOffset directly because many Intel PIIXs
+ are "hidden" from the function. The PIIX is usually the second
+ function of some other pci device (PCI-ISA bridge). However, the
+ mulit-function bit of the PCI-Isa bridge is not set. ScsiPortSetBusDataByOffset
+ will not be able to find it.
+
+ This function will try to figure out if we have the "bad" PCI-ISA bridge,
+ and write to the PIIX PCI space directly if necessary
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ SystemIoBusNumber - bus number
+ SlotNumber - pci slot and function numbers
+ Buffer - pci data buffer
+ Offset - byte offset into the pci space
+ Length - number of bytes to write
+
+Return Value:
+
+ byte written
+
+--*/
+{
+ ULONG byteWritten;
+ PULONG pciAddrReg;
+ PULONG pciDataReg;
+ ULONG i;
+ ULONG j;
+ ULONG data;
+ PULONG dataBuffer;
+
+ USHORT vendorId;
+ USHORT deviceId;
+ UCHAR headerType;
+
+ //
+ // If we have a hidden PIIX, it is always a function 1 of
+ // some device (PCI-ISA bridge (0x8086\0x122e)
+ // If we are NOT looking at function 1, skip the extra work
+ //
+ if (!AtapiPlaySafe && (SlotNumber.u.bits.FunctionNumber == 1)) {
+
+ pciAddrReg = (PULONG) ScsiPortGetDeviceBase(HwDeviceExtension,
+ PCIBus,
+ 0,
+ ScsiPortConvertUlongToPhysicalAddress(PCI_ADDR_PORT),
+ 4,
+ TRUE);
+ pciDataReg = (PULONG) ScsiPortGetDeviceBase(HwDeviceExtension,
+ PCIBus,
+ 0,
+ ScsiPortConvertUlongToPhysicalAddress(PCI_DATA_PORT),
+ 4,
+ TRUE);
+ } else {
+ pciAddrReg = pciDataReg = NULL;
+ }
+
+ if (pciAddrReg && pciDataReg) {
+ //
+ // get the vendor id and device id of the previous function
+ //
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber - 1, // looking at last function
+ 0));
+ data = ScsiPortReadPortUlong(pciDataReg);
+ vendorId = (USHORT) ((data >> 0) & 0xffff);
+ deviceId = (USHORT) ((data >> 16) & 0xffff);
+
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber - 1, // looking at last function
+ 3));
+ data = ScsiPortReadPortUlong(pciDataReg);
+ headerType = (UCHAR) ((data >> 16) & 0xff);
+
+ } else {
+ vendorId = PCI_INVALID_VENDORID;
+ }
+
+ //
+ // The hidden PIIX is the pci function after the PCI-ISA bridge
+ // When it is hidden, the PCI-ISA bridge PCI_MULTIFUNCTION bit is not set
+ //
+ byteWritten = 0;
+ if ((vendorId == 0x8086) && // Intel
+ (deviceId == 0x122e) && // PCI-ISA Bridge
+ !(headerType & PCI_MULTIFUNCTION)) {
+
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber,
+ 0));
+ data = ScsiPortReadPortUlong(pciDataReg);
+ vendorId = (USHORT) ((data >> 0) & 0xffff);
+ deviceId = (USHORT) ((data >> 16) & 0xffff);
+
+ if ((vendorId == 0x8086) && // Intel
+ (deviceId == 0x1230)) { // PIIX
+
+ PCI_COMMON_CONFIG pciData;
+
+ //
+ // read the same range of data in first
+ //
+ for (i=0, dataBuffer = (((PULONG) &pciData) + Offset/4);
+ i<(Length+3)/4;
+ i++, dataBuffer++) {
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber,
+ i + Offset/4));
+ data = ScsiPortReadPortUlong(pciDataReg);
+ if (i < (sizeof(Length)/4)) {
+ dataBuffer[0] = data;
+ } else {
+ for (j=0; j <sizeof(Length)%4; j++) {
+ ((PUCHAR)dataBuffer)[j] = (UCHAR) (data & 0xff);
+ data = data >> 8;
+ }
+ }
+ }
+
+ //
+ // Copy the new data over
+ //
+ for (i = 0; i<Length; i++) {
+ ((PUCHAR)&pciData)[i + Offset] = ((PUCHAR)Buffer)[i];
+ }
+
+ //
+ // write out the same range of data
+ //
+ for (i=0, dataBuffer = (((PULONG) &pciData) + Offset/4);
+ i<(Length+3)/4;
+ i++, dataBuffer++) {
+ ScsiPortWritePortUlong(pciAddrReg, PCI_ADDRESS(SystemIoBusNumber,
+ SlotNumber.u.bits.DeviceNumber,
+ SlotNumber.u.bits.FunctionNumber,
+ i + Offset/4));
+ ScsiPortWritePortUlong(pciDataReg, dataBuffer[0]);
+ }
+
+ byteWritten = Length;
+
+ } else {
+
+ // If the hidden device is not Intel PIIX, don't
+ // write to it
+ byteWritten = 0;
+ }
+
+ }
+
+ if (!byteWritten) {
+ //
+ // Didn't find any hidden PIIX. Write to the PCI
+ // space via the normal call (ScsiPortSetBusDataByOffset)
+ //
+ byteWritten = ScsiPortSetBusDataByOffset(HwDeviceExtension,
+ PCIConfiguration,
+ SystemIoBusNumber,
+ SlotNumber.u.AsULONG,
+ Buffer,
+ Offset,
+ Length);
+ }
+
+ if (pciAddrReg)
+ ScsiPortFreeDeviceBase(HwDeviceExtension, pciAddrReg);
+ if (pciDataReg)
+ ScsiPortFreeDeviceBase(HwDeviceExtension, pciDataReg);
+
+ return byteWritten;
+}
+
+BOOLEAN
+ChannelIsAlwaysEnabled (
+ PPCI_COMMON_CONFIG PciData,
+ ULONG Channel)
+/*++
+
+Routine Description:
+
+ dummy routine that always returns TRUE
+
+Arguments:
+
+ PPCI_COMMON_CONFIG - pci config data
+ Channel - ide channel number
+
+Return Value:
+
+ TRUE
+
+--*/
+{
+ return TRUE;
+}
+
+VOID
+SetBusMasterDetectionLevel (
+ IN PVOID HwDeviceExtension,
+ IN PCHAR userArgumentString
+ )
+/*++
+
+Routine Description:
+
+ check whether we should try to enable bus mastering
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ArgumentString - register arguments
+
+Return Value:
+
+ TRUE
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ BOOLEAN useBM;
+
+ ULONG pciBusNumber;
+ PCI_SLOT_NUMBER pciSlot;
+ ULONG slotNumber;
+ ULONG logicalDeviceNumber;
+ PCI_COMMON_CONFIG pciData;
+ ULONG DMADetectionLevel;
+
+ useBM = TRUE;
+
+ DMADetectionLevel = AtapiParseArgumentString(userArgumentString, "DMADetectionLevel");
+ if (DMADetectionLevel == DMADETECT_SAFE) {
+ AtapiPlaySafe = TRUE;
+ } else if (DMADetectionLevel == DMADETECT_UNSAFE) {
+ AtapiPlaySafe = FALSE;
+ } else { // default is no busmastering
+ useBM = FALSE;
+ }
+
+
+ //
+ // search for bad chip set
+ //
+ for (pciBusNumber=0;
+ pciBusNumber < 256 && useBM;
+ pciBusNumber++) {
+
+ pciSlot.u.AsULONG = 0;
+
+ for (slotNumber=0;
+ slotNumber < PCI_MAX_DEVICES && useBM;
+ slotNumber++) {
+
+ pciSlot.u.bits.DeviceNumber = slotNumber;
+
+ for (logicalDeviceNumber=0;
+ logicalDeviceNumber < PCI_MAX_FUNCTION && useBM;
+ logicalDeviceNumber++) {
+
+ pciSlot.u.bits.FunctionNumber = logicalDeviceNumber;
+
+ if (!GetPciBusData(HwDeviceExtension,
+ pciBusNumber,
+ pciSlot,
+ &pciData,
+ offsetof (PCI_COMMON_CONFIG, DeviceSpecific)
+ )) {
+ break;
+ }
+
+ if (pciData.VendorID == PCI_INVALID_VENDORID) {
+ break;
+ }
+
+ if ((pciData.VendorID == 0x8086) && // Intel
+ (pciData.DeviceID == 0x84c4) && // 82450GX/KX Pentium Pro Processor to PCI bridge
+ (pciData.RevisionID < 0x4)) { // Stepping less than 4
+
+ DebugPrint((1,
+ "atapi: Find a bad Intel processor-pci bridge. Disable PCI IDE busmastering...\n"));
+ useBM = FALSE;
+ }
+ }
+ }
+ }
+
+ deviceExtension->UseBusMasterController = useBM;
+ DebugPrint ((0, "ATAPI: UseBusMasterController = %d\n", deviceExtension->UseBusMasterController));
+
+ if (deviceExtension->UseBusMasterController) {
+ DebugPrint ((0, "ATAPI: AtapiPlaySafe = %d\n", AtapiPlaySafe));
+ }
+
+ return;
+}
+
+
+
+UCHAR PioDeviceModelNumber[][41] = {
+ {" Conner Peripherals 425MB - CFS425A "},
+ {"MATSHITA CR-581 "},
+ {"FX600S "},
+ {"CD-44E "},
+ {"QUANTUM TRB850A "},
+ {"QUANTUM MARVERICK 540A "},
+ {" MAXTOR MXT-540 AT "},
+ {"Maxtor 71260 AT "},
+ {"Maxtor 7850 AV "},
+ {"Maxtor 7540 AV "},
+ {"Maxtor 7213 AT "},
+ {"Maxtor 7345 "},
+ {"Maxtor 7245 AT "},
+ {"Maxtor 7245 "},
+ {"Maxtor 7211AU "},
+ {"Maxtor 7171 AT "}
+};
+#define NUMBER_OF_PIO_DEVICES (sizeof(PioDeviceModelNumber) / (sizeof(UCHAR) * 41))
+
+UCHAR SpecialWDDevicesFWVersion[][9] = {
+ {"14.04E28"},
+ {"25.26H35"},
+ {"26.27J38"},
+ {"27.25C38"},
+ {"27.25C39"}
+};
+#define NUMBER_OF_SPECIAL_WD_DEVICES (sizeof(SpecialWDDevicesFWVersion) / (sizeof (UCHAR) * 9))
+
+BOOLEAN
+AtapiDeviceDMACapable (
+ IN PVOID HwDeviceExtension,
+ IN ULONG deviceNumber
+ )
+/*++
+
+Routine Description:
+
+ check the given device whether it is on our bad device list (non dma device)
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ deviceNumber - device number
+
+Return Value:
+
+ TRUE if dma capable
+ FALSE if not dma capable
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ UCHAR modelNumber[41];
+ UCHAR firmwareVersion[9];
+ ULONG i;
+ BOOLEAN turnOffDMA = FALSE;
+ PCI_SLOT_NUMBER pciSlot;
+ PCI_COMMON_CONFIG pciData;
+
+ if (!(deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_DEVICE_PRESENT)) {
+ return FALSE;
+ }
+
+ for (i=0; i<40; i+=2) {
+ modelNumber[i + 0] = deviceExtension->IdentifyData[deviceNumber].ModelNumber[i + 1];
+ modelNumber[i + 1] = deviceExtension->IdentifyData[deviceNumber].ModelNumber[i + 0];
+ }
+ modelNumber[i] = 0;
+
+ for (i=0; i<NUMBER_OF_PIO_DEVICES; i++) {
+ if (!AtapiStringCmp(modelNumber, PioDeviceModelNumber[i], 40)) {
+
+ DebugPrint ((0, "ATAPI: device on the hall of shame list. no DMA!\n"));
+
+ turnOffDMA = TRUE;
+ }
+ }
+
+ //
+ // if we have a Western Digial device
+ // if the best dma mode is multi word dma mode 1
+ // if the identify data word offset 129 is not 0x5555
+ // turn off dma unless
+ // if the device firmware version is on the list and
+ // it is the only drive on the bus
+ //
+ if (!AtapiStringCmp(modelNumber, "WDC", 3)) {
+ if (deviceExtension->DeviceParameters[deviceNumber].BestMultiWordDMAMode == 1) {
+
+ for (i=0; i<8; i+=2) {
+ firmwareVersion[i + 0] = deviceExtension->IdentifyData[deviceNumber].FirmwareRevision[i + 1];
+ firmwareVersion[i + 1] = deviceExtension->IdentifyData[deviceNumber].FirmwareRevision[i + 0];
+ }
+ firmwareVersion[i] = 0;
+
+ //
+ // Check the special flag. If not found, can't use dma
+ //
+ if (*(((PUSHORT)&deviceExtension->IdentifyData[deviceNumber]) + 129) != 0x5555) {
+
+ DebugPrint ((0, "ATAPI: found mode 1 WD drive. no dma unless it is the only device\n"));
+
+ turnOffDMA = TRUE;
+
+ for (i=0; i<NUMBER_OF_SPECIAL_WD_DEVICES; i++) {
+
+ if (!AtapiStringCmp(firmwareVersion, SpecialWDDevicesFWVersion[i], 8)) {
+
+ ULONG otherDeviceNumber;
+
+ //
+ // 0 becomes 1
+ // 1 becomes 0
+ // 2 becomes 3
+ // 3 becomes 2
+ //
+ otherDeviceNumber = ((deviceNumber & 0x2) | ((deviceNumber & 0x1) ^ 1));
+
+ //
+ // if the device is alone on the bus, we can use dma
+ //
+ if (!(deviceExtension->DeviceFlags[otherDeviceNumber] & DFLAGS_DEVICE_PRESENT)) {
+ turnOffDMA = FALSE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // ALi IDE controller cannot busmaster with an ATAPI device
+ //
+ pciSlot.u.AsULONG = 0;
+ pciSlot.u.bits.DeviceNumber = deviceExtension->PciDeviceNumber;
+ pciSlot.u.bits.FunctionNumber = deviceExtension->PciLogDevNumber;
+
+ if (GetPciBusData(HwDeviceExtension,
+ deviceExtension->PciBusNumber,
+ pciSlot,
+ &pciData,
+ offsetof (PCI_COMMON_CONFIG, DeviceSpecific)
+ )) {
+
+ if ((pciData.VendorID == 0x10b9) &&
+ (pciData.DeviceID == 0x5219)) {
+
+ if (deviceExtension->DeviceFlags[deviceNumber] & DFLAGS_ATAPI_DEVICE) {
+
+ DebugPrint ((0, "ATAPI: Can't do DMA because we have a ALi controller and a ATAPI device\n"));
+
+ turnOffDMA = TRUE;
+
+
+
+ }
+ }
+ }
+
+ if (turnOffDMA) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
diff --git a/private/ntos/miniport/atapi/atapi.h b/private/ntos/miniport/atapi/atapi.h
new file mode 100644
index 000000000..2364537b3
--- /dev/null
+++ b/private/ntos/miniport/atapi/atapi.h
@@ -0,0 +1,857 @@
+/*++
+
+Copyright (c) 1993-1996 Microsoft Corporation
+
+Module Name:
+
+ atapi.h
+
+Abstract:
+
+ This module contains the structures and definitions for the ATAPI
+ IDE miniport driver.
+
+Author:
+
+ Mike Glass
+
+
+Revision History:
+
+--*/
+
+#include "scsi.h"
+#include "stdio.h"
+#include "string.h"
+
+//
+// Function Prototypes
+//
+ULONG
+GetPciBusData(
+ IN PVOID DeviceExtension,
+ IN ULONG SystemIoBusNumber,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ OUT PVOID PciConfigBuffer,
+ IN ULONG NumByte
+ );
+
+ULONG
+SetPciBusData(
+ IN PVOID HwDeviceExtension,
+ IN ULONG SystemIoBusNumber,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+BOOLEAN
+ChannelIsAlwaysEnabled (
+ IN PPCI_COMMON_CONFIG PciData,
+ IN ULONG Channel
+ );
+
+//
+// IDE register definition
+//
+
+typedef struct _IDE_REGISTERS_1 {
+ USHORT Data;
+ UCHAR BlockCount;
+ UCHAR BlockNumber;
+ UCHAR CylinderLow;
+ UCHAR CylinderHigh;
+ UCHAR DriveSelect;
+ UCHAR Command;
+} IDE_REGISTERS_1, *PIDE_REGISTERS_1;
+
+typedef struct _IDE_REGISTERS_2 {
+ UCHAR DeviceControl;
+ UCHAR DriveAddress;
+} IDE_REGISTERS_2, *PIDE_REGISTERS_2;
+
+typedef struct _IDE_REGISTERS_3 {
+ ULONG Data;
+ UCHAR Others[4];
+} IDE_REGISTERS_3, *PIDE_REGISTERS_3;
+
+//
+// Bus Master Controller Register
+//
+typedef struct _IDE_BUS_MASTER_REGISTERS {
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status;
+ UCHAR Reserved2;
+ ULONG DescriptionTable;
+} IDE_BUS_MASTER_REGISTERS, *PIDE_BUS_MASTER_REGISTERS;
+
+//
+// Device Extension Device Flags
+//
+
+#define DFLAGS_DEVICE_PRESENT (1 << 0) // Indicates that some device is present.
+#define DFLAGS_ATAPI_DEVICE (1 << 1) // Indicates whether Atapi commands can be used.
+#define DFLAGS_TAPE_DEVICE (1 << 2) // Indicates whether this is a tape device.
+#define DFLAGS_INT_DRQ (1 << 3) // Indicates whether device interrupts as DRQ is set after
+ // receiving Atapi Packet Command
+#define DFLAGS_REMOVABLE_DRIVE (1 << 4) // Indicates that the drive has the 'removable' bit set in
+ // identify data (offset 128)
+#define DFLAGS_MEDIA_STATUS_ENABLED (1 << 5) // Media status notification enabled
+#define DFLAGS_ATAPI_CHANGER (1 << 6) // Indicates atapi 2.5 changer present.
+#define DFLAGS_SANYO_ATAPI_CHANGER (1 << 7) // Indicates multi-platter device, not conforming to the 2.5 spec.
+#define DFLAGS_CHANGER_INITED (1 << 8) // Indicates that the init path for changers has already been done.
+#define DFLAGS_USE_DMA (1 << 9) // Indicates whether device can use DMA
+#define DFLAGS_LBA (1 << 10) // support LBA addressing
+
+//
+// Controller Flags
+//
+#define CFLAGS_BUS_MASTERING (1 << 0) // The Controller is capable of doing bus mastering
+ // defined by SFF-8038i
+
+//
+// Used to disable 'advanced' features.
+//
+
+#define MAX_ERRORS 4
+
+//
+// ATAPI command definitions
+//
+
+#define ATAPI_MODE_SENSE 0x5A
+#define ATAPI_MODE_SELECT 0x55
+#define ATAPI_FORMAT_UNIT 0x24
+
+//
+// ATAPI Command Descriptor Block
+//
+
+typedef struct _MODE_SENSE_10 {
+ UCHAR OperationCode;
+ UCHAR Reserved1;
+ UCHAR PageCode : 6;
+ UCHAR Pc : 2;
+ UCHAR Reserved2[4];
+ UCHAR ParameterListLengthMsb;
+ UCHAR ParameterListLengthLsb;
+ UCHAR Reserved3[3];
+} MODE_SENSE_10, *PMODE_SENSE_10;
+
+typedef struct _MODE_SELECT_10 {
+ UCHAR OperationCode;
+ UCHAR Reserved1 : 4;
+ UCHAR PFBit : 1;
+ UCHAR Reserved2 : 3;
+ UCHAR Reserved3[5];
+ UCHAR ParameterListLengthMsb;
+ UCHAR ParameterListLengthLsb;
+ UCHAR Reserved4[3];
+} MODE_SELECT_10, *PMODE_SELECT_10;
+
+typedef struct _MODE_PARAMETER_HEADER_10 {
+ UCHAR ModeDataLengthMsb;
+ UCHAR ModeDataLengthLsb;
+ UCHAR MediumType;
+ UCHAR Reserved[5];
+}MODE_PARAMETER_HEADER_10, *PMODE_PARAMETER_HEADER_10;
+
+//
+// IDE command definitions
+//
+
+#define IDE_COMMAND_ATAPI_RESET 0x08
+#define IDE_COMMAND_RECALIBRATE 0x10
+#define IDE_COMMAND_READ 0x20
+#define IDE_COMMAND_WRITE 0x30
+#define IDE_COMMAND_VERIFY 0x40
+#define IDE_COMMAND_SEEK 0x70
+#define IDE_COMMAND_SET_DRIVE_PARAMETERS 0x91
+#define IDE_COMMAND_ATAPI_PACKET 0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1
+#define IDE_COMMAND_READ_MULTIPLE 0xC4
+#define IDE_COMMAND_WRITE_MULTIPLE 0xC5
+#define IDE_COMMAND_SET_MULTIPLE 0xC6
+#define IDE_COMMAND_READ_DMA 0xC8
+#define IDE_COMMAND_WRITE_DMA 0xCA
+#define IDE_COMMAND_GET_MEDIA_STATUS 0xDA
+#define IDE_COMMAND_ENABLE_MEDIA_STATUS 0xEF
+#define IDE_COMMAND_IDENTIFY 0xEC
+#define IDE_COMMAND_MEDIA_EJECT 0xED
+#define IDE_COMMAND_DOOR_LOCK 0xDE
+#define IDE_COMMAND_DOOR_UNLOCK 0xDF
+
+//
+// IDE status definitions
+//
+
+#define IDE_STATUS_ERROR 0x01
+#define IDE_STATUS_INDEX 0x02
+#define IDE_STATUS_CORRECTED_ERROR 0x04
+#define IDE_STATUS_DRQ 0x08
+#define IDE_STATUS_DSC 0x10
+#define IDE_STATUS_DRDY 0x40
+#define IDE_STATUS_IDLE 0x50
+#define IDE_STATUS_BUSY 0x80
+
+//
+// IDE drive select/head definitions
+//
+
+#define IDE_DRIVE_SELECT_1 0xA0
+#define IDE_DRIVE_SELECT_2 0x10
+
+//
+// IDE drive control definitions
+//
+
+#define IDE_DC_DISABLE_INTERRUPTS 0x02
+#define IDE_DC_RESET_CONTROLLER 0x04
+#define IDE_DC_REENABLE_CONTROLLER 0x00
+
+//
+// IDE error definitions
+//
+
+#define IDE_ERROR_BAD_BLOCK 0x80
+#define IDE_ERROR_DATA_ERROR 0x40
+#define IDE_ERROR_MEDIA_CHANGE 0x20
+#define IDE_ERROR_ID_NOT_FOUND 0x10
+#define IDE_ERROR_MEDIA_CHANGE_REQ 0x08
+#define IDE_ERROR_COMMAND_ABORTED 0x04
+#define IDE_ERROR_END_OF_MEDIA 0x02
+#define IDE_ERROR_ILLEGAL_LENGTH 0x01
+
+//
+// ATAPI register definition
+//
+
+typedef struct _ATAPI_REGISTERS_1 {
+ USHORT Data;
+ UCHAR InterruptReason;
+ UCHAR Unused1;
+ UCHAR ByteCountLow;
+ UCHAR ByteCountHigh;
+ UCHAR DriveSelect;
+ UCHAR Command;
+} ATAPI_REGISTERS_1, *PATAPI_REGISTERS_1;
+
+typedef struct _ATAPI_REGISTERS_2 {
+ UCHAR DeviceControl;
+ UCHAR DriveAddress;
+} ATAPI_REGISTERS_2, *PATAPI_REGISTERS_2;
+
+
+//
+// ATAPI interrupt reasons
+//
+
+#define ATAPI_IR_COD 0x01
+#define ATAPI_IR_IO 0x02
+
+//
+// IDENTIFY data
+//
+#pragma pack (1)
+typedef struct _IDENTIFY_DATA {
+ USHORT GeneralConfiguration; // 00 00
+ USHORT NumberOfCylinders; // 02 1
+ USHORT Reserved1; // 04 2
+ USHORT NumberOfHeads; // 06 3
+ USHORT UnformattedBytesPerTrack; // 08 4
+ USHORT UnformattedBytesPerSector; // 0A 5
+ USHORT SectorsPerTrack; // 0C 6
+ USHORT VendorUnique1[3]; // 0E 7-9
+ USHORT SerialNumber[10]; // 14 10-19
+ USHORT BufferType; // 28 20
+ USHORT BufferSectorSize; // 2A 21
+ USHORT NumberOfEccBytes; // 2C 22
+ UCHAR FirmwareRevision[8]; // 2E 23-26
+ UCHAR ModelNumber[40]; // 36 27-46
+ UCHAR MaximumBlockTransfer; // 5E 47
+ UCHAR VendorUnique2; // 5F
+ USHORT DoubleWordIo; // 60 48
+ USHORT Capabilities; // 62 49
+ USHORT Reserved2; // 64 50
+ UCHAR VendorUnique3; // 66 51
+ UCHAR PioCycleTimingMode; // 67
+ UCHAR VendorUnique4; // 68 52
+ UCHAR DmaCycleTimingMode; // 69
+ USHORT TranslationFieldsValid:2; // 6A 53
+ USHORT Reserved3:14;
+ USHORT NumberOfCurrentCylinders; // 6C 54
+ USHORT NumberOfCurrentHeads; // 6E 55
+ USHORT CurrentSectorsPerTrack; // 70 56
+ ULONG CurrentSectorCapacity; // 72 57-58
+ USHORT CurrentMultiSectorSetting; // 59
+ ULONG UserAddressableSectors; // 60-61
+ USHORT SingleWordDMASupport : 8; // 62
+ USHORT SingleWordDMAActive : 8;
+ USHORT MultiWordDMASupport : 8; // 63
+ USHORT MultiWordDMAActive : 8;
+ USHORT AdvancedPIOModes : 8; // 64
+ USHORT Reserved4 : 8;
+ USHORT MinimumMWXferCycleTime; // 65
+ USHORT RecommendedMWXferCycleTime; // 66
+ USHORT MinimumPIOCycleTime; // 67
+ USHORT MinimumPIOCycleTimeIORDY; // 68
+ USHORT Reserved5[11]; // 69-79
+ USHORT MajorRevision; // 80
+ USHORT MinorRevision; // 81
+ USHORT Reserved6[45]; // 82-126
+ USHORT SpecialFunctionsEnabled; // 127
+ USHORT Reserved7[128]; // 128-255
+} IDENTIFY_DATA, *PIDENTIFY_DATA;
+
+//
+// Identify data without the Reserved4.
+//
+
+typedef struct _IDENTIFY_DATA2 {
+ USHORT GeneralConfiguration; // 00 00
+ USHORT NumberOfCylinders; // 02 1
+ USHORT Reserved1; // 04 2
+ USHORT NumberOfHeads; // 06 3
+ USHORT UnformattedBytesPerTrack; // 08 4
+ USHORT UnformattedBytesPerSector; // 0A 5
+ USHORT SectorsPerTrack; // 0C 6
+ USHORT VendorUnique1[3]; // 0E 7-9
+ USHORT SerialNumber[10]; // 14 10-19
+ USHORT BufferType; // 28 20
+ USHORT BufferSectorSize; // 2A 21
+ USHORT NumberOfEccBytes; // 2C 22
+ UCHAR FirmwareRevision[8]; // 2E 23-26
+ UCHAR ModelNumber[40]; // 36 27-46
+ UCHAR MaximumBlockTransfer; // 5E 47
+ UCHAR VendorUnique2; // 5F
+ USHORT DoubleWordIo; // 60 48
+ USHORT Capabilities; // 62 49
+ USHORT Reserved2; // 64 50
+ UCHAR VendorUnique3; // 66 51
+ UCHAR PioCycleTimingMode; // 67
+ UCHAR VendorUnique4; // 68 52
+ UCHAR DmaCycleTimingMode; // 69
+ USHORT TranslationFieldsValid:2; // 6A 53
+ USHORT Reserved3:14;
+ USHORT NumberOfCurrentCylinders; // 6C 54
+ USHORT NumberOfCurrentHeads; // 6E 55
+ USHORT CurrentSectorsPerTrack; // 70 56
+ ULONG CurrentSectorCapacity; // 72 57-58
+ USHORT CurrentMultiSectorSetting; // 59
+ ULONG UserAddressableSectors; // 60-61
+ USHORT SingleWordDMASupport : 8; // 62
+ USHORT SingleWordDMAActive : 8;
+ USHORT MultiWordDMASupport : 8; // 63
+ USHORT MultiWordDMAActive : 8;
+ USHORT AdvancedPIOModes : 8; // 64
+ USHORT Reserved4 : 8;
+ USHORT MinimumMWXferCycleTime; // 65
+ USHORT RecommendedMWXferCycleTime; // 66
+ USHORT MinimumPIOCycleTime; // 67
+ USHORT MinimumPIOCycleTimeIORDY; // 68
+ USHORT Reserved5[11]; // 69-79
+ USHORT MajorRevision; // 80
+ USHORT MinorRevision; // 81
+ USHORT Reserved6[45]; // 82-126
+ USHORT SpecialFunctionsEnabled; // 127
+ USHORT Reserved7[2]; // 128-129
+} IDENTIFY_DATA2, *PIDENTIFY_DATA2;
+#pragma pack ()
+
+#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA)
+
+//
+// IDENTIFY capability bit definitions.
+//
+
+#define IDENTIFY_CAPABILITIES_DMA_SUPPORTED (1 << 8)
+#define IDENTIFY_CAPABILITIES_LBA_SUPPORTED (1 << 9)
+#define IDENTIFY_CAPABILITIES_IOREADY_CAN_BE_DISABLED (1 << 10)
+#define IDENTIFY_CAPABILITIES_IOREADY_SUPPORTED (1 << 11)
+
+
+//
+// Select LBA mode when progran IDE device
+//
+#define IDE_LBA_MODE (1 << 6)
+
+//
+// Beautification macros
+//
+
+#define GetStatus(BaseIoAddress, Status) \
+ Status = ScsiPortReadPortUchar(&BaseIoAddress->Command);
+
+#define GetBaseStatus(BaseIoAddress, Status) \
+ Status = ScsiPortReadPortUchar(&BaseIoAddress->Command);
+
+#define WriteCommand(BaseIoAddress, Command) \
+ ScsiPortWritePortUchar(&BaseIoAddress->Command, Command);
+
+
+
+#define ReadBuffer(BaseIoAddress, Buffer, Count) \
+ ScsiPortReadPortBufferUshort(&BaseIoAddress->Data, \
+ Buffer, \
+ Count);
+
+#define WriteBuffer(BaseIoAddress, Buffer, Count) \
+ ScsiPortWritePortBufferUshort(&BaseIoAddress->Data, \
+ Buffer, \
+ Count);
+
+#define ReadBuffer2(BaseIoAddress, Buffer, Count) \
+ ScsiPortReadPortBufferUlong(&BaseIoAddress->Data, \
+ Buffer, \
+ Count);
+
+#define WriteBuffer2(BaseIoAddress, Buffer, Count) \
+ ScsiPortWritePortBufferUlong(&BaseIoAddress->Data, \
+ Buffer, \
+ Count);
+
+#define WaitOnBusy(BaseIoAddress, Status) \
+{ \
+ ULONG i; \
+ for (i=0; i<20000; i++) { \
+ GetStatus(BaseIoAddress, Status); \
+ if (Status & IDE_STATUS_BUSY) { \
+ ScsiPortStallExecution(150); \
+ continue; \
+ } else { \
+ break; \
+ } \
+ if (i == 20000) \
+ DebugPrint ((0, "WaitOnBusy failed in %s line %u. status = 0x%x\n", __FILE__, __LINE__, (ULONG) (Status))); \
+ } \
+}
+
+#define WaitOnBaseBusy(BaseIoAddress, Status) \
+{ \
+ ULONG i; \
+ for (i=0; i<20000; i++) { \
+ GetBaseStatus(BaseIoAddress, Status); \
+ if (Status & IDE_STATUS_BUSY) { \
+ ScsiPortStallExecution(150); \
+ continue; \
+ } else { \
+ break; \
+ } \
+ } \
+}
+
+#define WaitForDrq(BaseIoAddress, Status) \
+{ \
+ ULONG i; \
+ for (i=0; i<1000; i++) { \
+ GetStatus(BaseIoAddress, Status); \
+ if (Status & IDE_STATUS_BUSY) { \
+ ScsiPortStallExecution(100); \
+ } else if (Status & IDE_STATUS_DRQ) { \
+ break; \
+ } else { \
+ ScsiPortStallExecution(200); \
+ } \
+ } \
+}
+
+
+#define WaitShortForDrq(BaseIoAddress, Status) \
+{ \
+ ULONG i; \
+ for (i=0; i<2; i++) { \
+ GetStatus(BaseIoAddress, Status); \
+ if (Status & IDE_STATUS_BUSY) { \
+ ScsiPortStallExecution(100); \
+ } else if (Status & IDE_STATUS_DRQ) { \
+ break; \
+ } else { \
+ ScsiPortStallExecution(100); \
+ } \
+ } \
+}
+
+#define AtapiSoftReset(BaseIoAddress, DeviceNumber, interruptOff) \
+{\
+ ULONG i;\
+ UCHAR statusByte; \
+ DebugPrintTickCount(); \
+ ScsiPortWritePortUchar(&BaseIoAddress->DriveSelect,(UCHAR)(((DeviceNumber & 0x1) << 4) | 0xA0)); \
+ ScsiPortStallExecution(500);\
+ ScsiPortWritePortUchar(&BaseIoAddress->Command, IDE_COMMAND_ATAPI_RESET); \
+ for (i = 0; i < 1000; i++) { \
+ ScsiPortStallExecution(999); \
+ }\
+ ScsiPortWritePortUchar(&BaseIoAddress->DriveSelect,(UCHAR)((DeviceNumber << 4) | 0xA0)); \
+ WaitOnBusy(BaseIoAddress, statusByte); \
+ ScsiPortStallExecution(500);\
+ if (interruptOff) { \
+ ScsiPortWritePortUchar(&baseIoAddress2->DeviceControl, IDE_DC_DISABLE_INTERRUPTS); \
+ } \
+ DebugPrintTickCount(); \
+}
+
+#define IdeHardReset(BaseIoAddress1, BaseIoAddress2, result) \
+{\
+ UCHAR statusByte;\
+ ULONG i;\
+ ScsiPortWritePortUchar(&BaseIoAddress2->DeviceControl,IDE_DC_RESET_CONTROLLER );\
+ ScsiPortStallExecution(50 * 1000);\
+ ScsiPortWritePortUchar(&BaseIoAddress2->DeviceControl,IDE_DC_REENABLE_CONTROLLER);\
+ for (i = 0; i < 1000 * 1000; i++) {\
+ statusByte = ScsiPortReadPortUchar(&BaseIoAddress1->Command);\
+ if (statusByte != IDE_STATUS_IDLE && statusByte != 0x0) {\
+ ScsiPortStallExecution(5);\
+ } else {\
+ break;\
+ }\
+ }\
+ if (i == 1000*1000) {\
+ result = FALSE;\
+ }\
+ result = TRUE;\
+}
+
+#define IS_RDP(OperationCode)\
+ ((OperationCode == SCSIOP_ERASE)||\
+ (OperationCode == SCSIOP_LOAD_UNLOAD)||\
+ (OperationCode == SCSIOP_LOCATE)||\
+ (OperationCode == SCSIOP_REWIND) ||\
+ (OperationCode == SCSIOP_SPACE)||\
+ (OperationCode == SCSIOP_SEEK)||\
+ (OperationCode == SCSIOP_WRITE_FILEMARKS))
+
+struct _CONTROLLER_PARAMETERS;
+
+//
+// Keep trap off DriverEntry status
+//
+typedef struct _FIND_STATE {
+
+ ULONG BusNumber;
+ ULONG SlotNumber;
+ ULONG LogicalDeviceNumber;
+ ULONG IdeChannel;
+
+ PULONG DefaultIoPort;
+ PULONG DefaultInterrupt;
+ PBOOLEAN IoAddressUsed;
+
+ struct _CONTROLLER_PARAMETERS * ControllerParameters;
+
+} FIND_STATE, * PFIND_STATE;
+
+//
+// Bus Master Physical Region Descriptor
+//
+#pragma pack (1)
+typedef struct _PHYSICAL_REGION_DESCRIPTOR {
+ ULONG PhyscialAddress;
+ ULONG ByteCount:16;
+ ULONG Reserved:15;
+ ULONG EndOfTable:1;
+} PHYSICAL_REGION_DESCRIPTOR, * PPHYSICAL_REGION_DESCRIPTOR;
+#pragma pack ()
+
+#define MAX_TRANSFER_SIZE_PER_SRB (0x20000)
+
+#define MAX_DEVICE (2)
+#define MAX_CHANNEL (2)
+
+//
+// Device extension
+//
+typedef struct _HW_DEVICE_EXTENSION {
+
+ //
+ // Current request on controller.
+ //
+
+ PSCSI_REQUEST_BLOCK CurrentSrb;
+
+ //
+ // Base register locations
+ //
+
+ PIDE_REGISTERS_1 BaseIoAddress1[2];
+ PIDE_REGISTERS_2 BaseIoAddress2[2];
+ PIDE_BUS_MASTER_REGISTERS BusMasterPortBase[2];
+
+ //
+ // Interrupt level
+ //
+
+ ULONG InterruptLevel;
+
+ //
+ // Interrupt Mode (Level or Edge)
+ //
+
+ ULONG InterruptMode;
+
+ //
+ // Data buffer pointer.
+ //
+
+ PUSHORT DataBuffer;
+
+ //
+ // Data words left.
+ //
+
+ ULONG WordsLeft;
+
+ //
+ // Number of channels being supported by one instantiation
+ // of the device extension. Normally (and correctly) one, but
+ // with so many broken PCI IDE controllers being sold, we have
+ // to support them.
+ //
+
+ ULONG NumberChannels;
+
+ //
+ // Count of errors. Used to turn off features.
+ //
+
+ ULONG ErrorCount;
+
+ //
+ // Indicates number of platters on changer-ish devices.
+ //
+
+ ULONG DiscsPresent[MAX_DEVICE * MAX_CHANNEL];
+
+ //
+ // Flags word for each possible device.
+ //
+
+ USHORT DeviceFlags[MAX_DEVICE * MAX_CHANNEL];
+
+ //
+ // Indicates the number of blocks transferred per int. according to the
+ // identify data.
+ //
+
+ UCHAR MaximumBlockXfer[MAX_DEVICE * MAX_CHANNEL];
+
+ //
+ // Indicates expecting an interrupt
+ //
+
+ BOOLEAN ExpectingInterrupt;
+
+ //
+ // Indicates DMA is in progress
+ //
+
+ BOOLEAN DMAInProgress;
+
+
+ //
+ // Indicate last tape command was DSC Restrictive.
+ //
+
+ BOOLEAN RDP;
+
+ //
+ // Driver is being used by the crash dump utility or ntldr.
+ //
+
+ BOOLEAN DriverMustPoll;
+
+ //
+ // Indicates use of 32-bit PIO
+ //
+
+ BOOLEAN DWordIO;
+
+ //
+ // Indicates whether '0x1f0' is the base address. Used
+ // in SMART Ioctl calls.
+ //
+
+ BOOLEAN PrimaryAddress;
+
+ //
+ // Placeholder for the sub-command value of the last
+ // SMART command.
+ //
+
+ UCHAR SmartCommand;
+
+ //
+ // Placeholder for status register after a GET_MEDIA_STATUS command
+ //
+
+ UCHAR ReturningMediaStatus;
+
+ UCHAR Reserved[1];
+
+ //
+ // Mechanism Status Srb Data
+ //
+ PSCSI_REQUEST_BLOCK OriginalSrb;
+ SCSI_REQUEST_BLOCK InternalSrb;
+ MECHANICAL_STATUS_INFORMATION_HEADER MechStatusData;
+ SENSE_DATA MechStatusSense;
+ ULONG MechStatusRetryCount;
+
+ //
+ // Identify data for device
+ //
+ IDENTIFY_DATA2 IdentifyData[MAX_DEVICE * MAX_CHANNEL];
+
+ //
+ // Bus Master Data
+ //
+ // Physcial Region Table for bus mastering
+ PPHYSICAL_REGION_DESCRIPTOR DataBufferDescriptionTablePtr;
+ ULONG DataBufferDescriptionTableSize;
+ PHYSICAL_ADDRESS DataBufferDescriptionTablePhysAddr;
+
+ //
+ // Controller Flags
+ //
+ USHORT ControllerFlags;
+
+ //
+ // Control whether we ship try to enable busmastering
+ //
+ BOOLEAN UseBusMasterController;
+
+ //
+ // Function to set bus master timing
+ //
+ BOOLEAN (*BMTimingControl) (struct _HW_DEVICE_EXTENSION * DeviceExtension);
+
+ //
+ // Function to set check whether a PCI IDE channel is enabled
+ //
+ BOOLEAN (*IsChannelEnabled) (PPCI_COMMON_CONFIG PciData, ULONG Channel);
+
+
+ // PCI Address
+ ULONG PciBusNumber;
+ ULONG PciDeviceNumber;
+ ULONG PciLogDevNumber;
+
+ //
+ // Device Specific Info.
+ //
+ struct _DEVICE_PARAMETERS {
+
+ ULONG MaxWordPerInterrupt;
+
+ UCHAR IdeReadCommand;
+ UCHAR IdeWriteCommand;
+
+ BOOLEAN IoReadyEnabled;
+ ULONG PioCycleTime;
+ ULONG DmaCycleTime;
+
+ ULONG BestPIOMode;
+ ULONG BestSingleWordDMAMode;
+ ULONG BestMultiWordDMAMode;
+
+ } DeviceParameters[MAX_CHANNEL * MAX_DEVICE];
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+//
+// PCI IDE Controller definition
+//
+typedef struct _CONTROLLER_PARAMETERS {
+
+ INTERFACE_TYPE AdapterInterfaceType;
+
+ PUCHAR VendorId;
+ USHORT VendorIdLength;
+ PUCHAR DeviceId;
+ USHORT DeviceIdLength;
+
+ ULONG NumberOfIdeBus;
+
+ BOOLEAN SingleFIFO;
+
+ BOOLEAN (*TimingControl) (PHW_DEVICE_EXTENSION DeviceExtension);
+
+ BOOLEAN (*IsChannelEnabled) (PPCI_COMMON_CONFIG PciData, ULONG Channel);
+
+} CONTROLLER_PARAMETERS, * PCONTROLLER_PARAMETERS;
+
+//
+// max number of CHS addressable sectors
+//
+#define MAX_NUM_CHS_ADDRESSABLE_SECTORS ((ULONG) (16515072 - 1))
+
+
+//
+// IDE Cycle Timing
+//
+#define PIO_MODE0_CYCLE_TIME 600
+#define PIO_MODE1_CYCLE_TIME 383
+#define PIO_MODE2_CYCLE_TIME 240
+#define PIO_MODE3_CYCLE_TIME 180
+#define PIO_MODE4_CYCLE_TIME 120
+
+#define SWDMA_MODE0_CYCLE_TIME 960
+#define SWDMA_MODE1_CYCLE_TIME 480
+#define SWDMA_MODE2_CYCLE_TIME 240
+
+#define MWDMA_MODE0_CYCLE_TIME 480
+#define MWDMA_MODE1_CYCLE_TIME 150
+#define MWDMA_MODE2_CYCLE_TIME 120
+
+#define UNINITIALIZED_CYCLE_TIME 0xffffffff
+
+//
+// invalid mode values
+//
+#define INVALID_PIO_MODE 0xffffffff
+#define INVALID_SWDMA_MODE 0xffffffff
+#define INVALID_MWDMA_MODE 0xffffffff
+
+
+//
+// Bus Master Status Register
+//
+#define BUSMASTER_DMA_SIMPLEX_BIT ((UCHAR) (1 << 7))
+#define BUSMASTER_DEVICE1_DMA_OK ((UCHAR) (1 << 6))
+#define BUSMASTER_DEVICE0_DMA_OK ((UCHAR) (1 << 5))
+#define BUSMASTER_INTERRUPT ((UCHAR) (1 << 2))
+#define BUSMASTER_ERROR ((UCHAR) (1 << 1))
+#define BUSMASTER_ACTIVE ((UCHAR) (1 << 0))
+
+
+//
+// PCI access port
+//
+#define PCI_ADDR_PORT (0x0cf8)
+#define PCI_DATA_PORT (0x0cfc)
+#define PCI_ADDRESS(bus, deviceNum, funcNum, offset) \
+ ((1 << 31) | \
+ ((bus & 0xff) << 16) | \
+ ((deviceNum & 0x1f) << 11) | \
+ ((funcNum & 0x7) << 8) | \
+ ((offset & 0x3f) << 2))
+
+// BUG BUG BUG
+// GET PAGE_SIZE into miniport.h
+#ifdef ALPHA
+#define PAGE_SIZE (ULONG)0x2000
+#else // MIPS, PPC, I386
+#define PAGE_SIZE (ULONG)0x1000
+#endif
+
+#define SCSIOP_ATA_PASSTHROUGH (0xcc)
+
+//
+// valid DMA detection level
+//
+#define DMADETECT_PIO 0
+#define DMADETECT_SAFE 1
+#define DMADETECT_UNSAFE 2
diff --git a/private/ntos/miniport/atapi/atapi.rc b/private/ntos/miniport/atapi/atapi.rc
new file mode 100644
index 000000000..ffb61dd1b
--- /dev/null
+++ b/private/ntos/miniport/atapi/atapi.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "ATAPI IDE Miniport Driver"
+#define VER_INTERNALNAME_STR "atapi.sys"
+#define VER_ORIGINALFILENAME_STR "atapi.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/atapi/intel.c b/private/ntos/miniport/atapi/intel.c
new file mode 100644
index 000000000..7ce65ee8b
--- /dev/null
+++ b/private/ntos/miniport/atapi/intel.c
@@ -0,0 +1,37 @@
+#include "miniport.h"
+#include "atapi.h"
+#include "ntdddisk.h"
+#include "ntddscsi.h"
+#include "intel.h"
+
+BOOLEAN
+PiixTimingControl (
+ struct _HW_DEVICE_EXTENSION DeviceExtension
+ )
+{
+
+
+
+
+ return TRUE;
+}
+
+BOOLEAN IntelIsChannelEnabled (
+ PPCI_COMMON_CONFIG PciData,
+ ULONG Channel)
+{
+ PUCHAR rawPciData = (PUCHAR) PciData;
+ ULONG pciDataOffset;
+
+ if (Channel == 0) {
+ pciDataOffset = 0x41;
+ } else {
+ pciDataOffset = 0x43;
+ }
+
+ return (rawPciData[pciDataOffset] & 0x80);
+}
+
+
+
+
diff --git a/private/ntos/miniport/atapi/intel.h b/private/ntos/miniport/atapi/intel.h
new file mode 100644
index 000000000..329220572
--- /dev/null
+++ b/private/ntos/miniport/atapi/intel.h
@@ -0,0 +1,10 @@
+BOOLEAN
+PiixTimingControl (
+ struct _HW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN IntelIsChannelEnabled (
+ PPCI_COMMON_CONFIG PciData,
+ ULONG Channel);
+
+
diff --git a/private/ntos/miniport/atapi/makefile b/private/ntos/miniport/atapi/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/atapi/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/atapi/sources b/private/ntos/miniport/atapi/sources
new file mode 100644
index 000000000..833938ef4
--- /dev/null
+++ b/private/ntos/miniport/atapi/sources
@@ -0,0 +1,42 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=atapi
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+
+TARGETLIBS=\nt\public\sdk\lib\*\scsiport.lib
+!IF $(ALPHA)
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib $(BASEDIR)\public\sdk\lib\*\libcntpr.lib
+!ENDIF
+
+SOURCES=atapi.c \
+ atapi.rc \
+ intel.c
+
diff --git a/private/ntos/miniport/buslogic/buslogic.c b/private/ntos/miniport/buslogic/buslogic.c
new file mode 100644
index 000000000..5d3b3cee2
--- /dev/null
+++ b/private/ntos/miniport/buslogic/buslogic.c
@@ -0,0 +1,3181 @@
+/*++
+
+Copyright (c) 1992 BusLogic, Inc.
+
+Module Name:
+
+ Buslogic.c
+
+Abstract:
+
+ This is the port driver for the BusLogic SCSI ISA/EISA/MCA Adapters.
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "buslogic.h" // includes scsi.h
+
+//
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//
+
+ULONG AdapterAddresses[] = {0X330, 0X334, 0X234, 0X134, 0X130, 0X230, 0};
+ULONG PciAdapterAddresses[] = {0Xfff,0xfff,0xfff,0xfff,0xfff,0xfff,0}; /* dummy entry for PCI */
+
+UCHAR VendorId[4]={'1','0','4','b'};
+UCHAR NewDeviceId[4]={'1','0','4','0'};
+
+ULONG InittedEISABoards = 0;
+//
+// Function declarations
+//
+// Functions that start with 'BLogic' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+BLogicEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+BLogicDetermineInstalled(
+ IN PCARD_STRUC CardPtr,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PBL_CONTEXT CurrContextPtr,
+ OUT PBOOLEAN Again
+ );
+
+ULONG
+BLogicFindAdapter (
+ IN PCARD_STRUC CardPtr,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+BLogicAdapterState(
+ IN PCARD_STRUC CardPtr,
+ IN PVOID Context,
+ IN BOOLEAN SaveState
+ );
+
+BOOLEAN
+BLogicHwInitialize(
+ IN PCARD_STRUC CardPtr
+ );
+
+BOOLEAN
+BLogicStartIo(
+ IN PCARD_STRUC CardPtr,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+BLogicInterrupt(
+ IN PCARD_STRUC CardPtr
+ );
+
+BOOLEAN
+BLogicResetBus(
+ IN PCARD_STRUC CardPtr,
+ IN ULONG PathId
+ );
+
+BOOLEAN
+ResetBus(
+ IN PCARD_STRUC CardPtr,
+ IN ULONG PathId
+ );
+
+// Add the following function back in!
+
+BOOLEAN
+ReInitializeHBA(
+ IN PCARD_STRUC CardPtr,
+ IN ULONG PathId
+ );
+//
+// This function is called from BLogicStartIo.
+//
+
+VOID
+BuildCcb(
+ IN PCARD_STRUC CardPtr,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BuildCcb.
+//
+
+VOID
+BuildSdl(
+ IN PCARD_STRUC CardPtr,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BLogicInitialize.
+//
+
+BOOLEAN
+AdapterPresent(
+ IN PCARD_STRUC CardPtr
+ );
+
+//
+// This function is called from BLogicInterrupt.
+//
+
+UCHAR
+MapError(
+ IN PCARD_STRUC CardPtr,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCCB Ccb
+ );
+
+BOOLEAN
+ReadCommandRegister(
+ IN PCARD_STRUC CardPtr,
+ OUT PUCHAR DataByte
+ );
+
+BOOLEAN
+WriteCommandRegister(
+ IN PCARD_STRUC CardPtr,
+ IN UCHAR AdapterCommand
+ );
+
+BOOLEAN
+AdjustCCBqueue(
+ PCCB ccbp,
+ IN PDEV_STRUC devptr
+ );
+
+PMBI
+DoneMbox(
+ IN PCARD_STRUC CardPtr
+ );
+
+BOOLEAN
+SendCCB(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCARD_STRUC CardPtr,
+ IN PDEV_STRUC DevStruc
+ );
+
+BOOLEAN
+FinishHBACmd(
+ IN PCARD_STRUC CardPtr
+ );
+
+BOOLEAN
+CheckInvalid(
+ IN PCARD_STRUC CardPtr
+ );
+
+ULONG
+FindOurEISAId(
+ IN PCARD_STRUC CardPtr,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ PBASE_REGISTER baseIoAddress
+ );
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ return BLogicEntry(DriverObject, Argument2);
+
+} // end DriverEntry()
+
+
+ULONG
+BLogicEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from DriverEntry if this driver is installable
+ or directly from the system if the driver is built into the kernel.
+ It calls the OS dependent driver which controls the initialization.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status return by scsi port intialize.
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ BL_CONTEXT CurrContext;
+ PBL_CONTEXT CurrContextPtr = &CurrContext;
+ ULONG isaStatus;
+ ULONG mcaStatus;
+ ULONG EisaStatus;
+ ULONG i,PCIStatus,LowStatus1,LowStatus2;
+
+ DebugPrint((1,"\n\nBusLogic SCSI MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = (PHW_INITIALIZE) BLogicHwInitialize;
+ hwInitializationData.HwResetBus = (PHW_RESET_BUS) BLogicResetBus;
+ hwInitializationData.HwStartIo = (PHW_STARTIO) BLogicStartIo;
+ hwInitializationData.HwInterrupt = (PHW_INTERRUPT) BLogicInterrupt;
+ hwInitializationData.HwFindAdapter = (PHW_FIND_ADAPTER) BLogicFindAdapter;
+ hwInitializationData.HwAdapterState = BLogicAdapterState;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+ hwInitializationData.TaggedQueuing = TRUE;
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(CARD_STRUC);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(DEV_STRUC);
+ hwInitializationData.NumberOfAccessRanges = 1;
+
+ //
+ // Ask for SRB extensions for CCBs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(CCB);
+
+ //
+ // The adapter count is used by the find adapter routine to track how
+ // which adapter addresses have been tested.
+ //
+
+ CurrContextPtr->AdapterCount = 0;
+ CurrContextPtr->PCIDevId = 0x1040;
+
+ //
+ // try to configure for the PCI bus, fully-compliant HBA.
+ // Specify the bus type.
+ //
+ hwInitializationData.AdapterInterfaceType = PCIBus;
+ hwInitializationData.VendorId = VendorId;
+ hwInitializationData.VendorIdLength = 4;
+ hwInitializationData.DeviceId = NewDeviceId;
+ hwInitializationData.DeviceIdLength = 4;
+ PCIStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, CurrContextPtr);
+
+ //
+ // Now try to configure for the EISA bus.
+ // Specify the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ CurrContextPtr->AdapterCount = 0;
+ CurrContextPtr->PCIDevId = 0;
+ EisaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, CurrContextPtr);
+
+
+ //
+ // Now try to configure for the Mca bus.
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = MicroChannel;
+
+ CurrContextPtr->AdapterCount = 0;
+ CurrContextPtr->PCIDevId = 0;
+ mcaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, CurrContextPtr);
+
+ //
+ // Now try to configure for the ISA bus.
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Isa;
+
+ CurrContextPtr->AdapterCount = 0;
+ CurrContextPtr->PCIDevId = 0;
+ isaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, CurrContextPtr);
+
+ //
+ // Return the smallest status.
+ //
+
+ LowStatus1 = (PCIStatus < EisaStatus ? PCIStatus : EisaStatus);
+ LowStatus2 = (mcaStatus < isaStatus ? mcaStatus : isaStatus);
+
+ return(LowStatus1 < LowStatus2 ? LowStatus1 : LowStatus2);
+
+} // end BLogicEntry()
+
+
+ULONG
+BLogicFindAdapter (
+ IN PCARD_STRUC CardPtr,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+ Context - Register base address
+ ConfigInfo - Configuration information structure describing HBA
+ This structure is defined in PORT.H.
+
+Return Value:
+
+ ULONG
+
+--*/
+
+{
+ ULONG length;
+ ULONG status;
+ ULONG i;
+ UCHAR adapterTid;
+ UCHAR dmaChannel;
+ UCHAR irq;
+ UCHAR bit;
+ UCHAR VesaCard = 0;
+ UCHAR ThrowAway;
+ PBASE_REGISTER baseIoAddress;
+ BOOLEAN NoErrorOnWide = TRUE;
+ PBL_CONTEXT CurrContextPtr = (PBL_CONTEXT)Context;
+
+ //
+ // Determine if there are any adapters installed. Determine installed
+ // will initialize the BaseIoAddress if an adapter is found.
+ //
+
+ status = BLogicDetermineInstalled(CardPtr,
+ ConfigInfo,
+ (PBL_CONTEXT)CurrContextPtr,
+ Again);
+
+ //
+ // If there are not adapter's found then return.
+ //
+
+ if ((status != SP_RETURN_FOUND) && (status != RETURN_FOUND_VESA)) {
+ return(status);
+ }
+
+ baseIoAddress = CardPtr->BaseIoAddress;
+
+ if (status == RETURN_FOUND_VESA) {
+ VesaCard = 1;
+ }
+
+ //
+ // Issue adapter command to get IRQ.
+ //
+ // Returns 3 data bytes:
+ //
+ // Byte 0 Dma Channel
+ //
+ // Byte 1 Interrupt Channel
+ //
+ // Byte 2 Adapter SCSI ID
+ //
+
+ if (!WriteCommandRegister(CardPtr, AC_RET_CONFIGURATION_DATA)) {
+ DebugPrint((1,"BLogicFindAdapter: Get configuration data command failed\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Determine DMA channel.
+ //
+
+ if (!ReadCommandRegister(CardPtr,&dmaChannel)) {
+ DebugPrint((1,"BLogicFindAdapter: Couldn't read dma channel\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ /* EISA may have DMA channel disabled or MCA byte is not valid */
+ /* also, vesa card always returns DMA channel 5 */
+
+ if ((dmaChannel != 0) && (!VesaCard)
+ && (ConfigInfo->AdapterInterfaceType != PCIBus)){
+ WHICH_BIT(dmaChannel,bit);
+ ConfigInfo->DmaChannel = bit;
+ }
+
+ DebugPrint((2,"BLogicFindAdapter: DMA channel is %x\n",
+ ConfigInfo->DmaChannel));
+
+ //
+ // Determine hardware interrupt vector.
+ //
+
+ if (!ReadCommandRegister(CardPtr,&irq)) {
+ DebugPrint((1,"BLogicFindAdapter: Couldn't read adapter irq\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ WHICH_BIT(irq, bit);
+
+ //
+ // BusInterruptLevel is already provided for us in the ConfigInfo
+ // structure on the fully-compliant 946C boards - otherwise,
+ // IRQ assignment from the 0Bh HBA command
+ //
+
+ if (!((ConfigInfo->AdapterInterfaceType == PCIBus) &&
+ (CurrContextPtr->PCIDevId == 0x1040)))
+ {
+ ConfigInfo->BusInterruptLevel = (UCHAR) 9 + bit;
+ }
+ //
+ // Determine what SCSI bus id the adapter is on.
+ //
+
+ if (!ReadCommandRegister(CardPtr,&adapterTid)) {
+ DebugPrint((1,"BLogicFindAdapter: Couldn't read adapter SCSI id\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+ DebugPrint((1,"BLogicFindAdapter: Setup info cmd failed\n"));
+ return FALSE;
+ }
+
+ //
+ // Set number of buses.
+ //
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InitiatorBusId[0] = adapterTid;
+ CardPtr->HostTargetId = adapterTid;
+
+ // ConfigInfo->MaximumTransferLength = MAX_TRANSFER_SIZE;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_DESCRIPTORS - 1;
+ CardPtr->MailBoxArray = ScsiPortGetUncachedExtension(
+ CardPtr,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ if (CardPtr->MailBoxArray == NULL) {
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ CardPtr,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 6 << 16
+ );
+
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // Convert virtual to physical mailbox address.
+ //
+
+ CardPtr->MailBoxArray->MailboxPA =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(CardPtr,
+ NULL,
+ CardPtr->MailBoxArray->Mbo,
+ &length));
+
+ //
+ // Assume that physical address is below 16M
+ //
+
+ ASSERT(CardPtr->MailBoxArray->MailboxPA < 0x1000000);
+
+ // check for wide support ONLY if on NT 3.5 platform */
+
+ if (ConfigInfo->Length == CONFIG_INFO_VERSION_2)
+ {
+ CardPtr->Flags |= OS_SUPPORTS_WIDE;
+
+ // default to non-wide support
+
+ ConfigInfo->MaximumNumberOfTargets = 8;
+
+ // turn on wide support if available
+
+ NoErrorOnWide = TRUE;
+
+ if (!WriteCommandRegister(CardPtr, AC_WIDE_SUPPORT)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ NoErrorOnWide = FALSE;
+ }
+ else if (!CheckInvalid(CardPtr)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ // DebugPrint((0,"BLogicFindAdapter: check invalid failed \n"));
+ NoErrorOnWide = FALSE;
+ }
+ else if (!WriteCommandRegister(CardPtr, 0x01)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ NoErrorOnWide = FALSE;
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ NoErrorOnWide = FALSE;
+ }
+ else if (NoErrorOnWide) {
+ CardPtr->Flags |= WIDE_ENABLED;
+ ConfigInfo->MaximumNumberOfTargets = 16;
+
+ }
+ } /* end if NT 3.5, then check for wide support */
+
+ DebugPrint((3,"BLogicFindAdapter: Configuration completed\n"));
+
+
+ //
+ // enable generation on interrupts to the host on HBAs that support
+ // the 0x25 command used previously to disable generation of ints
+ // during this routine's call to DetermineInstalled
+ //
+
+
+ if (!WriteCommandRegister(CardPtr,AC_INT_GENERATION_STATE)){
+ DebugPrint((1,"BLogicFindAdapter: ints enable/disable cmd failed\n"));
+ }
+ else if (!CheckInvalid(CardPtr)) {
+ DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n")); DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
+
+ }
+ else{
+ ThrowAway = ENABLE_INTS;
+ if (!WriteCommandRegister(CardPtr,ThrowAway)){
+ DebugPrint((1,"BLogicFindAdapter: ints enable/disable cmd failed\n"));
+ }
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+
+ // this cmd DOES NOT generate an interrupt - so
+ // just check for command complete!
+
+ if (!(ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)
+ & (IOP_SCSI_HBA_IDLE))) {
+ DebugPrint((1,"BLogicFindAdapter: ints enable/disable cmd failed\n"));
+ }
+ }
+
+ //
+ // Set up DMA type based on bus type
+ //
+
+ ConfigInfo->Dma32BitAddresses =
+ (ConfigInfo->AdapterInterfaceType == Isa) ? FALSE : TRUE;
+ return SP_RETURN_FOUND;
+
+} // end BLogicFindAdapter()
+
+
+BOOLEAN
+BLogicAdapterState(
+ IN PCARD_STRUC CardPtr,
+ IN PVOID Context,
+ IN BOOLEAN SaveState
+ )
+
+/*++
+
+Routine Description:
+
+ The Buslogic adapters will take advantage of work done in the past to
+ support Novell networks. This means any MSDOS mode driver will be set
+ up to run without using mailboxes. This will save the work of having
+ to save/restore mailbox locations for the MSDOS driver in this routine.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+ Context - Register base address
+ SaveState - TRUE == Save real mode state ; FALSE == Restore real mode state
+
+Return Value:
+
+ TRUE - Save/Restore operation was successful.
+
+--*/
+
+{
+ return TRUE;
+} // end BLogicAdapterState()
+
+
+
+BOOLEAN
+BLIsCloneIDByte(
+ IN PCARD_STRUC CardPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the adapter ID command and determines if the
+ adapter is potentially a BusLogic adapter.
+
+Arguments:
+
+ CardPtr - HBA miniport data storage
+
+Return Value:
+
+ TRUE if it looks like the adapter is a clone or if the command fails.
+ FALSE otherwise.
+
+--*/
+
+{
+ UCHAR byte;
+ UCHAR specialOptions;
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
+ IOP_INTERRUPT_RESET);
+
+ if (!WriteCommandRegister(CardPtr, AC_ADAPTER_INQUIRY)) {
+ return TRUE;
+ }
+
+ //
+ // Byte 0.
+ //
+
+ if ((ReadCommandRegister(CardPtr, &byte)) == FALSE) {
+ return TRUE;
+ }
+
+ //
+ // Get the special options byte.
+ //
+
+ if ((ReadCommandRegister(CardPtr, &specialOptions)) == FALSE) {
+ return TRUE;
+ }
+
+ //
+ // Get the last two bytes and clear the interrupt.
+ //
+
+ if ((ReadCommandRegister(CardPtr, &byte)) == FALSE) {
+ return TRUE;
+ }
+
+ if ((ReadCommandRegister(CardPtr, &byte)) == FALSE) {
+ return TRUE;
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+ DebugPrint((1,"BLogicIsClone: Setup info cmd failed\n"));
+ return FALSE;
+ }
+
+ if ((specialOptions == 0x30) || (specialOptions == 0x42)) {
+
+ //
+ // This is an adaptec or AMI adapter.
+ //
+
+ return TRUE;
+ }
+
+ return FALSE;
+} // end BLIsCloneIDByte()
+
+
+ULONG
+BLogicDetermineInstalled(
+ IN PCARD_STRUC CardPtr,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PBL_CONTEXT CurrContextPtr,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if BusLogic SCSI adapter is installed in system
+ by reading the status register as each base I/O address
+ and looking for a pattern. If an adapter is found, the BaseIoAddres is
+ initialized.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+
+ ConfigInfo - Supplies the known configuraiton information.
+
+ CurrContextPtr - Supplies the count of adapter slots which have been
+ tested and, in the case of PCI, the Device ID.
+
+ Again - Returns whehter the OS specific driver should call again.
+
+Return Value:
+
+ Returns a status indicating whether a driver is present or not.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress;
+ PUCHAR ioSpace;
+ UCHAR ThrowAway,TaggedQueueSupport,EISAConfigReg;
+ UCHAR i;
+ BOOLEAN configProvided = FALSE;
+ UCHAR FoundVesaCard = 0;
+ ULONG *AdapterAddrPtr;
+ ULONG length;
+ SCSI_PHYSICAL_ADDRESS PhysAddr;
+
+
+ if (ConfigInfo->AdapterInterfaceType == Eisa)
+ InittedEISABoards = 1;
+
+ //
+ // Get the system physical address for this card. The card uses I/O space.
+ //
+
+ AdapterAddrPtr = (ConfigInfo->AdapterInterfaceType == PCIBus) ?
+ PciAdapterAddresses : AdapterAddresses;
+
+ //
+ // Scan though the adapter address looking for adapters.
+ //
+
+ ioSpace = NULL;
+ while (AdapterAddrPtr[CurrContextPtr->AdapterCount] != 0) {
+
+ //
+ // Free any previously allocated ioSpace.
+ //
+
+ if (ioSpace) {
+ ScsiPortFreeDeviceBase(
+ CardPtr,
+ ioSpace
+ );
+ }
+
+ //
+ // If the calling operating system has configuration information
+ // already established for the driver then the RangeLength will be
+ // set to zero instead of SP_UNINITIALIZED_VALUE. This is used
+ // to indicate the condition and this routine will search for an
+ // adapter based on the information provided.
+ //
+
+ configProvided = ((*ConfigInfo->AccessRanges)[0].RangeLength == 0) ? FALSE : TRUE;
+ if (configProvided) {
+ ioSpace = ScsiPortGetDeviceBase(
+ CardPtr, // CardPtr
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ (*ConfigInfo->AccessRanges)[0].RangeStart,
+ 0x16, // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+ if (!ioSpace) {
+ return SP_RETURN_NOT_FOUND;
+ }
+ } else {
+ ioSpace = ScsiPortGetDeviceBase(
+ CardPtr, // CardPtr
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress(AdapterAddrPtr[CurrContextPtr->AdapterCount]),
+ 0x16, // NumberOfBytes
+ TRUE // InIoSpace
+ );
+ if (!ioSpace) {
+ continue;
+ }
+ }
+ baseIoAddress = (PBASE_REGISTER)ioSpace;
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ CardPtr->BaseIoAddress = baseIoAddress;
+ DebugPrint((1,"BLogic: Base IO address is %x\n", baseIoAddress));
+
+ //
+ // Update the adapter count.
+ //
+
+ (CurrContextPtr->AdapterCount)++;
+
+
+
+ //
+ // Check to make sure the I/O range is not already in use
+ //
+ PhysAddr = ScsiPortConvertUlongToPhysicalAddress((ULONG)baseIoAddress);
+
+ if (!(ScsiPortValidateRange(
+ CardPtr, // CardPtr
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ PhysAddr,
+ 4, // NumberOfBytes
+ TRUE // InIoSpace
+ ))) {
+
+ continue;
+ }
+
+
+ if (((ScsiPortReadPortUchar((PUCHAR)baseIoAddress)) & (~0x2C)) == 0x10) {
+
+
+ //
+ // Before sending any other host adapter commands, try to disable
+ // generation of interrupts to the host (HBA command 0x25).
+ // On f.w. that support this command, we will be able
+ // to initialize an HBA that is sharing an IRQ level with a
+ // previously-initialized HBA on the same IRQ without winding up
+ // in the ISR for the first HBA in an endless "not our interrupt"
+ // loop due to level-triggered int generated by second HBA (not yet
+ // registered by the OS for any ISR). This should allow us to share
+ // interrupts on critical platforms such as PCI.
+ //
+
+
+ if (!WriteCommandRegister(CardPtr,AC_INT_GENERATION_STATE)){
+ DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n"));
+ }
+ else if (!CheckInvalid(CardPtr)) {
+ DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n")); DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
+ }
+ else{
+ ThrowAway = DISABLE_INTS;
+ if (!WriteCommandRegister(CardPtr,ThrowAway)){
+ DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n"));
+ }
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+
+ // this cmd DOES NOT generate an interrupt - so
+ // just check for command complete!
+
+ if (!(ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)
+ & (IOP_SCSI_HBA_IDLE))) {
+ DebugPrint((1,"BLogicDetInstalled: ints enable/disable cmd failed\n"));
+ }
+ }
+
+
+ //
+ // Check adapter inquiry to get rid of clones.
+ //
+
+ if (BLIsCloneIDByte(CardPtr)) {
+ DebugPrint((1, "BLogicDetermineInstalled: Clone byte not BusLogic\n"));
+ continue;
+ }
+
+ //
+ // Send BusLogic Internal cmd (84h) to distinguish from clones
+ //
+
+ if (!WriteCommandRegister(CardPtr,AC_EXTENDED_FWREV)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Extended FW Rev command failed\n"));
+ continue;
+ }
+
+ if (!ReadCommandRegister(CardPtr,&ThrowAway)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Extended FW Rev cmd failed\n"));
+ continue;
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Extended FW Rev cmd failed\n"));
+ continue;
+ }
+
+ //
+ // Send Extended Setup Info cmd (8dh)
+ //
+
+ if (!WriteCommandRegister(CardPtr,
+ AC_EXTENDED_SETUP_INFO)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Get Extended Setup Info cmd failed\n"));
+ continue;
+ }
+ if (!WriteCommandRegister(CardPtr,
+ 11)) { /* ask for 11 bytes */
+ DebugPrint((1,"BLogicDetermineInstalled: Get Extended Setup Info cmd failed\n"));
+ continue;
+ }
+
+ if (!ReadCommandRegister(CardPtr,&CardPtr->BusType)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Couldn't read parameter byte\n"));
+ continue;
+ }
+
+ //
+ // Throw away next 8 bytes
+ //
+
+ for (i = 0; i < 8; i ++)
+ {
+ if (!ReadCommandRegister(CardPtr,&ThrowAway)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Couldn't read parameter byte\n"));
+ break;
+ }
+ }
+ if (i != 8)
+ continue;
+
+ /* read EISA config reg - throw away byte for ISA and MCA */
+
+ if (!ReadCommandRegister(CardPtr,&EISAConfigReg)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Couldn't read parameter byte\n"));
+ continue;
+ }
+
+ if (!ReadCommandRegister(CardPtr,&TaggedQueueSupport)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Couldn't read parameter byte\n"));
+ continue;
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+ DebugPrint((1,"BLogicDetermineInstalled: Extended Setup info cmd failed\n"));
+ continue;
+ }
+
+ if (TaggedQueueSupport != 0) {
+ CardPtr->Flags |= TAGGED_QUEUING;
+ }
+
+ switch (CardPtr->BusType) {
+ case ISA_HBA:
+ if (ConfigInfo->AdapterInterfaceType != Isa)
+ continue;
+ break;
+
+ case EISA_HBA:
+
+ // EISA, VESA, and PCI HBAs all , reporting back as bus type
+ // EISA, will always reflect accurate edge\level info in
+ // in "EISAConfigReg" below - I checked with FW group on this
+
+ ConfigInfo->InterruptMode = EISAConfigReg & LEVEL_TRIG ? LevelSensitive : Latched;
+
+ if (ConfigInfo->AdapterInterfaceType == Eisa)
+ {
+ if (!(FindOurEISAId(CardPtr,ConfigInfo,baseIoAddress)))
+ {
+ FoundVesaCard = 1;
+ }
+ break;
+ }
+ else if (ConfigInfo->AdapterInterfaceType == Isa)
+ {
+ /* if we already reported this HBA as an EISA board */
+ /* don't double report. Otherwise, this must be a VESA */
+ /* board on an ISA-VESA motherboard. */
+
+ if (InittedEISABoards)
+ continue;
+ else
+ {
+ FoundVesaCard = 1;
+ break;
+ }
+ }
+ else if (ConfigInfo->AdapterInterfaceType == PCIBus)
+ break;
+
+ case MCA_HBA:
+ if (ConfigInfo->AdapterInterfaceType != MicroChannel)
+ continue;
+ break;
+
+ } /* end switch */
+
+ //
+ // turn off ISA-compatible I/O mapping on compliant PCI HBAs.
+ //
+
+ if (ConfigInfo->AdapterInterfaceType == PCIBus)
+ {
+ //
+ // Turn off ISA-compatible I/O mapping for this HBA
+ //
+
+ if (!WriteCommandRegister(CardPtr,AC_ISA_COMPATIBLE_SUPPORT)) {
+ DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
+ continue;
+ }
+ else if (!CheckInvalid(CardPtr)) {
+ DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
+ continue;
+ }
+ else{
+ ThrowAway = DISABLE_ISA_MAPPING;
+ if (!WriteCommandRegister(CardPtr,ThrowAway)){
+ DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
+ continue;
+ }
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+
+ // this cmd DOES NOT generate an interrupt - so
+ // just check for command complete!
+
+ if (!(ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)
+ & (IOP_SCSI_HBA_IDLE))) {
+ DebugPrint((1,"BLogicDetermineInstalled: ISA Compatible Support Mode cmd failed\n"));
+ continue;
+ }
+ }
+ } // turn off ISA- compatible I/O mapping on PCI-compliant 946C cards
+
+ //
+ // An adapter has been found. Set the base address in the device
+ // extension, and request another call.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Fill in the access array information.
+ //
+
+ if (!configProvided) {
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ AdapterAddresses[(CurrContextPtr->AdapterCount) - 1]);
+ }
+ (*ConfigInfo->AccessRanges)[0].RangeLength = 4;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+
+ return(FoundVesaCard ? RETURN_FOUND_VESA : SP_RETURN_FOUND);
+
+ } /* end if ((baseIoAddress) & (~0x2C)) == 0x10) */
+ } /* end adapter count loop */
+
+ //
+ // The entire table has been searched and no adapters have been found.
+ // There is no need to call again and the device base can now be freed.
+ // Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ CurrContextPtr->AdapterCount = 0;
+
+ return(SP_RETURN_NOT_FOUND);
+
+} // end BLogicDetermineInstalled()
+
+ULONG
+FindOurEISAId(
+ IN PCARD_STRUC CardPtr,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ PBASE_REGISTER baseIoAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if BusLogic HBA is an EISA or VESA board. Try to match both
+ our EISA ID and the base port of the board in question. If both match
+ this is an EISA board. If not, this must be our VESA board.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+
+ ConfigInfo - Supplies the known configuration information.
+
+ baseIoAddress - Base IO port address for this HBA
+
+Return Value:
+
+ Returns one if successful - means the card in question is an EISA card.
+ Returns zero if unsuccessful - means the card in question is a VESA card.
+
+--*/
+
+{
+ PEISA_ID eisaID;
+ ULONG eisaSlotNumber;
+ PVOID eisaAddress;
+ UCHAR Port;
+
+ //
+ // Clear any high order base address bits.
+ //
+
+ baseIoAddress = (PBASE_REGISTER)((ULONG) baseIoAddress & 0xFFF);
+
+ //
+ // Check to see if adapter EISA ID can be found
+ //
+
+ for (eisaSlotNumber= 1; eisaSlotNumber<MAXIMUM_EISA_SLOTS; eisaSlotNumber++)
+ {
+
+ //
+ // Get the system address for this card.
+ // The card uses I/O space.
+ //
+
+ eisaAddress = ScsiPortGetDeviceBase(CardPtr,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ TRUE);
+
+ eisaID =
+ (PEISA_ID)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE);
+
+ if ((ScsiPortReadPortUchar(&eisaID->BoardId[0]) == 0x0A) &&
+ (ScsiPortReadPortUchar(&eisaID->BoardId[1]) == 0xB3) &&
+ ((ScsiPortReadPortUchar(&eisaID->BoardId[2]) == 0x42) ||
+ (ScsiPortReadPortUchar(&eisaID->BoardId[2]) == 0x47)))
+ {
+
+ /* still need to look for IO port match because we could */
+ /* have VESA and EISA BusLogic cards in same machine */
+
+ Port = (ScsiPortReadPortUchar(&eisaID->IOPort[0]) & PORTMASK);
+
+ switch (Port) {
+ case 0:
+ if ((ULONG)baseIoAddress == 0x330)
+ {
+ DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
+ eisaSlotNumber,baseIoAddress));
+ return(1);
+ }
+ break;
+ case 1:
+ if ((ULONG)baseIoAddress == 0x334)
+ {
+ DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
+ eisaSlotNumber,baseIoAddress));
+ return(1);
+ }
+ break;
+ case 2:
+ if ((ULONG)baseIoAddress == 0x230)
+ {
+ DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
+ eisaSlotNumber,baseIoAddress));
+ return(1);
+ }
+ break;
+ case 3:
+ if ((ULONG)baseIoAddress == 0x234)
+ {
+ DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
+ eisaSlotNumber,baseIoAddress));
+ return(1);
+ }
+ break;
+ case 4:
+ if ((ULONG)baseIoAddress == 0x130)
+ {
+ DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
+ eisaSlotNumber,baseIoAddress));
+ return(1);
+ }
+ break;
+ case 5:
+ if ((ULONG)baseIoAddress == 0x134)
+ {
+ DebugPrint((1,"BusLogic: EISA Adapter found at slot %d,port %x \n",
+ eisaSlotNumber,baseIoAddress));
+ return(1);
+ }
+ break;
+ default:
+ break;
+ } /* end switch */
+
+ } /* end if found BusLogic ID */
+ } /* end for loop */
+
+ DebugPrint((1,"BusLogic: VESA Adapter found at port %x\n",baseIoAddress));
+ return(0);
+}
+
+BOOLEAN
+BLogicHwInitialize(
+ IN PCARD_STRUC CardPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a required entry point.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PNONCACHED_EXTENSION MailBoxArray =
+ CardPtr->MailBoxArray;
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+ UCHAR status;
+ ULONG i;
+ PDEV_STRUC DevStruc;
+ UCHAR TargID;
+ UCHAR Lun;
+
+ DebugPrint((2,"BLogicHwInitialize: Reset BusLogic HBA and SCSI bus\n"));
+
+ //
+ // Reset HBA.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_SOFT_RESET);
+
+ ScsiPortStallExecution(500*1000);
+
+ //
+ // Wait up to 500 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 500; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar(&CardPtr->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+ }
+
+ //
+ // Check if reset failed or succeeded.
+ //
+
+ if (!(status & IOP_SCSI_HBA_IDLE) || !(status & IOP_MAILBOX_INIT_REQUIRED))
+ {
+
+ DebugPrint((0, "BLogicHwInitialize: Soft reset failed.\n"));
+
+ //
+ // If the soft reset does not work, try a hard reset.
+ //
+
+ if (!BLogicResetBus(CardPtr, 0)) {
+ DebugPrint((1,"BLogicHwInitialize: Reset SCSI bus failed\n"));
+ return FALSE;
+ }
+
+ //
+ // Inform the port driver that the bus has been reset.
+ //
+
+
+ ScsiPortNotification(ResetDetected, CardPtr, 0);
+
+ DebugPrint((1,"BLogicHwInitialize: Reset completed\n"));
+
+ }
+ else /* soft reset succeeded */
+ {
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(CardPtr,
+ CardPtr->BusNum,
+ (UCHAR) -1,
+ (UCHAR) -1,
+ SRB_STATUS_BUS_RESET);
+ //
+ // Reinitialize Active CCBS pointer and counter in LUN extensions
+ //
+
+ for (TargID= 0; TargID < 8; TargID++)
+ for (Lun = 0; Lun < 8; Lun++)
+ {
+ if (DevStruc= (PDEV_STRUC) (ScsiPortGetLogicalUnit(CardPtr,0,TargID,Lun)))
+ {
+ DevStruc->CurrentCCB = 0;
+ DevStruc->NumActive = 0;
+ }
+ }
+
+ }
+
+ //
+ // Zero out mailboxes.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+
+ mailboxIn = &MailBoxArray->Mbi[i];
+ mailboxOut = &MailBoxArray->Mbo[i];
+
+ mailboxOut->Command = mailboxIn->Status = 0;
+ }
+
+ CardPtr->StartMBO = (PMBO)(&MailBoxArray->Mbo);
+ CardPtr->CurrMBO = (PMBO)(&MailBoxArray->Mbo);
+ CardPtr->LastMBO = ((PMBO)(&MailBoxArray->Mbo) + (MB_COUNT - 1));
+ CardPtr->StartMBI =(PMBI)( &MailBoxArray->Mbi);
+ CardPtr->CurrMBI = (PMBI)(&MailBoxArray->Mbi);
+ CardPtr->LastMBI = ((PMBI)(&MailBoxArray->Mbi) + (MB_COUNT - 1));
+
+
+ DebugPrint((3,"BLogicHwInitialize: Initialize mailbox\n"));
+
+ if (!WriteCommandRegister(CardPtr,AC_MBOX_EXTENDED_INIT)) {
+ DebugPrint((1,"BLogicHWInitialize: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(CardPtr,MB_COUNT)) {
+ DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+ if (!WriteCommandRegister(CardPtr,
+ ((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte0)) {
+ DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+ if (!WriteCommandRegister(CardPtr,
+ ((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte1)) {
+ DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+ if (!WriteCommandRegister(CardPtr,
+ ((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte2)) {
+ DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+ if (!WriteCommandRegister(CardPtr,
+ ((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte3)) {
+ DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+ if (!FinishHBACmd(CardPtr)) {
+ DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+
+
+ //
+ // Override default setting for bus on time. This makes floppy
+ // drives work better with this adapter.
+ //
+
+ if (!WriteCommandRegister(CardPtr, AC_SET_BUS_ON_TIME)) {
+
+ DebugPrint((1,"BlogicHWInitialize:Can't set bus on time\n"));
+ return FALSE;
+
+ } else if (!WriteCommandRegister(CardPtr, 0x05)) {
+
+ DebugPrint((1,"BlogicHWInitialize:Can't set bus on time\n"));
+ return FALSE;
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+ DebugPrint((1,"BLogicHWInitialize: Set BUS On time failed\n"));
+ return FALSE;
+ }
+
+ /* turn on wide support if available */
+ if (CardPtr->Flags & OS_SUPPORTS_WIDE)
+ {
+ // DebugPrint((0,"BLogicHwInitialize: about to send wide cmd\n"));
+
+ if (!WriteCommandRegister(CardPtr, AC_WIDE_SUPPORT)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ }
+ else if (!CheckInvalid(CardPtr)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ }
+ else if (!WriteCommandRegister(CardPtr, 0x01)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ }
+ if (!FinishHBACmd(CardPtr)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ }
+ else {
+ CardPtr->Flags |= WIDE_ENABLED;
+ }
+ } /* end if OS_SUPPORTS_WIDE */
+
+ return TRUE;
+
+} // end BLogicHwInitialize()
+
+
+BOOLEAN
+BLogicStartIo(
+ IN PCARD_STRUC CardPtr,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel. The mailboxes are scanned for an empty one and
+ the CCB is written to it. Then the doorbell is rung and the
+ OS port driver is notified that the adapter can take
+ another request, if any are available.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PNONCACHED_EXTENSION MailBoxArray =
+ CardPtr->MailBoxArray;
+ PCCB ccb;
+ PDEV_STRUC DevStruc;
+ PCCB ActiveCCB;
+ ULONG i = 0;
+ UCHAR MaxActive = 0;
+ UCHAR j;
+
+ DebugPrint((3,"BLogicStartIo: Enter routine\n"));
+
+ if (CardPtr->Flags & REINIT_REQUIRED)
+ {
+ if (!ReInitializeHBA(CardPtr,Srb->PathId))
+ {
+ DebugPrint((1,"BLogicStartIo: HBA reinitialization failed\n"));
+ return FALSE;
+ }
+ CardPtr->Flags &= (~REINIT_REQUIRED);
+ }
+
+ //
+ // Check if command is an ABORT request.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Get CCB to abort.
+ //
+
+ ccb = Srb->NextSrb->SrbExtension;
+ MaxActive =(Srb->NextSrb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ?
+ MAXACTIVE_TAGGED : MAXACTIVE;
+
+ //
+ // Verify that CCB to abort is still outstanding.
+ //
+
+ DevStruc =
+ ScsiPortGetLogicalUnit(CardPtr,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ for (j=DevStruc->NumActive, ActiveCCB = DevStruc->CurrentCCB;
+ j > 0; j--)
+ {
+ if (ActiveCCB != ccb)
+ ActiveCCB = ActiveCCB->NxtActiveCCB;
+ else
+ break;
+
+ }
+
+ if (j == 0)
+ {
+
+ DebugPrint((1, "BLogicStartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification(RequestComplete,
+ CardPtr,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+ if (DevStruc->NumActive < MaxActive)
+ ScsiPortNotification(NextLuRequest,CardPtr,Srb->PathId,
+ Srb->TargetId,Srb->Lun);
+ else
+ ScsiPortNotification(NextRequest,CardPtr,NULL);
+ return TRUE;
+ }
+
+
+ //
+ // Set abort SRB for completion.
+ //
+
+ ccb->AbortSrb = Srb;
+ SendCCB(Srb,CardPtr,DevStruc);
+
+ if (DevStruc->NumActive < MaxActive)
+ ScsiPortNotification(NextLuRequest,CardPtr,Srb->PathId,
+ Srb->TargetId,Srb->Lun);
+ else
+ ScsiPortNotification(NextRequest,CardPtr,NULL);
+
+ return TRUE;
+
+ } /* end ABORT request handling */
+
+
+ ccb = Srb->SrbExtension;
+
+ ccb->SrbAddress = Srb; /* Save SRB back ptr in CCB */
+ MaxActive = (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ?
+ MAXACTIVE_TAGGED : MAXACTIVE;
+
+ DevStruc = ScsiPortGetLogicalUnit(CardPtr,Srb->PathId,Srb->TargetId,
+ Srb->Lun);
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Get logical unit extension.
+ //
+
+
+ DevStruc->NumActive++;
+
+ //
+ // Build CCB.
+ //
+
+ BuildCcb(CardPtr, Srb);
+ SendCCB(Srb,CardPtr,DevStruc);
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset Adapter and SCSI bus.
+ //
+
+ DebugPrint((1, "BLogicStartIo: Reset bus request received\n"));
+
+ if (!BLogicResetBus(CardPtr,Srb->PathId)) {
+ DebugPrint((1,"BLogicStartIo: Reset bus failed\n"));
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ ScsiPortNotification(RequestComplete,
+ CardPtr,
+ Srb);
+ break;
+
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ DevStruc->NumActive++;
+
+ ccb->OperationCode = RESET_COMMAND;
+ ccb->TargID = Srb->TargetId;
+ ccb->Lun = Srb->Lun;
+
+ SendCCB(Srb,CardPtr,DevStruc);
+
+ ScsiPortNotification(RequestComplete,
+ CardPtr,
+ Srb);
+
+ break;
+
+ //
+ // Drop through to default.
+ //
+
+ default:
+
+ //
+ // Set error, complete request
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,CardPtr,Srb);
+
+ } // end switch
+
+ //
+ // Adapter ready for next request.
+ //
+
+ if (DevStruc->NumActive < MaxActive)
+ ScsiPortNotification(NextLuRequest,CardPtr,Srb->PathId,
+ Srb->TargetId,Srb->Lun);
+ else
+ ScsiPortNotification(NextRequest,CardPtr,NULL);
+
+ return TRUE;
+
+
+} // end BLogicStartIo()
+
+
+BOOLEAN
+BLogicInterrupt(
+ IN PCARD_STRUC CardPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the CCB is
+ retrieved to complete the request.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PNONCACHED_EXTENSION MailBoxArray =
+ CardPtr->MailBoxArray;
+ PCCB ccb;
+ PSCSI_REQUEST_BLOCK srb,abortsrb;
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+ PMBI mailboxIn;
+ ULONG physicalCcb;
+ PDEV_STRUC DevStruc;
+ UCHAR mbox_compcode;
+ UCHAR InterruptFlags;
+ UCHAR MaxActive=0;
+ UCHAR TargID;
+ UCHAR Lun;
+
+ InterruptFlags = ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister);
+
+ DebugPrint((3,"BLogicInterrupt: Interrupt flags %x\n", InterruptFlags));
+
+ if (!(InterruptFlags & IOP_ANY_INTERRUPT)) {
+ DebugPrint((4,"BLogicInterrupt: Not our interrupt!\n"));
+ return FALSE;
+ }
+ else
+ /* Clear interrupt on adapter. */
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ //
+ // Determine cause of interrupt.
+ //
+
+ if (InterruptFlags & IOP_COMMAND_COMPLETE) {
+
+ //
+ // Adapter command completed.
+ //
+
+ DebugPrint((2,"BLogicInterrupt: Adapter Command complete\n"));
+ DebugPrint((3,"BLogicInterrupt: Status %x\n",
+ ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)));
+
+ return TRUE;
+
+ }
+ else if (InterruptFlags & IOP_SCSI_RESET_DETECTED) {
+
+ DebugPrint((1,"BLogicInterrupt: SCSI Reset detected\n"));
+ //
+ // Notify of reset.
+ //
+
+ //
+ // Reset HBA because firmware may be in confused state with
+ // respect to outstanding CCBs.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_SOFT_RESET);
+
+ //
+ // Notify OS of SCSI bus reset.
+ //
+
+ ScsiPortNotification(ResetDetected,CardPtr,NULL);
+
+ // Complete all active requests for specified unit
+
+ ScsiPortCompleteRequest(CardPtr,
+ (UCHAR) 0,
+ (UCHAR) -1,
+ (UCHAR) -1,
+ SRB_STATUS_BUS_RESET);
+
+ //
+ // Reinitialize Active CCBS pointer and counter in LUN extensions
+ //
+
+ for (TargID= 0; TargID < 8; TargID++)
+ for (Lun = 0; Lun < 8; Lun++)
+ {
+ if (DevStruc=ScsiPortGetLogicalUnit(CardPtr,0,TargID,Lun))
+ {
+ DevStruc->CurrentCCB = 0;
+ DevStruc->NumActive = 0;
+ }
+ }
+
+ //
+ // Set flag indicating HBA reinitialization will be required before
+ // any new requests can be serviced (due to soft reset above).
+ //
+
+ CardPtr->Flags |= REINIT_REQUIRED;
+ }
+
+ else if (InterruptFlags & IOP_MBI_FULL) {
+ DebugPrint((3,"BLogicInterrupt: MBI Full\n"));
+
+ while (mailboxIn = DoneMbox(CardPtr))
+ {
+
+ physicalCcb = mailboxIn->Address;
+ DebugPrint((3, "BLogicInterrupt: Physical CCB %lx\n", physicalCcb));
+
+ /* Check if physical CCB is zero. ( to cover for hardware errs) */
+
+ if (!physicalCcb) {
+
+ DebugPrint((1,"BLogicInterrupt: Physical CCB address is 0\n"));
+ return TRUE;
+ }
+
+ //
+ // Convert Physical CCB to Virtual.
+ //
+
+ ccb = ScsiPortGetVirtualAddress(CardPtr, ScsiPortConvertUlongToPhysicalAddress(physicalCcb));
+ DebugPrint((3, "BLogicInterrupt: Virtual CCB %lx\n", ccb));
+
+ //
+ // Make sure the virtual address was found.
+ //
+
+ if (ccb == NULL) {
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ CardPtr,
+ NULL,
+ 0,
+ CardPtr->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 5 << 8
+ );
+
+ return(TRUE);
+
+ }
+
+ mbox_compcode = mailboxIn->Status;
+ mailboxIn->Status = MBI_FREE; /* free this In Mailbox */
+
+ //
+ // Get SRB from CCB.
+ //
+
+ srb = ccb->SrbAddress;
+
+ //
+ // Get logical unit extension.
+ //
+
+ DevStruc =
+ ScsiPortGetLogicalUnit(CardPtr,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun);
+
+ if (mbox_compcode == MBI_NOT_FOUND) {
+ DebugPrint((1, "BLogicInterrupt: aborted CCB not found %lx\n", ccb));
+ continue;
+ }
+
+ if (!AdjustCCBqueue (ccb,DevStruc)) {
+
+ //
+ // We have no record of the CCB returned by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ CardPtr,
+ NULL,
+ 0,
+ CardPtr->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (7 << 8) | mbox_compcode
+ );
+
+ continue;
+
+ }
+
+ srb->ScsiStatus = ccb->TargetStatus;
+
+ DebugPrint((2, "BLogicInterrupt: SCSI Status %x\n", srb->ScsiStatus));
+ DebugPrint((2, "BLogicInterrupt: Adapter Status %x\n", ccb->HostStatus));
+
+ //
+ // Check MBI status.
+ //
+
+ switch (mbox_compcode) {
+
+ case MBI_SUCCESS:
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ ASSERT(DevStruc->CurrentCCB);
+ break;
+
+ case MBI_ABORT:
+
+ DebugPrint((1, "BLogicInterrupt: CCB aborted\n"));
+
+ srb->SrbStatus = SRB_STATUS_ABORTED;
+
+ //
+ // Get the abort SRB (requested the abort) from CCB.
+ //
+
+ abortsrb = ccb->AbortSrb;
+
+ //
+ // Call notification routine for the aborted SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ CardPtr,
+ srb);
+
+ //
+ // Set status for completing abort request itself.
+ //
+
+ abortsrb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb = abortsrb;
+ break;
+
+ case MBI_ERROR:
+
+ DebugPrint((2, "BLogicInterrupt: Error occurred\n"));
+
+ srb->SrbStatus = MapError(CardPtr, srb, ccb);
+ if (ccb->TargetStatus == 2)
+ if (ccb->RequestSenseLength != 1)
+ srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+
+ break;
+
+ default:
+
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(
+ CardPtr,
+ NULL,
+ 0,
+ CardPtr->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (1 << 8) | mbox_compcode
+ );
+
+ DebugPrint((1, "BLogicInterrupt: Unrecognized mailbox status\n"));
+
+ continue;
+
+ } // end switch on mailbox-in completion status
+
+ DevStruc->NumActive--;
+ MaxActive = (srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) ?
+ MAXACTIVE_TAGGED : MAXACTIVE;
+
+ ScsiPortNotification(RequestComplete,CardPtr,srb);
+
+ //
+ // Notify that we are ready for another request
+ //
+
+ if (DevStruc->NumActive == (MaxActive - 1))
+ ScsiPortNotification(NextLuRequest,CardPtr,srb->PathId,
+ srb->TargetId,srb->Lun);
+ else /* assume we already asked for req for this LUN */
+ ScsiPortNotification(NextRequest,CardPtr,NULL);
+
+ } /* while done MBI */
+
+ } /* end if MBI full */
+ else
+ { /* unexpected interrupt status */
+ ScsiPortLogError(
+ CardPtr,
+ NULL,
+ 0,
+ CardPtr->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (8 << 8)
+ );
+
+ DebugPrint((1, "BLogicInterrupt: Spurious Interrupt\n"));
+
+ }
+
+ return TRUE;
+} // end BLogicInterrupt()
+
+
+VOID
+BuildCcb(
+ IN PCARD_STRUC CardPtr,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build CCB
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PCCB ccb = Srb->SrbExtension;
+ UCHAR *pchar;
+ USHORT i;
+ ULONG physReqSensePtr;
+ ULONG length;
+
+ DebugPrint((3,"BuildCcb: Enter routine\n"));
+
+ // zero-fill the CCB
+
+ pchar = (UCHAR *) ccb;
+ for (i=0; i < sizeof(CCB); i++)
+ *pchar++= 0;
+
+ ccb->SrbAddress = Srb; /* Save SRB back ptr in CCB */
+
+ //
+ // Set CCB Operation Code.
+ //
+
+ if (Srb->DataTransferLength > 0)
+ ccb->OperationCode = SCATTER_GATHER_COMMAND;
+ else
+ ccb->OperationCode = SCSI_INITIATOR_COMMAND;
+ //
+ // Set target id and LUN.
+ //
+
+ ccb->TargID = Srb->TargetId;
+ ccb->Lun = Srb->Lun;
+
+
+ if ((CardPtr->Flags & TAGGED_QUEUING) &&
+ (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE))
+ {
+ if (CardPtr->Flags & WIDE_ENABLED)
+ ccb->ControlByte |= ENABLE_TQ;
+ else
+ ccb->Lun |= ENABLE_TQ;
+
+ switch (Srb->QueueAction) {
+
+ case ORDERED_TAG:
+ ccb->Lun |= ORDERED;
+ break;
+ case SIMPLE_TAG:
+ ccb->Lun |= SIMPLE;
+ break;
+ case HEAD_OF_QUEUE:
+ ccb->Lun |= QUEUEHEAD;
+ break;
+ } /* end switch */
+ }
+
+ //
+ // Set transfer direction bit.
+ //
+
+ switch (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) {
+ case SRB_FLAGS_DATA_OUT:
+ ccb->ControlByte |= CCB_DATA_XFER_OUT;
+ break;
+
+ case SRB_FLAGS_DATA_IN:
+ ccb->ControlByte |= CCB_DATA_XFER_IN;
+ break;
+
+ case SRB_FLAGS_NO_DATA_TRANSFER:
+ ccb->ControlByte |= CCB_DATA_XFER_IN | CCB_DATA_XFER_OUT;
+ break;
+ }
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) &&
+ Srb->SenseInfoBufferLength != 0) {
+
+ ccb->RequestSenseLength = Srb->SenseInfoBufferLength;
+ physReqSensePtr = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(CardPtr, Srb,
+ Srb->SenseInfoBuffer, &length));
+
+ ccb->SensePointer = physReqSensePtr;
+ }
+ else
+
+
+ //
+ // 01h disables auto request sense.
+ //
+
+ ccb->RequestSenseLength = 1;
+
+
+ //
+ // Set CDB length and copy to CCB.
+ //
+
+ ccb->CdbLength = (UCHAR)Srb->CdbLength;
+
+ ScsiPortMoveMemory(ccb->Cdb, Srb->Cdb, ccb->CdbLength);
+
+
+ //
+ // Build SDL in CCB if data transfer.
+ //
+
+ if (Srb->DataTransferLength > 0) {
+ BuildSdl(CardPtr, Srb);
+ }
+
+ //
+ // Move -1 to Target Status to indicate
+ // CCB has not completed.
+ //
+
+ ccb->TargetStatus = 0xff;
+
+ return;
+
+} // end BuildCcb()
+
+
+VOID
+BuildSdl(
+ IN PCARD_STRUC CardPtr,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list for the CCB.
+
+Arguments:
+
+ CardPtr
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PCCB ccb = Srb->SrbExtension;
+ PSDL sdl = &ccb->Sdl;
+ PSGD sgd;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG i = 0;
+
+ DebugPrint((3,"BuildSdl: Enter routine\n"));
+
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(CardPtr, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SDL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SDL));
+
+ sgd = sdl->Sgd;
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+
+ DebugPrint((3, "BuildSdl: Data buffer %lx\n", dataPointer));
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(CardPtr,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "BuildSdl: Physical address %lx\n", physicalAddress));
+ DebugPrint((3, "BuildSdl: Data length %lx\n", length));
+ DebugPrint((3, "BuildSdl: Bytes left %lx\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ sgd->Length = length;
+ sgd->Address = physicalAddress;
+ sgd++;
+ i++;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+
+ } while (bytesLeft);
+
+ //
+ // Write Scatter/Gather Descriptor List length to CCB.
+ //
+
+ ccb->DataLength = i * sizeof(SGD);
+
+ DebugPrint((3,"BuildSdl: S/G list length is %d\n", ccb->DataLength));
+
+ if (ccb->DataLength > 8)
+ DebugPrint((3,"BuildSdl: Multiple elements in S/G list"));
+
+ //
+ // Write SDL address to CCB.
+ //
+
+ ccb->DataPointer = (PVOID) physicalSdl;
+
+ DebugPrint((3,"BuildSdl: SDL address is %lx\n", sdl));
+
+ DebugPrint((3,"BuildSdl: CCB address is %lx\n", ccb));
+
+ return;
+
+} // end BuildSdl()
+
+
+BOOLEAN
+BLogicResetBus(
+ IN PCARD_STRUC CardPtr,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Reset BusLogic SCSI adapter and SCSI bus.
+ Initialize adapter mailbox.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ UCHAR TargID,Lun;
+ PDEV_STRUC DevStruc;
+
+ DebugPrint((2,"BLogicResetBus: Reset BusLogic HBA and SCSI bus\n"));
+
+ if (!ResetBus(CardPtr,PathId)) {
+ DebugPrint((1,"BLogicResetBus: Reset bus failed\n"));
+ return FALSE;
+ }
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(CardPtr,
+ (UCHAR) PathId,
+ (UCHAR) -1,
+ (UCHAR) -1,
+ SRB_STATUS_BUS_RESET);
+ //
+ // Reinitialize Active CCBS pointer and counter in LUN extensions
+ //
+
+ for (TargID= 0; TargID < 8; TargID++)
+ for (Lun = 0; Lun < 8; Lun++)
+ {
+ if (DevStruc=ScsiPortGetLogicalUnit(CardPtr,0,TargID,Lun))
+ {
+ DevStruc->CurrentCCB = 0;
+ DevStruc->NumActive = 0;
+ }
+ }
+
+ return TRUE;
+
+} // end BLogicResetBus()
+
+
+BOOLEAN
+ResetBus(
+ IN PCARD_STRUC CardPtr,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Reset BusLogic SCSI adapter and SCSI bus.
+ Initialize adapter mailbox.
+ Don't do callback on outstanding SRBs
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ PNONCACHED_EXTENSION MailBoxArray =
+ CardPtr->MailBoxArray;
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+ ULONG i;
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+ UCHAR status;
+
+ DebugPrint((2,"ResetBus: Reset BusLogic HBA and SCSI bus\n"));
+
+ //
+ // Reset SCSI chip.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
+
+ // Separated out the previously-removed routine ReInitializeHBA
+ // because it is now called by StartIO as well
+
+ if (!ReInitializeHBA(CardPtr,PathId)) {
+ DebugPrint((1,"ResetBus: Reset bus failed\n"));
+ return FALSE;
+ }
+ return TRUE;
+
+} // end ResetBus()
+
+
+BOOLEAN
+ReInitializeHBA(
+ IN PCARD_STRUC CardPtr,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Wait for HBA to reinitialize.
+ Initialize adapter mailbox.
+
+Arguments:
+
+ CardPtr - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ PNONCACHED_EXTENSION MailBoxArray =
+ CardPtr->MailBoxArray;
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+ ULONG i;
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+ UCHAR status;
+
+
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 500 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 500; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar(&CardPtr->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ if (!(status & IOP_SCSI_HBA_IDLE)) {
+ return(FALSE);
+ }
+
+ //
+ // Zero out mailboxes.
+ //
+
+ for (i=0,mailboxIn = MailBoxArray->Mbi,mailboxOut = MailBoxArray->Mbo;
+ i<MB_COUNT; i++, mailboxIn++,mailboxOut++) {
+ mailboxOut->Command = mailboxIn->Status = 0;
+ }
+
+ CardPtr->StartMBO = (PMBO)(&MailBoxArray->Mbo);
+ CardPtr->CurrMBO = (PMBO)(&MailBoxArray->Mbo);
+ CardPtr->LastMBO = ((PMBO)(&MailBoxArray->Mbo) + (MB_COUNT - 1));
+ CardPtr->StartMBI =(PMBI)( &MailBoxArray->Mbi);
+ CardPtr->CurrMBI = (PMBI)(&MailBoxArray->Mbi);
+ CardPtr->LastMBI = ((PMBI)(&MailBoxArray->Mbi) + (MB_COUNT - 1));
+
+
+ DebugPrint((3,"ReInitializeHBA: Initialize mailbox\n"));
+
+ if (!WriteCommandRegister(CardPtr,AC_MBOX_EXTENDED_INIT)) {
+ DebugPrint((1,"ReInitializeHBA: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(CardPtr,MB_COUNT)) {
+ DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+
+ if (!WriteCommandRegister(CardPtr,
+ ((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte0)) {
+ DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+
+ if (!WriteCommandRegister(CardPtr,
+ ((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte1)) {
+ DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+
+ if (!WriteCommandRegister(CardPtr,
+ ((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte2)) {
+ DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+
+ if (!WriteCommandRegister(CardPtr,
+ ((PFOUR_BYTE)&MailBoxArray->MailboxPA)->Byte3)) {
+ DebugPrint((1,"ReInitializeHBA: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+
+ if (!FinishHBACmd(CardPtr)) {
+ DebugPrint((1,"BLogicHWInitialize: Extended InitMboxes failed\n"));
+ return FALSE;
+ }
+
+ /* turn on wide support if available */
+ if (CardPtr->Flags & OS_SUPPORTS_WIDE)
+ {
+
+ // DebugPrint((0,"ReInitializeHBA: about to send wide cmd\n"));
+
+ if (!WriteCommandRegister(CardPtr, AC_WIDE_SUPPORT)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ }
+ else if (!CheckInvalid(CardPtr)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ }
+ else if (!WriteCommandRegister(CardPtr, 0x01)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ }
+ if (!FinishHBACmd(CardPtr)) {
+ CardPtr->Flags &= ~WIDE_ENABLED;
+ }
+ else {
+ CardPtr->Flags |= WIDE_ENABLED;
+ }
+ } /* end if OS_SUPPORTS_WIDE */
+
+ return TRUE;
+
+} // end ReInitializeHBA()
+
+UCHAR
+MapError(
+ IN PCARD_STRUC CardPtr,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ Translate BusLogic error to SRB error, and log an error if necessary.
+
+Arguments:
+
+ CardPtr - The hardware device extension.
+
+ Srb - The failing Srb.
+
+ Ccb - Command Control Block contains error.
+
+Return Value:
+
+ SRB Error
+
+--*/
+
+{
+ UCHAR status;
+ ULONG logError = 0;
+
+ switch (Ccb->HostStatus) {
+
+ case CCB_COMPLETE:
+ return SRB_STATUS_ERROR;
+
+ case CCB_SELECTION_TIMEOUT:
+ return SRB_STATUS_SELECTION_TIMEOUT;
+
+ case CCB_DATA_OVER_UNDER_RUN:
+ status = SRB_STATUS_DATA_OVERRUN;
+
+ //
+ // Don't log the protocol error anymore. it floods the system
+ // for underruns as well
+ //
+ // logError = SP_PROTOCOL_ERROR;
+ //
+
+ break;
+
+ case CCB_UNEXPECTED_BUS_FREE:
+ status = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ logError = SP_UNEXPECTED_DISCONNECT;
+ break;
+
+ case CCB_PHASE_SEQUENCE_FAIL:
+ case CCB_INVALID_DIRECTION:
+ status = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ logError = SP_PROTOCOL_ERROR;
+ break;
+
+ case CCB_BAD_MBO_COMMAND:
+ case CCB_INVALID_OP_CODE:
+ case CCB_BAD_LINKED_LUN:
+ case CCB_DUPLICATE_CCB:
+ case CCB_INVALID_CCB:
+ status = SRB_STATUS_INVALID_REQUEST;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+
+ default:
+ status = SRB_STATUS_ERROR;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+ }
+
+ if(logError) {
+
+ ScsiPortLogError(
+ CardPtr,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ (2 << 8) | Ccb->HostStatus
+ );
+
+ }
+
+ return(status);
+
+} // end MapError()
+
+
+BOOLEAN
+ReadCommandRegister(
+ IN PCARD_STRUC CardPtr,
+ OUT PUCHAR DataByte
+ )
+
+/*++
+
+Routine Description:
+
+ Read command register.
+
+Arguments:
+
+ DeviceExtesion - Pointer to adapder extension
+ DataByte - Byte read from register
+
+Return Value:
+
+ TRUE if command register read.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+ ULONG i;
+
+ //
+ // Wait up to 500 microseconds for adapter to be ready.
+ //
+
+ for (i=0; i<500; i++) {
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_DATA_IN_PORT_FULL) {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+
+ } else {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i==500) {
+
+ ScsiPortLogError(
+ CardPtr,
+ NULL,
+ 0,
+ CardPtr->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 8
+ );
+
+ DebugPrint((1, "BLogic:ReadCommandRegister: Read command timed out\n"));
+ return FALSE;
+ }
+
+ *DataByte = ScsiPortReadPortUchar(&baseIoAddress->CommandRegister);
+
+ return TRUE;
+
+} // end ReadCommandRegister()
+
+
+BOOLEAN
+WriteCommandRegister(
+ IN PCARD_STRUC CardPtr,
+ IN UCHAR AdapterCommand
+ )
+
+/*++
+
+Routine Description:
+
+ Write operation code to command register.
+
+Arguments:
+
+ DeviceExtesion - Pointer to adapter extension
+ AdapterCommand - Value to be written to register
+
+Return Value:
+
+ TRUE if command sent.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+ ULONG i;
+
+ //
+ // Wait up to 500 microseconds for adapter to be ready.
+ //
+
+ for (i=0; i<500; i++) {
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_COMMAND_DATA_OUT_FULL) {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+
+ } else {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+ }
+ }
+
+ if (i==500) {
+
+ ScsiPortLogError(
+ CardPtr,
+ NULL,
+ 0,
+ CardPtr->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4 << 8
+ );
+
+ DebugPrint((1, "BLogic:WriteCommandRegister: Write command timed out\n"));
+ return FALSE;
+ }
+
+ ScsiPortWritePortUchar(&baseIoAddress->CommandRegister, AdapterCommand);
+
+ return TRUE;
+
+} // end WriteCommandRegister()
+
+
+BOOLEAN
+FinishHBACmd(
+ IN PCARD_STRUC CardPtr
+ )
+
+/*++
+
+Routine Description:
+
+ Wait for command complete interrupt, clear interrupt, chk cmd status.
+
+Arguments:
+
+ CardPtr - Pointer to adapter extension
+
+Return Value:
+
+ TRUE if command completed successfully.
+ FALSE if timed out waiting for adapter or invalid command.
+
+--*/
+
+{
+
+ ULONG i;
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+
+ for (i=0; i<500; i++) {
+
+ if (!((ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) &
+ (IOP_COMMAND_COMPLETE | IOP_ANY_INTERRUPT))==
+ (IOP_COMMAND_COMPLETE | IOP_ANY_INTERRUPT))) {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+
+ } else {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+ }
+ }
+
+ if (i==500) {
+
+ DebugPrint((1, "BLogic:FinishHBACmd: Wait for CmdCmplt & AnyIntr failed\n"));
+ return FALSE;
+ }
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,IOP_INTERRUPT_RESET);
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ (IOP_INVALID_COMMAND)) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+} // end FinishHBACmd()
+
+
+BOOLEAN
+CheckInvalid(
+ IN PCARD_STRUC CardPtr
+ )
+
+/*++
+
+Routine Description:
+
+ Read status register to check for invalid command.
+
+Arguments:
+
+ DeviceExtesion - Pointer to adapder extension
+ DataByte - Byte read from register
+
+Return Value:
+
+ FALSE if invalid command bit on or timed out waiting for adapter.
+ TRUE if everything's o.k.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = CardPtr->BaseIoAddress;
+ ULONG i;
+
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 500 microseconds for adapter to be ready.
+ //
+
+ for (i=0; i<500; i++) {
+ if (ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) &
+ IOP_COMMAND_COMPLETE) {
+ //
+ // Adapter command complete. Break out of loop.
+ //
+
+ break;
+
+ } else {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i==500) {
+ // if command not complete, must not be invalid
+ return TRUE;
+ }
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_INVALID_COMMAND)
+ return FALSE;
+ else
+ return TRUE;
+
+} // end CheckInvalid()
+
+
+
+BOOLEAN
+SendCCB(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCARD_STRUC CardPtr,
+ IN PDEV_STRUC DevStruc
+ )
+
+/*++
+
+Routine Description:
+
+ Finds empty outgoing Mbox, stuffs CCB into it and sends start command.
+
+Arguments:
+
+ CardPtr - Pointer to adapter extension
+ Srb - Pointer to SCSI Request Block
+ DevStruc - Pointer to device (TAR/LUN) structure
+
+Return Value:
+
+ TRUE if command completed successfully.
+
+
+--*/
+
+{
+ PMBO mboxOut;
+ ULONG physicalCCB;
+ PCCB ccb;
+ ULONG length;
+ USHORT i;
+
+ while (1) /* wait for free mbox out */
+ {
+ for (i=0, mboxOut = CardPtr->CurrMBO ; i< MB_COUNT; i++,mboxOut++)
+ { /* look for an open slot */
+
+ if (mboxOut > CardPtr->LastMBO)
+ mboxOut = CardPtr->StartMBO;
+
+ if (mboxOut->Command == MBO_FREE)
+ {
+
+ /* Insert Phys addr of CCB into MBO */
+
+ if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND)
+ ccb = (PCCB)(Srb->SrbExtension);
+ else
+ ccb = (PCCB)(Srb->NextSrb->SrbExtension);
+
+ physicalCCB = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(CardPtr, NULL, ccb, &length));
+
+ //
+ // Assume physical address is contiguous for size of CCB.
+ //
+
+ ASSERT(length >= sizeof(CCB));
+ mboxOut->Address = physicalCCB;
+
+ if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND) {
+ /* insert this SRB into active queue for this device */
+
+ ccb->NxtActiveCCB = DevStruc->CurrentCCB;
+ DevStruc->CurrentCCB = ccb;
+ mboxOut->Command = MBO_START;
+ }
+ else
+ mboxOut->Command = MBO_ABORT;
+
+ CardPtr->CurrMBO = mboxOut + 1;
+
+ if (!WriteCommandRegister(CardPtr,AC_START_SCSI_COMMAND)) {
+ DebugPrint((1,"BLogicStartIo: Can't write command to adapter\n"));
+ }
+
+ return TRUE;
+
+ } /* end for found a free MBO */
+ } /* end for 0 to mbox count */
+ } /* end while forever */
+
+} /* end SendCCB() */
+
+
+PMBI
+DoneMbox(
+ IN PCARD_STRUC CardPtr
+ )
+
+/*++
+
+Routine Description:
+
+ Finds Full incoming Mbox
+
+Arguments:
+
+ CardPtr - Pointer to adapter extension
+
+Return Value:
+
+ Pointer to full MBI if full found, FALSE if not
+
+--*/
+
+{
+ register PMBI mboxp;
+ int i;
+
+ mboxp = CardPtr->CurrMBI;
+
+ for (i = 0; i < MB_COUNT; i++, mboxp++)
+ {
+ if (mboxp > CardPtr->LastMBI)
+ mboxp = CardPtr->StartMBI;
+
+ if (mboxp->Status != MBI_FREE)
+ {
+ CardPtr->CurrMBI = mboxp + 1;
+ return (mboxp);
+ }
+
+ }
+ return ((PMBI) NULL);
+} /* end DoneMbox() */
+
+
+BOOLEAN
+AdjustCCBqueue(
+ PCCB ccbp,
+ IN PDEV_STRUC devptr
+ )
+/*++
+
+Routine Description:
+
+ Removes newly-completed CCB from outstanding CCB queue for a given
+ device.
+
+Arguments:
+
+ ccbp - Pointer to the completed CCB
+ devptr - Pointer to device (TAR/LUN) structure
+
+Return Value:
+
+ TRUE if matching CCB was found in active queue
+ FALSE if no match could be found
+
+--*/
+{
+ PCCB tempCCB = devptr->CurrentCCB; /* ptr to head of active CCBS */
+
+ if (tempCCB == 0)
+ {
+ return FALSE;
+ }
+
+ if (ccbp == tempCCB) /* match with head of active CCB queue */
+ {
+ devptr->CurrentCCB = tempCCB->NxtActiveCCB;
+ ccbp->NxtActiveCCB = (PCCB) 0;
+ return TRUE;
+
+ }
+
+ while (tempCCB->NxtActiveCCB != 0 )
+ {
+ if (ccbp == tempCCB->NxtActiveCCB)
+ {
+ tempCCB->NxtActiveCCB = ccbp->NxtActiveCCB;
+ ccbp->NxtActiveCCB = (PCCB) 0;
+ return TRUE;
+ }
+
+ tempCCB = tempCCB->NxtActiveCCB;
+ }
+
+ return FALSE; /* no match found */
+
+} /* end function AdjustCCBQueue */
diff --git a/private/ntos/miniport/buslogic/buslogic.h b/private/ntos/miniport/buslogic/buslogic.h
new file mode 100644
index 000000000..ebeb69273
--- /dev/null
+++ b/private/ntos/miniport/buslogic/buslogic.h
@@ -0,0 +1,435 @@
+/*++
+
+Copyright (c) 1992 BusLogic, Inc.
+
+Module Name:
+
+ buslogic.h
+
+Abstract:
+
+ This module contains the structures, specific to the BusLogic
+ host bus adapters, used by the SCSI miniport driver. Data structures
+ that are part of standard ANSI SCSI will be defined in a header
+ file that will be available to all SCSI device drivers.
+
+Revision History:
+
+--*/
+
+#include "scsi.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CCB - BusLogic SCSI Command Control Block
+//
+// The CCB is a wrapper for the CDB (Command Descriptor Block)
+// and specifies detailed information about a SCSI command.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Byte 0 Command Control Block Operation Code
+//
+// Byte 1 Address and Direction Control
+//
+// Byte 2 SCSI_Command_Length - Length of SCSI CDB
+//
+// Byte 3 Request Sense Allocation Length
+//
+// Bytes 4, 5,6 & 7 Data Length // Data transfer byte count
+//
+// Bytes 8,9, A, & B Data Pointer // SG List or Data Bfr Ptr
+//
+// Bytes C & D Reserved
+//
+// Byte E Host Status // Host Adapter status
+//
+// Byte F Target Status // Target status
+//
+// Byte 10 Target ID // Target ID
+//
+// Byte 11 LUN
+//
+// Byte 12 thru 1D SCSI CDB // Command Desc. Block
+//
+// Byte 1E Reserved
+//
+// Byte 1F Link ID
+//
+// Byte 20 thru 23 Link pointer // physical link ptr
+//
+// Byte 24 thru 27 Sense pointer // phys. ptr to req. sense
+//
+// Driver-specific fields follow //
+
+//
+// Operation Code Definitions
+//
+#define SCSI_INITIATOR_COMMAND 0x00
+#define TARGET_MODE_COMMAND 0x01
+#define SCATTER_GATHER_COMMAND 0x02
+#define RESET_COMMAND 0x81
+//
+// Control Byte (byte 1) definitions
+//
+#define CCB_DATA_XFER_OUT 0x10 // Write
+#define CCB_DATA_XFER_IN 0x08 // Read
+#define CCB_LUN_MASK 0x07 // Logical Unit Number
+//
+// Request Sense Definitions
+//
+#define FOURTEEN_BYTES 0x00 // Request Sense Buffer size
+#define NO_AUTO_REQUEST_SENSE 0x01 // No Request Sense Buffer
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Scatter/Gather Segment List Definitions
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Adapter limits
+//
+
+#define MAX_SG_DESCRIPTORS 32
+#define MAX_TRANSFER_SIZE 256 * 1024
+
+//
+// Scatter/Gather Segment Descriptor Definition
+//
+
+typedef struct _SGD {
+ ULONG Length;
+ ULONG Address;
+} SGD, *PSGD;
+
+typedef struct _BL_CONTEXT {
+ ULONG AdapterCount;
+ ULONG PCIDevId;
+} BL_CONTEXT, *PBL_CONTEXT;
+
+
+typedef struct _SDL {
+ SGD Sgd[MAX_SG_DESCRIPTORS];
+} SDL, *PSDL;
+
+#define SEGMENT_LIST_SIZE MAX_SG_DESCRIPTORS * sizeof(SGD)
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CCB Typedef
+//
+
+typedef struct _CCB *PCCB;
+
+typedef struct _CCB {
+ UCHAR OperationCode;
+ UCHAR ControlByte;
+ UCHAR CdbLength;
+ UCHAR RequestSenseLength;
+ ULONG DataLength;
+ PVOID DataPointer;
+ USHORT CcbRes0;
+ UCHAR HostStatus;
+ UCHAR TargetStatus;
+ UCHAR TargID;
+ UCHAR Lun;
+ UCHAR Cdb[12];
+ UCHAR CcbRes1;
+ UCHAR LinkIdentifier;
+ PVOID LinkPointer;
+ ULONG SensePointer;
+ SDL Sdl;
+ PVOID SrbAddress;
+ PVOID AbortSrb;
+ PCCB NxtActiveCCB;
+
+ } CCB;
+
+//
+// CCB and request sense buffer
+//
+
+#define CCB_SIZE sizeof(CCB)
+
+
+//
+// Host Adapter Command Operation Codes
+//
+
+#define AC_NO_OPERATION 0x00
+#define AC_MAILBOX_INITIALIZATION 0x01
+#define AC_START_SCSI_COMMAND 0x02
+#define AC_START_BIOS_COMMAND 0x03
+#define AC_ADAPTER_INQUIRY 0x04
+#define AC_ENABLE_MBO_AVAIL_INT 0x05
+#define AC_SET_SELECTION_TIMEOUT 0x06
+#define AC_SET_BUS_ON_TIME 0x07
+#define AC_SET_BUS_OFF_TIME 0x08
+#define AC_SET_TRANSFER_SPEED 0x09
+#define AC_RET_INSTALLED_DEVICES 0x0A
+#define AC_RET_CONFIGURATION_DATA 0x0B
+#define AC_ENABLE_TARGET_MODE 0x0C
+#define AC_RETURN_SETUP_DATA 0x0D
+#define AC_WRITE_CHANNEL_2_BUFFER 0x1A
+#define AC_READ_CHANNEL_2_BUFFER 0x1B
+#define AC_WRITE_FIFO_BUFFER 0x1C
+#define AC_READ_FIFO_BUFFER 0x1D
+#define AC_ECHO_COMMAND_DATA 0x1F
+#define AC_SET_ADAPTER_OPTIONS 0x21
+#define AC_EXTENDED_SETUP_INFO 0x8D
+#define AC_EXTENDED_FWREV 0x84
+#define AC_MBOX_EXTENDED_INIT 0x81
+#define AC_ISA_COMPATIBLE_SUPPORT 0x95
+#define AC_WIDE_SUPPORT 0x96
+#define AC_PCI_INFO 0x86
+#define AC_INT_GENERATION_STATE 0x25
+
+#define DISABLE_ISA_MAPPING 0x6 // cmd 0x95 above
+#define ENABLE_INTS 0x1 // cmd 0x25 above
+#define DISABLE_INTS 0x0 // cmd 0x25 above
+
+//
+// Host status byte
+//
+#define CCB_COMPLETE 0x00 // CCB completed without error
+#define CCB_LINKED_COMPLETE 0x0A // Linked command completed
+#define CCB_LINKED_COMPLETE_INT 0x0B // Linked complete with interrupt
+#define CCB_SELECTION_TIMEOUT 0x11 // Set SCSI selection timed out
+#define CCB_DATA_OVER_UNDER_RUN 0x12
+#define CCB_UNEXPECTED_BUS_FREE 0x13 // Target dropped SCSI BSY
+#define CCB_PHASE_SEQUENCE_FAIL 0x14 // Target bus phase sequence failure
+#define CCB_BAD_MBO_COMMAND 0x15 // MBO command not 0, 1 or 2
+#define CCB_INVALID_OP_CODE 0x16 // CCB invalid operation code
+#define CCB_BAD_LINKED_LUN 0x17 // Linked CCB LUN different from first
+#define CCB_INVALID_DIRECTION 0x18 // Invalid target direction
+#define CCB_DUPLICATE_CCB 0x19 // Duplicate CCB
+#define CCB_INVALID_CCB 0x1A // Invalid CCB - bad parameter
+
+//
+// DMA Transfer Speeds
+//
+
+#define DMA_SPEED_50_MBS 0x00
+
+//
+// LUN byte definitions
+//
+
+#define ENABLE_TQ 0x20 /* bit 5 in bytes 17 of CCB (LUN) */
+#define QUEUEHEAD 0x40 /* Head of Queue tag */
+#define ORDERED 0x80 /* Ordered Queue tag */
+#define SIMPLE 0x00 /* Simple Queue tag */
+
+
+//
+// I/O Port Interface
+//
+
+typedef struct _BASE_REGISTER {
+ UCHAR StatusRegister;
+ UCHAR CommandRegister;
+ UCHAR InterruptRegister;
+} BASE_REGISTER, *PBASE_REGISTER;
+
+//
+// Base+0 Write: Control Register
+//
+
+#define IOP_HARD_RESET 0x80 // bit 7
+#define IOP_SOFT_RESET 0x40 // bit 6
+#define IOP_INTERRUPT_RESET 0x20 // bit 5
+#define IOP_SCSI_BUS_RESET 0x10 // bit 4
+
+//
+// Base+0 Read: Status
+//
+
+#define IOP_SELF_TEST 0x80 // bit 7
+#define IOP_INTERNAL_DIAG_FAILURE 0x40 // bit 6
+#define IOP_MAILBOX_INIT_REQUIRED 0x20 // bit 5
+#define IOP_SCSI_HBA_IDLE 0x10 // bit 4
+#define IOP_COMMAND_DATA_OUT_FULL 0x08 // bit 3
+#define IOP_DATA_IN_PORT_FULL 0x04 // bit 2
+#define IOP_INVALID_COMMAND 0X01 // bit 1
+
+//
+// Base+1 Write: Command/Data Out
+//
+
+//
+// Base+1 Read: Data In
+//
+
+//
+// Base+2 Read: Interrupt Flags
+//
+
+
+#define IOP_ANY_INTERRUPT 0x80 // bit 7
+#define IOP_SCSI_RESET_DETECTED 0x08 // bit 3
+#define IOP_COMMAND_COMPLETE 0x04 // bit 2
+#define IOP_MBO_EMPTY 0x02 // bit 1
+#define IOP_MBI_FULL 0x01 // bit 0
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Mailbox Definitions
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Mailbox Definition
+//
+
+#define MB_COUNT 32 // number of mailboxes
+
+//
+// Mailbox Out
+//
+
+typedef struct _MBO {
+ ULONG Address;
+ UCHAR MboRes[3];
+ UCHAR Command;
+} MBO, *PMBO;
+
+//
+// MBO Command Values
+//
+
+#define MBO_FREE 0x00
+#define MBO_START 0x01
+#define MBO_ABORT 0x02
+
+//
+// Mailbox In
+//
+
+typedef struct _MBI {
+
+ ULONG Address;
+ UCHAR MbiHStat;
+ UCHAR MbiTStat;
+ UCHAR MbiRes;
+ UCHAR Status;
+} MBI, *PMBI;
+
+//
+// MBI Status Values
+//
+
+#define MBI_FREE 0x00
+#define MBI_SUCCESS 0x01
+#define MBI_ABORT 0x02
+#define MBI_NOT_FOUND 0x03
+#define MBI_ERROR 0x04
+
+//
+// Mailbox Initialization
+//
+
+typedef struct _MAILBOX_INIT {
+ ULONG Address;
+ UCHAR Count;
+} MAILBOX_INIT, *PMAILBOX_INIT;
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+
+
+typedef struct _NONCACHED_EXTENSION {
+
+ //
+ // Physical base address of mailboxes
+ //
+
+ ULONG MailboxPA;
+
+ //
+ // Mailboxes
+ //
+
+ MBO Mbo[MB_COUNT];
+ MBI Mbi[MB_COUNT];
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _CARD_STRUC {
+
+ PNONCACHED_EXTENSION MailBoxArray; /* NonCached Extension */
+ PBASE_REGISTER BaseIoAddress; /* Base I/O Address */
+ PMBO CurrMBO; /* Current Mbox Out */
+ PMBO StartMBO; /* First Mbox Out */
+ PMBO LastMBO; /* Last Mbox Out */
+ PMBI CurrMBI; /* Current Mbox In */
+ PMBI StartMBI; /* First Mbox In */
+ PMBI LastMBI; /* Last Mbox In */
+ ULONG Flags;
+ UCHAR BusType; /* ISA/EISA/ or MCA */
+ UCHAR BusNum; /* SCSI bus number */
+ UCHAR HostTargetId; /* HBA Target ID */
+ UCHAR Reserved; /* explicit DWORD align */
+} CARD_STRUC, *PCARD_STRUC;
+
+//
+// CardStruc BusType definitions
+//
+
+#define ISA_HBA 'A'
+#define EISA_HBA 'E'
+#define MCA_HBA 'M'
+
+//
+// CardStruc Flags definitions
+//
+#define TAGGED_QUEUING 0x1000
+#define REINIT_REQUIRED 0x100
+#define WIDE_ENABLED 0x10
+#define OS_SUPPORTS_WIDE 0x200
+
+//
+// Logical unit extension
+//
+
+typedef struct _DEV_STRUC {
+ PCCB CurrentCCB; /* pointer to most recent active CCB */
+ UCHAR NumActive;
+
+} DEV_STRUC, *PDEV_STRUC;
+
+#define MAXACTIVE 2
+#define MAXACTIVE_TAGGED 8
+
+
+//
+// miscellaneous definitions
+//
+
+#define SIMPLE_TAG 0x20
+#define HEAD_OF_QUEUE 0x21
+#define ORDERED_TAG 0x22
+
+#define LEVEL_TRIG 0x40
+
+#define RETURN_FOUND_VESA 4
+#define PORTMASK 0x7
+
+#define MAXIMUM_EISA_SLOTS 0x10
+#define EISA_ADDRESS_BASE 0x0C80
+
+typedef struct _EISA_ID {
+ UCHAR BoardId[4];
+ UCHAR Reserved[8];
+ UCHAR IOPort[1];
+} *PEISA_ID;
diff --git a/private/ntos/miniport/buslogic/buslogic.rc b/private/ntos/miniport/buslogic/buslogic.rc
new file mode 100644
index 000000000..7bfe96603
--- /dev/null
+++ b/private/ntos/miniport/buslogic/buslogic.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "BusLogic SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "BusLogic.sys"
+#define VER_ORIGINALFILENAME_STR "BusLogic.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/buslogic/makefile b/private/ntos/miniport/buslogic/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/buslogic/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/buslogic/sources b/private/ntos/miniport/buslogic/sources
new file mode 100644
index 000000000..5a19fd437
--- /dev/null
+++ b/private/ntos/miniport/buslogic/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=buslogic
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=buslogic.c buslogic.rc
diff --git a/private/ntos/miniport/compaq/cpqarray.c b/private/ntos/miniport/compaq/cpqarray.c
new file mode 100644
index 000000000..b5a0219d3
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqarray.c
@@ -0,0 +1,3819 @@
+/*++
+
+Copyright (c) 1993-4 Microsoft Corporation
+
+Module Name:
+
+ cpqarray.c
+
+Abstract:
+
+ This is the device driver for the Compaq Intelligent Disk Array.
+
+Authors:
+
+ Mike Glass (mglass)
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+ Compaq Information Manager (CIM) support was developed by Tom Bonola and
+ Tom Woller, courtesy of Compaq Computer Corporation.
+
+Revision History:
+
+--*/
+
+#ifndef BYTE
+#define BYTE unsigned char
+#endif
+
+#ifndef WORD
+#define WORD unsigned short
+#endif
+
+#ifndef DWORD
+#define DWORD unsigned long
+#endif
+
+#ifndef INT
+#define INT int
+#endif
+
+#ifndef STATIC
+#if DBG
+#define STATIC
+#else
+#define STATIC static
+#endif
+#endif
+
+
+
+#include "miniport.h"
+#include "scsi.h"
+#include <ntddscsi.h>
+#include <scsireg.h>
+#include <cpqsczmp.h> // Compaq SCSI M&P definitions
+#include "cpqarray.h"
+#include "pcibios.h"
+
+
+//
+// Adapter storage area
+//
+
+typedef struct _DEVICE_EXTENSION {
+
+ //
+ // Requests needing restarts
+ //
+
+ PCOMMAND_LIST RestartRequests;
+
+ //
+ // IDA BMIC registers
+ //
+
+ PIDA_CONTROLLER Bmic;
+ PULONG CPFIFO;
+ PULONG CCFIFO;
+ PULONG InterruptMask;
+ PULONG InterruptStatus;
+ PULONG InterruptPending;
+ HBA_CONFIGURATION HBAConfiguration; //Memory mapped base
+ ULONG BaseIOAddress; // I/O space accessible, not used.
+ PEISAPCI_CONTROLLER eisapci;
+ ULONG PCIoff;
+
+ //
+ // Noncached extension for identify commands
+ //
+
+ PVOID IdentifyBuffer;
+
+ //
+ // Number of logical drives
+ //
+
+ ULONG NumberOfLogicalDrives;
+ UCHAR SectorShift; //setup to 9
+ ULONG EisaId;
+ UCHAR IrqLevel;
+ IDENTIFY_CONTROLLER IdentifyData; // permanent controller info storage
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+//
+// Drive storage area
+//
+
+typedef struct _LOGICAL_UNIT_EXTENSION {
+
+ //
+ // Drive indentify data.
+ //
+
+ IDENTIFY_LOGICAL_DRIVE IdentifyData;
+ SENSE_CONFIGURATION SenseData; // sense data for logical drive
+
+} LOGICAL_UNIT_EXTENSION, *PLOGICAL_UNIT_EXTENSION;
+
+#include "cpqsmngr.h"
+
+VOID
+BuildFlushDisable(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+ULONG
+IdaProcessIoctl(
+ IN PDEVICE_EXTENSION pIdaDeviceExtension,
+ PVOID pIoctlBuffer,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+ULONG
+BuildCIMList(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+VOID
+IdaMoveMemory(
+ OUT PUCHAR pDestination,
+ IN PUCHAR pSource,
+ IN ULONG ulLength
+);
+
+BOOLEAN
+IdaStrCmp(
+ IN PUCHAR p1,
+ IN PUCHAR p2
+);
+
+VOID
+IdaEnableInts(IN PDEVICE_EXTENSION);
+
+
+VOID
+IdaDisableInts(IN PDEVICE_EXTENSION);
+
+
+BOOLEAN
+SearchEisaBus(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from IdaFindAdapter if the system fails to
+ pass in predetermined configuration data. It searches the EISA bus
+ data looking for information about controllers that this driver
+ supports.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ Context - Used to track how many EISA slots have been searched.
+ ConfigInfo - System template for configuration information.
+
+Return Value:
+
+ TRUE - If Compaq IDA controller found.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG length;
+ ULONG eisaSlotNumber;
+ PACCESS_RANGE accessRange;
+ PCM_EISA_SLOT_INFORMATION slotInformation;
+ PCM_EISA_FUNCTION_INFORMATION functionInformation;
+ ULONG numberOfFunctions;
+
+ //
+ // Get pointer to first configuration info structure access range.
+ //
+
+ accessRange = &((*(ConfigInfo->AccessRanges))[0]);
+
+ for (eisaSlotNumber=*((PULONG)Context);
+ eisaSlotNumber<16;
+ eisaSlotNumber++) {
+
+ //
+ // Get pointer to bus data for this EISA slot.
+ //
+
+ length = ScsiPortGetBusData(HwDeviceExtension,
+ EisaConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ eisaSlotNumber,
+ &slotInformation,
+ 0);
+
+ if (!length) {
+ continue;
+ }
+
+ //
+ // Check for Compaq IDA board id.
+ //
+
+ if ((slotInformation->CompressedId & 0x00FFFFFF) == 0x0040110E) {
+ break;
+ }
+ }
+
+ //
+ // Check if all slots searched.
+ //
+
+ if (eisaSlotNumber == 16) {
+ return FALSE;
+ }
+
+ //
+ // Set up default port address.
+ //
+
+ accessRange->RangeStart.LowPart =
+ (eisaSlotNumber * 0x1000) + 0x0C80;
+ accessRange->RangeLength = sizeof(IDA_CONTROLLER);
+
+ accessRange++;
+
+ ConfigInfo->SlotNumber = eisaSlotNumber;
+
+ //
+ // Get the number of EISA configuration functions returned in bus data.
+ //
+
+ numberOfFunctions = slotInformation->NumberFunctions;
+
+ //
+ // Get first configuration record.
+ //
+
+ functionInformation =
+ (PCM_EISA_FUNCTION_INFORMATION)(slotInformation + 1);
+
+ //
+ // Walk configuration records to find EISA IRQ.
+ //
+
+ for (; 0 < numberOfFunctions; numberOfFunctions--, functionInformation++) {
+
+ //
+ // Check for IRQ.
+ //
+
+ if (functionInformation->FunctionFlags & EISA_HAS_IRQ_ENTRY) {
+
+ ConfigInfo->BusInterruptLevel =
+ functionInformation->EisaIrq->ConfigurationByte.Interrupt;
+ ConfigInfo->InterruptMode = LevelSensitive;
+ }
+
+ //
+ // Check for IO ranges.
+ //
+
+ if (functionInformation->FunctionFlags & EISA_HAS_PORT_RANGE) {
+
+ PEISA_PORT_CONFIGURATION eisaPort =
+ functionInformation->EisaPort;
+
+ //
+ // Search for emulation ranges.
+ //
+
+ while (eisaPort->PortAddress) {
+
+ //
+ // Check range to determine length.
+ //
+
+ switch (eisaPort->PortAddress) {
+
+ case 0x000001f0:
+ case 0x00000170:
+
+ accessRange->RangeStart.LowPart = eisaPort->PortAddress;
+ accessRange->RangeLength = 0x0000000F;
+ break;
+
+ case 0x000003f6:
+ case 0x00000176:
+
+ accessRange->RangeStart.LowPart = eisaPort->PortAddress;
+ accessRange->RangeLength = 0x00000001;
+ break;
+ }
+
+ DebugPrint((1,
+ "CPQARRAY: SearchEisaBus: IO base %x\n",
+ eisaPort->PortAddress));
+
+ //
+ // Advance pointers to next IO range.
+ //
+
+ accessRange++;
+ eisaPort++;
+ }
+ }
+ }
+
+ //
+ // Indicate from which EISA slot to continue search.
+ //
+
+ *((PULONG)Context) = eisaSlotNumber + 1;
+
+ return TRUE;
+
+} // end SearchEisaBus()
+
+
+BOOLEAN
+IdaInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the system during initialization to
+ prepare the controller to receive requests.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_EISA_DAZZLER) {
+
+ {
+ ULONG tmp;
+ DebugPrint((3,"CPQARRAY: Initing DAZZLER\n"));
+ tmp = ScsiPortReadPortUlong(&deviceExtension->eisapci->CPFIFO);
+ DebugPrint((3,"IdaInitialize: Room for %x requests\n",tmp));
+ }
+
+ //
+ // Enable command completion interrupts and not channel clear
+ //
+ ScsiPortWritePortUlong(&deviceExtension->eisapci->InterruptMask,
+ IDA_PCI_FIFO_NOT_EMPTY_MASK);
+ } else {
+
+ //
+ // Enable completion interrupts.
+ //
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->InterruptControl,
+ IDA_COMPLETION_INTERRUPT_ENABLE);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SystemDoorBellMask,
+ IDA_COMPLETION_INTERRUPT_ENABLE);
+ }
+
+ return TRUE;
+} // end IdaInitialize()
+
+
+BOOLEAN
+IdaInitializePCI(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the system during initialization to
+ prepare the controller to receive requests.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PULONG ptmp;
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ DebugPrint((1,"CPQARRAY: Initing PCI DAZZLER at 0x%x\n",
+ deviceExtension->HBAConfiguration.ulBaseIOAddress));
+ //
+ // Enable command completion interrupts and not channel clear
+ //
+ ptmp = deviceExtension->InterruptMask;
+ ptmp[0] |= IDA_PCI_FIFO_NOT_EMPTY_MASK;
+
+ DebugPrint((1,"IdaInitializePCI: Room for %x requests\n",
+ *((PULONG)deviceExtension->CPFIFO)));
+
+ return TRUE;
+
+} // end IdaInitializePCI()
+
+
+
+BOOLEAN
+IdaResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resets the controller and completes outstanding requests.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ PathId - Indicates adapter to reset.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+
+#ifndef NCPQNO_TIMEOUT
+ //
+ // 10 second timeout is inappropriate for IDA-style controllers. The
+ // better approach is to never timeout any requests. Proper fix is
+ // to have a class driver for IDA and set the timeout for each type
+ // of controller (currently 3 minutes is a good timeout).
+ //
+/* ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_REQUEST_TIMEOUT,
+ 1); */
+#else
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(HwDeviceExtension,
+ (UCHAR)PathId,
+ 0xFF,
+ 0xFF,
+ SRB_STATUS_BUS_RESET);
+#endif
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ HwDeviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end IdaResetBus()
+
+
+VOID
+BuildCommandList(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a command list suitable for submission to the
+ Compaq IDA controller, from an SRB.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ Srb - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCOMMAND_LIST commandList = Srb->SrbExtension;
+ PVOID dataPointer;
+ ULONG physicalAddress;
+ ULONG bytesLeft;
+ ULONG descriptor;
+ ULONG length;
+
+ //
+ // Save SRB address for interrupt routine.
+ //
+
+ commandList->SrbAddress = Srb;
+
+ //
+ // Set up Command List Header.
+ //
+
+ commandList->CommandListHeader.LogicalDriveNumber = Srb->TargetId;
+
+ commandList->CommandListHeader.RequestPriority = CL_NORMAL_PRIORITY;
+
+ commandList->CommandListHeader.Flags =
+ CL_FLAGS_NOTIFY_LIST_COMPLETE + CL_FLAGS_NOTIFY_LIST_ERROR;
+
+ //
+ // Terminate request list.
+ //
+
+ commandList->RequestHeader.NextRequestOffset = 0;
+
+ //
+ // Clear request tracking flags.
+ //
+
+ commandList->Flags = 0;
+
+ //
+ // Determine command.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ commandList->RequestHeader.CommandByte = RH_COMMAND_READ;
+ } else {
+ commandList->RequestHeader.CommandByte = RH_COMMAND_WRITE;
+ }
+
+ //
+ // Reset error code.
+ //
+
+ commandList->RequestHeader.ErrorCode = 0;
+
+ //
+ // Clear reserved field.
+ //
+
+ commandList->RequestHeader.Reserved = 0;
+
+ //
+ // Determine number of blocks to transfer.
+ //
+
+ commandList->RequestHeader.BlockCount =
+ ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb |
+ ((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8;
+
+ //
+ // Determine number starting block.
+ //
+
+ commandList->RequestHeader.BlockNumber =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+
+ //
+ // Build scatter/gather descriptor list.
+ //
+
+ descriptor = 0;
+ dataPointer = Srb->DataBuffer;
+ bytesLeft = Srb->DataTransferLength;
+
+ do {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ //
+ // Fill in descriptor.
+ //
+
+ commandList->SgDescriptor[descriptor].Address = physicalAddress;
+ commandList->SgDescriptor[descriptor].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptor++;
+
+ } while (bytesLeft);
+
+ //
+ // Calculate size of command list.
+ //
+
+ commandList->RequestHeader.ScatterGatherCount = (UCHAR) descriptor;
+ commandList->CommandListSize = sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR) *
+ descriptor;
+
+ return;
+
+} // end BuildCommandList()
+
+VOID
+SubmitCommandList(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PCOMMAND_LIST CommandList
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to submit a command list to the controller. If
+ the controller can't take it within a specified time interval, then the
+ request is queued to be retried after another request completes.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ CommandList - Request to be submitted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG i;
+ PULONG ptmp;
+ ULONG tmp;
+
+#ifdef DBG
+ DebugPrint((3,
+ "%x %x %x %x Cmd=%x %x Bln=%x Blc=%x SGc=%x %x SG0l=%x SG0a=%x\n",
+ CommandList->CommandListHeader.LogicalDriveNumber,
+ CommandList->CommandListHeader.RequestPriority,
+ CommandList->CommandListHeader.Flags,
+ CommandList->RequestHeader.NextRequestOffset,
+ CommandList->RequestHeader.CommandByte,
+ CommandList->RequestHeader.ErrorCode,
+ CommandList->RequestHeader.BlockNumber,
+ CommandList->RequestHeader.BlockCount,
+ CommandList->RequestHeader.ScatterGatherCount,
+ CommandList->RequestHeader.Reserved,
+ CommandList->SgDescriptor[0].Length,
+ CommandList->SgDescriptor[0].Address
+ ));
+
+ if (CommandList->RequestHeader.ScatterGatherCount > 1) {
+
+ for (i=1;i<CommandList->RequestHeader.ScatterGatherCount;i++) {
+ DebugPrint((1,
+ "%d-l=%x a=%x ",
+ i,CommandList->SgDescriptor[i].Length,
+ CommandList->SgDescriptor[i].Address
+ ));
+ }
+
+ DebugPrint((3,"\n"));
+ }
+#endif
+
+ //
+ // Check for double submission.
+ //
+
+ if (CommandList->Flags & CL_FLAGS_REQUEST_STARTED) {
+
+ DebugPrint((0,
+ "CPQARRAY: SubmitCommandList: Double submission %x\n"));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 1);
+
+ return;
+ }
+
+ //
+ // Get physical address of command list.
+ //
+
+ physicalAddress =
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ CommandList,
+ &length).LowPart;
+
+ // Handle slightly different Command Header in case of SMART-2
+ // controllers. Probably should introduce union to clearify
+ // Command Header structure instead of setting .Flags to List
+ // size. Size is in dwords not bytes as was the case in SMART
+ // and previous ida controllers.
+
+ if (DeviceExtension->HBAConfiguration.bHBAModel == IDA_PCI_DAZZLER) {
+
+ DebugPrint((9,"SubmitCommandList: DAZZLER PCI card\n"));
+
+ CommandList->CommandListHeader.RequestPriority = 0;
+
+ CommandList->CommandListHeader.Flags =
+ ((CommandList->CommandListSize % 4) ? 1 : 0) +
+ (CommandList->CommandListSize >> 2);
+
+ ptmp = DeviceExtension->CPFIFO;
+
+ do {
+ tmp = ptmp[0];
+ ptmp[0] = physicalAddress;
+ } while (tmp == 0);
+
+ DebugPrint((3,
+ "SubmitCommandList: ptmp=0x%x physicalAddress=0x%x\n",
+ ptmp,physicalAddress));
+ CommandList->Flags |= CL_FLAGS_REQUEST_STARTED;
+
+ } else if ((DeviceExtension->HBAConfiguration.bHBAModel ==
+ IDA_EISA_DAZZLER) && !DeviceExtension->PCIoff ) {
+ DebugPrint((9,"SubmitCommandList: DAZZLER EISA PCI interface\n"));
+ CommandList->CommandListHeader.RequestPriority = 0;
+ CommandList->CommandListHeader.Flags =
+ ((CommandList->CommandListSize % 4) ? 1 : 0) +
+ (CommandList->CommandListSize/4);
+
+ //
+ // loop on CPFIFO until we have room to submit
+ //
+ do {
+ tmp = ScsiPortReadPortUlong(&DeviceExtension->eisapci->CPFIFO);
+ ScsiPortWritePortUlong(&DeviceExtension->eisapci->CPFIFO,
+ physicalAddress);
+ } while (tmp == 0);
+
+ CommandList->Flags |= CL_FLAGS_REQUEST_STARTED;
+ } else {
+ DebugPrint((9, "SubmitCommandList: DAZZLER EISA compatible interface\n"));
+
+ //
+ // Wait up to 100 microseconds for submission channel to clear.
+ //
+
+ for (i=0; i<100; i++) {
+
+ if (!(ScsiPortReadPortUchar(&DeviceExtension->Bmic->SystemDoorBell) &
+ SYSTEM_DOORBELL_SUBMIT_CHANNEL_CLEAR)) {
+
+ //
+ // Stall for a microsecond.
+ //
+
+ ScsiPortStallExecution(1);
+
+ } else {
+ break;
+ }
+
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 100) {
+
+ //
+ // Queue request for restart in completion routine.
+ //
+
+ DebugPrint((1,
+ "CPQARRAY: SubmitRequest: Queueing %x\n",
+ CommandList));
+
+ CommandList->Flags |= CL_FLAGS_REQUEST_QUEUED;
+ CommandList->NextEntry = DeviceExtension->RestartRequests;
+ DeviceExtension->RestartRequests = CommandList;
+
+ } else {
+
+ CommandList->Flags |= CL_FLAGS_REQUEST_STARTED;
+
+ //
+ // Reset channel clear bit to claim channel.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->SystemDoorBell,
+ SYSTEM_DOORBELL_SUBMIT_CHANNEL_CLEAR);
+
+ //
+ // Write Command List physical address to BMIC mailbox.
+ //
+
+ ScsiPortWritePortUlong(&DeviceExtension->Bmic->CommandListSubmit.Address,
+ physicalAddress);
+
+ //
+ // Write Command List length to BMIC mailbox.
+ //
+
+ ScsiPortWritePortUshort(&DeviceExtension->Bmic->CommandListSubmit.Length,
+ CommandList->CommandListSize);
+
+ //
+ // Set channel busy bit to signal new Command List is available.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->LocalDoorBell,
+ LOCAL_DOORBELL_COMMAND_LIST_SUBMIT);
+ }
+
+ }
+
+} // end SubmitCommandList()
+
+
+
+BOOLEAN
+IdaInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This interrupt service routine is called by the system to process an
+ adapter interrupt. The Compaq IDA controller interrupts to signal
+ completion of a request.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+
+Return Value:
+
+ TRUE if adapter is interrupting.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG physicalAddress;
+ PCOMMAND_LIST commandList;
+ PCOMMAND_LIST nextCommand;
+ PSCSI_REQUEST_BLOCK srb;
+ UCHAR status;
+ PSRB_IO_CONTROL pSrb;
+ PIDA_ERROR_BITS dataPointer;
+ PUCHAR ReturnPointer;
+ PUCHAR MovePointer;
+ UCHAR CmdListStatus;
+ PULONG ptmp;
+
+ //
+ // Verify that interrupt is from one of our controllers.
+ //
+
+ if ((deviceExtension->HBAConfiguration.bHBAModel == IDA_EISA_DAZZLER) &&
+ !deviceExtension->PCIoff ) {
+ DebugPrint((3,"IdaInterrupt: DAZZLER PCI mode\n"));
+
+ //
+ // The PCI interface specification calls for us to check the
+ // InterruptPending register to verify that an interrupt has
+ // been asserted at our controller. We are instead looking
+ // at the InterruptStatus masked with 0x01 to acheive the same
+ // result. We cannot use the spec's method, because at init and
+ // during a rescan at runtime, we have disabled controller
+ // interrupts and thus InterruptPending will be set to zero.
+ //
+
+ if (!(ScsiPortReadPortUlong(&deviceExtension->eisapci->InterruptStatus)
+ & IDA_PCI_COMPLETION_STATUS_ACTIVE)) {
+
+ //
+ // Interrupt is not for this controller.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Read the physical address
+ //
+
+ physicalAddress = ScsiPortReadPortUlong(&deviceExtension->
+ eisapci->CCFIFO);
+
+ DebugPrint((1,"CCFIFO=%x\n",physicalAddress));
+
+ CmdListStatus = (UCHAR)physicalAddress &
+ IDA_PCI_COMPLETION_STATUS_MASK;
+
+ if (CmdListStatus & IDA_PCI_COMPLETION_ERROR) {
+
+ DebugPrint((1,"IdaInterrupt: DAZZLER ERROR bit 0 set\n"));
+
+ //
+ // for compatibility change the status to old style error code.
+ //
+
+ CmdListStatus = RH_BAD_COMMAND_LIST;
+ }
+
+ physicalAddress &= IDA_PCI_PHYS_ADDR_MASK;
+
+ } else if (deviceExtension->HBAConfiguration.bHBAModel
+ == IDA_BASE_CONTROLLER) {
+
+ //
+ // Check if interrupt is expected.
+ //
+
+ if (!(ScsiPortReadPortUchar(&deviceExtension->Bmic->SystemDoorBell) &
+ SYSTEM_DOORBELL_COMMAND_LIST_COMPLETE)) {
+
+ //
+ // Interrupt is spurious.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Get physical command list address from mailbox.
+ //
+
+ physicalAddress =
+ ScsiPortReadPortUlong(&deviceExtension->Bmic->
+ CommandListComplete.Address);
+
+ CmdListStatus =
+ ScsiPortReadPortUchar(&deviceExtension->Bmic->
+ CommandListComplete.Status);
+
+ //
+ // Dismiss interrupt at device by clearing command complete
+ // bit in system doorbell.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SystemDoorBell,
+ SYSTEM_DOORBELL_COMMAND_LIST_COMPLETE);
+
+ //
+ // Free command completion channel.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->LocalDoorBell,
+ LOCAL_DOORBELL_COMPLETE_CHANNEL_CLEAR);
+
+ } else if (deviceExtension->HBAConfiguration.bHBAModel
+ == IDA_PCI_DAZZLER) {
+
+ // Flags gets the list size and then write the phys addr out
+ // to the port
+ DebugPrint((3,"IdaInterrupt: DAZZLER PCI card\n"));
+
+ //
+ // The PCI interface specification calls for us to check the
+ // InterruptPending register to verify that an interrupt has
+ // been asserted at our controller. We are instead looking
+ // at the InterruptStatus masked with 0x01 to acheive the same
+ // result. We cannot use the spec's method, because at init and
+ // during a rescan at runtime, we have disabled controller
+ // interrupts and thus InterruptPending will be set to zero.
+ //
+
+ if (!(*((PULONG)deviceExtension->InterruptStatus) &
+ IDA_PCI_COMPLETION_STATUS_ACTIVE)) {
+
+ //
+ // Interrupt is not for this controller.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Read the physical address
+ //
+
+ ptmp = deviceExtension->CCFIFO;
+ physicalAddress = ptmp[0];
+
+ DebugPrint((9,"CCFIFO=%x\n",physicalAddress));
+
+ CmdListStatus = (UCHAR)physicalAddress & IDA_PCI_COMPLETION_STATUS_MASK;
+
+ if (CmdListStatus & IDA_PCI_COMPLETION_ERROR) {
+
+ DebugPrint((1,"IdaInterrupt: DAZZLER ERROR bit 0 set\n"));
+
+ CmdListStatus = RH_BAD_COMMAND_LIST;
+ }
+
+ physicalAddress &= IDA_PCI_PHYS_ADDR_MASK;
+
+ } else {
+
+ DebugPrint((1,"IdaInterrupt: ERROR - unknown HBA\n"));
+
+ }
+
+ //
+ // As a sanity check make sure physical address is not zero.
+ //
+
+ if (!physicalAddress) {
+
+ DebugPrint((1,
+ "IdaInterrupt: Physical address is zero\n"));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 2);
+
+ return TRUE;
+ }
+
+ //
+ // Get the virtual command list address.
+ //
+
+ commandList =
+ ScsiPortGetVirtualAddress(deviceExtension,
+ ScsiPortConvertUlongToPhysicalAddress(
+ physicalAddress));
+
+ DebugPrint((9, "Phys=%x %x\n",physicalAddress,commandList));
+
+ //
+ // As a sanity check make sure command list is not zero.
+ //
+
+ if (!commandList) {
+
+ DebugPrint((1, "IdaInterrupt: Command list is zero\n"));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3);
+
+ return TRUE;
+ }
+
+ //
+ // Check for double completion.
+ //
+
+ if (commandList->Flags & CL_FLAGS_REQUEST_COMPLETED) {
+
+ DebugPrint((1, "IdaInterrupt: Double completion %x\n",
+ commandList));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4);
+
+ return TRUE;
+
+ } else {
+
+ commandList->Flags |= CL_FLAGS_REQUEST_COMPLETED;
+ }
+
+ DebugPrint((3,"ErrorCode=%x\n", commandList->RequestHeader.ErrorCode));
+
+ if (CmdListStatus & RH_BAD_COMMAND_LIST)
+ commandList->RequestHeader.ErrorCode |= RH_BAD_COMMAND_LIST;
+
+ //
+ // Check request block error code.
+ //
+
+ DebugPrint((3,"ErrorCode=%x\n", commandList->RequestHeader.ErrorCode));
+
+ switch (commandList->RequestHeader.ErrorCode & ~RH_WARNING) {
+
+ case RH_SUCCESS:
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case RH_FATAL_ERROR:
+
+ status = SRB_STATUS_ERROR;
+ break;
+
+ case RH_RECOVERABLE_ERROR:
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case RH_INVALID_REQUEST:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case RH_REQUEST_ABORTED:
+
+ status = SRB_STATUS_ABORTED;
+ break;
+
+ default:
+
+ status = SRB_STATUS_ERROR;
+ break;
+ }
+
+ //
+ // Get SRB.
+ //
+
+ srb = commandList->SrbAddress;
+
+ //
+ // As a sanity check make sure SRB is not zero.
+ //
+
+ if (!srb) {
+
+ if (!commandList->Flags & CL_FLAGS_IDENTIFY_REQUEST) {
+
+ DebugPrint((1, "IdaInterrupt: SRB is zero\n"));
+
+ //
+ // Log this error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 5);
+ }
+
+ return TRUE;
+ }
+
+ if (srb->Function == SRB_FUNCTION_IO_CONTROL) {
+
+ pSrb = (PSRB_IO_CONTROL)srb->DataBuffer;
+
+ switch (pSrb->ControlCode) {
+ case CPQ_IOCTL_PASSTHROUGH:
+ {
+ dataPointer = (PIDA_ERROR_BITS)((PUCHAR)srb->DataBuffer
+ + srb->DataTransferLength
+ - sizeof(IDA_ERROR_BITS));
+
+ if (CmdListStatus & RH_BAD_COMMAND_LIST) {
+ DebugPrint((1,
+ "IdaInterrupt: BAD_COMMAND_LIST error for PASSTHRU to %x\n",
+ deviceExtension));
+
+ dataPointer->ControllerError = RH_BAD_COMMAND_LIST |
+ (ULONG)commandList->RequestHeader.ErrorCode;
+ } else {
+ dataPointer->ControllerError =
+ (ULONG)commandList->RequestHeader.ErrorCode;
+ }
+
+ break;
+ }
+
+ case CPQ_IOCTL_SCSIPASSTHROUGH:
+ {
+
+ PSCSI_BUFFER_HEADER dataPacket;
+ ULONG bufferOffset;
+
+ if (commandList->RequestHeader.BlockNumber == 1) {
+ DebugPrint((3,
+ "IdaInterrupt: SCSIPASSTHRU intermediate copy needed.\n"));
+
+ //
+ // if BlockNumber == 1 then need to copy the data at the end of the
+ // commandList into the user buffer.
+ //
+
+ ReturnPointer = (PUCHAR)srb->DataBuffer
+ + sizeof(SRB_IO_CONTROL)
+ + sizeof(MAP_PARAMETER_PACKET);
+
+ MovePointer = (PUCHAR)commandList + sizeof(SG_DESCRIPTOR)
+ + sizeof(COMMAND_LIST_HEADER)
+ + sizeof(REQUEST_HEADER)
+ + sizeof(SCSI_PASSTHRU);
+
+ IdaMoveMemory(ReturnPointer, MovePointer,
+ commandList->SgDescriptor[0].Length);
+ }
+
+ //
+ // setup the return fields in the return data area.
+ //
+
+ bufferOffset = sizeof(SRB_IO_CONTROL) + sizeof(SCSI_PASSTHRU);
+
+ dataPacket = (PSCSI_BUFFER_HEADER)((PUCHAR)srb->DataBuffer
+ + bufferOffset);
+
+ dataPacket->CmdError = (UCHAR)commandList->RequestHeader.ErrorCode;
+
+ dataPacket->device_status =
+ ((PSCSI_PASSTHRU) (&commandList->
+ SgDescriptor[
+ commandList->
+ RequestHeader.ScatterGatherCount
+ ].Length))->scsi_header.device_status;
+
+ dataPacket->machine_error =
+ ((PSCSI_PASSTHRU) (&commandList->
+ SgDescriptor[commandList->RequestHeader.
+ ScatterGatherCount
+ ].
+ Length))->scsi_header.machine_error;
+
+ if (CmdListStatus & RH_BAD_COMMAND_LIST) {
+ DebugPrint((1,
+ "IdaInterrupt: BAD_COMMAND_LIST error for SCSI PASSTHRU to %x\n",
+ deviceExtension));
+
+ dataPacket->CmdError = (UCHAR)(RH_BAD_COMMAND_LIST |
+ commandList->RequestHeader.ErrorCode);
+ }
+
+ }
+
+ default:
+ break;
+
+ } // end switch
+
+ }
+
+ srb->SrbStatus = status;
+
+ //
+ // Inform system that this request is complete.
+ //
+
+ ScsiPortNotification(RequestComplete, deviceExtension, srb);
+
+ //
+ // Check if any requests need restarting.
+ //
+
+ if (deviceExtension->RestartRequests) {
+
+ //
+ // Get pointer to head of list.
+ //
+
+ nextCommand = deviceExtension->RestartRequests;
+ deviceExtension->RestartRequests = NULL;
+
+ //
+ // Try to restart each request in the list.
+ //
+
+ while (nextCommand) {
+
+ commandList = nextCommand;
+ nextCommand = nextCommand->NextEntry;
+
+ DebugPrint((1, "IdaInterrupt: Restarting request %x\n",
+ commandList));
+
+ //
+ // Submit command list to controller.
+ //
+
+ SubmitCommandList(deviceExtension, commandList);
+ }
+
+ }
+
+ return TRUE;
+
+} // IdaInterrupt();
+
+BOOLEAN
+GetDiskIdentifyData(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PVOID HwDeviceExtension,
+ IN PCOMMAND_LIST CommandList,
+ IN ULONG DriveNumber,
+ IN UCHAR Command
+ )
+
+/*++
+
+Routine Description:
+
+ Issue request to get identify data for this drive. This
+ routine has been modified for SMART-2 controller support.
+ Specifically, we are not accepting rescans for added logical
+ drives at run-time. Two functions have been added to
+ disable/enable controller interrupts while requesting details
+ from the firmware.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ CommandList - Buffer for building request to controller.
+ DriveNumber - Identifies drive on controller.
+ Command - IDA command code.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG length;
+ ULONG i;
+ BOOLEAN intrtn;
+
+ //
+ // Disable controller interrupts. This action was added with support
+ // for the SMART-2 controllers and online logical drive configuration.
+ // Following the addition of one or more logical drives, a rescan will
+ // request information about the new drives. Since this routine will
+ // return requested information, we cannot simply submit the command
+ // and exit. To reduce the number of outstanding requests we find at
+ // the controller while searching for ours, interrupts are temporarily
+ // disabled at all array controllers. The impact of this should not be
+ // too significant, as we should not be rescanning often.
+ //
+
+ IdaDisableInts(deviceExtension);
+
+ //
+ // load srb for interrupt routine...
+ //
+
+ CommandList->SrbAddress = Srb;
+
+ //
+ // Set up Command List Header.
+ //
+
+ CommandList->CommandListHeader.LogicalDriveNumber = (UCHAR)DriveNumber;
+ CommandList->CommandListHeader.RequestPriority = CL_NORMAL_PRIORITY;
+
+ //
+ // Indicate no notification required.
+ //
+
+ CommandList->CommandListHeader.Flags = 0;
+
+ //
+ // Zero out unused fields.
+ //
+
+ CommandList->RequestHeader.NextRequestOffset = 0;
+ CommandList->RequestHeader.ErrorCode = RH_SUCCESS;
+ CommandList->RequestHeader.Reserved = 0;
+
+ //
+ // Determine command.
+ //
+
+ CommandList->RequestHeader.CommandByte = Command;
+
+ //
+ // Set up request control fields.
+ //
+
+ CommandList->RequestHeader.BlockCount = 1;
+ CommandList->RequestHeader.BlockNumber = 0;
+ CommandList->Flags = CL_FLAGS_IDENTIFY_REQUEST;
+
+ //
+ // Fill in scatter/gather entry.
+ //
+
+ CommandList->SgDescriptor[0].Length = 512;
+
+ CommandList->SgDescriptor[0].Address =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(HwDeviceExtension,
+ NULL,
+ deviceExtension->
+ IdentifyBuffer,
+ &length));
+
+ //
+ // Calculate size of command list.
+ //
+
+ CommandList->RequestHeader.ScatterGatherCount=1;
+ CommandList->CommandListSize = sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR);
+
+ //
+ // Submit command list to controller.
+ //
+
+ SubmitCommandList(deviceExtension, CommandList);
+
+ DebugPrint((1, "GetDiskIdentifyData: Command Submitted:\n"));
+
+ //
+ // Poll interrupt routine. We are planning to poll for quite
+ // some time. It appears that the initial request made to the
+ // Dazzler/P board takes sometime and if we don't wait long
+ // enough here, we will have problems at init and probably
+ // anytime a rescan is requested. Current setting is 6 minutes
+ // which is probably too long, but.....
+ //
+
+ for (i=0; i < 360000; i++) {
+
+ //
+ // Call interrupt routine directly.
+ //
+
+ IdaInterrupt(HwDeviceExtension);
+
+ DebugPrint((1, "GetDiskIdentifyData: IdaInterrupt called:\n"));
+
+ // check for my completion...
+ if (CommandList->Flags & CL_FLAGS_REQUEST_COMPLETED) {
+
+ //
+ // Check status of completed request.
+ //
+
+ if ((CommandList->RequestHeader.ErrorCode & ~RH_WARNING) ==
+ RH_SUCCESS) {
+ IdaEnableInts(deviceExtension);
+ return TRUE;
+ } else {
+ DebugPrint((1, "GetDiskIdentifyData: Command failed: %x\n",
+ CommandList->RequestHeader.ErrorCode));
+
+ //
+ // Command failed.
+ //
+
+ IdaEnableInts(deviceExtension);
+ return FALSE;
+ }
+
+ }
+
+ ScsiPortStallExecution(1000);
+
+ }
+
+ IdaEnableInts(deviceExtension);
+ return FALSE;
+
+} // end GetDiskIdentifyData()
+
+
+BOOLEAN
+IdaStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This is routine is called by the system to start a request on the adapter.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ Srb - Address of the request to be started.
+
+Return Value:
+
+ TRUE - The request has been started.
+ FALSE - The controller was busy.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ ULONG i;
+ UCHAR status;
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ if (!IdaResetBus(deviceExtension, Srb->PathId)) {
+ status = SRB_STATUS_ERROR;
+ } else {
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_WRITE:
+ case SCSIOP_READ:
+
+ //
+ // Build command list from SRB.
+ //
+
+ BuildCommandList(deviceExtension,
+ Srb);
+
+ //
+ // Submit command list to controller.
+ //
+
+ SubmitCommandList(deviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension);
+
+ status = SRB_STATUS_PENDING;
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSIOP_READ_CAPACITY:
+
+ //
+ // Get logical unit extension.
+ //
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (luExtension) {
+ ULONG blockSize = luExtension->IdentifyData.BlockLength;
+
+ //
+ // Get blocksize and number of blocks from identify
+ // data.
+ //
+ REVERSE_BYTES
+ (&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock,
+ &blockSize);
+
+ REVERSE_BYTES
+ (&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress,
+ &luExtension->IdentifyData.NumberOfBlocks);
+
+ DebugPrint((1, "IdaStartIo: Block size %x\n",
+ luExtension->IdentifyData.BlockLength));
+
+ DebugPrint((1, "IdaStartIo: Number of blocks %x\n",
+ luExtension->IdentifyData.NumberOfBlocks));
+
+ status = SRB_STATUS_SUCCESS;
+
+ } else {
+ status = SRB_STATUS_ERROR;
+ }
+
+ break;
+
+ case SCSIOP_INQUIRY:
+ //
+ // Only respond at logical unit 0;
+ //
+
+ if (Srb->Lun != 0) {
+ //
+ // Indicate no device found at this address.
+ //
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Get number of logical drives.
+ //
+
+ if (GetDiskIdentifyData(Srb, HwDeviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension,
+ 0, RH_COMMAND_IDENTIFY_CONTROLLER)) {
+ deviceExtension->NumberOfLogicalDrives = (ULONG)
+ ((PIDENTIFY_CONTROLLER)
+ deviceExtension->IdentifyBuffer)->NumberLogicalDrives;
+
+ DebugPrint((1,
+ "IdaStartIo: Number of logical drives %x\n",
+ deviceExtension->NumberOfLogicalDrives));
+
+ //
+ // save off the identify controller buffer to the
+ // extension area
+ //
+
+ ScsiPortMoveMemory(&deviceExtension->IdentifyData,
+ deviceExtension->IdentifyBuffer,
+ sizeof(IDENTIFY_CONTROLLER));
+
+ } else {
+ DebugPrint((1,
+ "IdaFindAdapters: Get controller information failed\n"));
+ status = SRB_STATUS_ERROR;
+ break;
+ }
+
+ //
+ // Check if this is for one of the reported logical drives.
+ //
+
+ if (Srb->TargetId >=
+ deviceExtension->NumberOfLogicalDrives) {
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Issue identify command.
+ //
+
+ if (!GetDiskIdentifyData(Srb, HwDeviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension,
+ Srb->TargetId,
+ RH_COMMAND_IDENTIFY_LOGICAL_DRIVES)) {
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ //
+ // Copy data from buffer to logical unit extension.
+ //
+
+ ScsiPortMoveMemory(&luExtension->IdentifyData,
+ deviceExtension->IdentifyBuffer,
+ sizeof(IDENTIFY_LOGICAL_DRIVE));
+ //
+ // Issue sense configuration command.
+ //
+
+ if (!GetDiskIdentifyData(Srb, HwDeviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension,
+ Srb->TargetId,
+ RH_COMMAND_SENSE_CONFIGURATION)) {
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ //
+ // Copy data from buffer to logical unit extension.
+ //
+
+ ScsiPortMoveMemory(&luExtension->SenseData,
+ deviceExtension->IdentifyBuffer,
+ sizeof(SENSE_CONFIGURATION));
+
+ //
+ // Zero INQUIRY data structure.
+ //
+
+ for (i = 0; i < Srb->DataTransferLength; i++) {
+ ((PUCHAR)Srb->DataBuffer)[i] = 0;
+ }
+
+ //
+ // Compaq IDA only supports disks.
+ //
+
+ ((PINQUIRYDATA)Srb->DataBuffer)->DeviceType = DIRECT_ACCESS_DEVICE;
+
+ //
+ // Fill in vendor identification fields.
+ //
+
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[0] = 'C';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[1] = 'o';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[2] = 'm';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[3] = 'p';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[4] = 'a';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[5] = 'q';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[6] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->VendorId[7] = ' ';
+
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[0] = 'D';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[1] = 'i';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[2] = 's';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[3] = 'k';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[4] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[5] = 'A';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[6] = 'r';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[7] = 'r';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[8] = 'a';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[9] = 'y';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[10] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[11] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[12] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[13] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[14] = ' ';
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductId[15] = ' ';
+
+ //
+ // Move firmware revision from IDENTIFY data to
+ // product revision in INQUIRY data.
+ //
+
+ for (i = 0; i < 4; i++) {
+ ((PINQUIRYDATA)Srb->DataBuffer)->ProductRevisionLevel[i] =
+ deviceExtension->IdentifyData.FirmwareRevision[i];
+ }
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSIOP_VERIFY:
+
+ //
+ // Compaq array controllers hotfix bad sectors as they are
+ // encountered. A sector verify in unnecessary.
+ //
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ } // end switch (Srb->Cdb[0])
+
+ break;
+
+ //
+ // Issue FLUSH/DISABLE if shutdown command.
+ //
+
+ case SRB_FUNCTION_SHUTDOWN:
+
+ BuildFlushDisable(deviceExtension,Srb);
+ SubmitCommandList(deviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension);
+
+ status = SRB_STATUS_PENDING;
+
+ break;
+
+ //
+ // Do not need the flush command since all controllers have
+ // memory that is battery backed up. Just return success.
+ //
+
+ case SRB_FUNCTION_FLUSH:
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SRB_FUNCTION_IO_CONTROL: {
+ PCPQ_IDA_IDENTIFY pIoctlBuffer;
+
+ pIoctlBuffer = (PCPQ_IDA_IDENTIFY)Srb->DataBuffer;
+
+ //
+ // Status is returned mainly in 2 fields to the calling thread.
+ // These 2 fields determine if other status fields are valid to
+ // check. If the request is not a valid request for this driver
+ // then the Header.ReturnCode is not modified and the
+ // Srb->SrbStatus is set to SRB_STATUS_INVALID_REQUEST. If
+ // the request is valid for this driver then Srb->SrbStatus
+ // is always returned as SRB_STATUS_SUCCESS and the
+ // Header.ReturnCode contains information concerning the
+ // status of the particular request.
+ //
+
+ if (!IdaStrCmp(pIoctlBuffer->Header.Signature, IDA_SIGNATURE)) {
+
+ if (IdaProcessIoctl(deviceExtension,
+ pIoctlBuffer,
+ Srb) == CPQ_CIM_ISSUED) {
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ } else {
+ status = SRB_STATUS_INVALID_REQUEST;
+ }
+
+ break;
+ }
+
+ default:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+
+ } // end switch
+
+ //
+ // Check if SRB should be completed.
+ //
+
+ if (status != SRB_STATUS_PENDING) {
+
+ //
+ // Set status in SRB.
+ //
+
+ Srb->SrbStatus = status;
+
+ //
+ // Inform system that this request is complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ }
+
+ //
+ // Indicate to system that the controller can take another request
+ // for this device.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ return TRUE;
+
+} // end IdaStartIo()
+
+ULONG
+IdaProcessIoctl(
+ IN PDEVICE_EXTENSION deviceExtension,
+ PVOID pIoctlBuffer,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+{
+ ULONG currentId;
+ ULONG numberOfLuns;
+ ULONG status;
+ PCPQ_IDA_IDENTIFY pCPQ = pIoctlBuffer;
+
+ //
+ // Build command list from SRB.
+ //
+
+ status = CPQ_CIM_COMPLETED;
+
+ DebugPrint((3,
+ "IdaProcessIoctl(): parsing request %d for PathId=%d TargetId=%d Lun=%d\n",
+ pCPQ->Header.ControlCode,Srb->PathId,Srb->TargetId,Srb->Lun));
+
+ switch(pCPQ->Header.ControlCode) {
+ case CPQ_IOCTL_IDENTIFY_DRIVER: {
+ PLOGICAL_UNIT_EXTENSION luExtension;
+
+ PMAP_HEADER header = (PMAP_HEADER)((PUCHAR)Srb->DataBuffer +
+ sizeof(SRB_IO_CONTROL));
+
+ IdaMoveMemory(header->DriverName, IDA_DRIVER_NAME,
+ sizeof(header->DriverName));
+
+ header->DriverMajorVersion = IDA_MAJOR_VERSION;
+ header->DriverMinorVersion = IDA_MINOR_VERSION;
+
+ header->ControllerCount = 1;
+
+ //
+ // We need to give back the number of LUNs not the actual
+ // number of LUNs available because LU extensions are not
+ // discarded when a drive has been removed or taken off-line.
+ //
+
+ currentId = 0;
+ numberOfLuns = 0;
+
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ (UCHAR)currentId,
+ Srb->Lun);
+ while (luExtension) {
+ numberOfLuns++;
+ currentId++;
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ (UCHAR)currentId,
+ Srb->Lun);
+ }
+
+ header->LogicalDiskCount = numberOfLuns;
+
+ header->RequiredMemory = sizeof(MAP_CONTROLLER_DATA) +
+ (sizeof(MAP_LOGICALDRIVE_DATA) * numberOfLuns);
+
+ status = CPQ_CIM_COMPLETED;
+ break;
+ }
+
+ case CPQ_IOCTL_IDENTIFY_CONTROLLERS: {
+ ULONG i;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ PMAP_LOGICALDRIVE_DATA LdriveData;
+ PMAP_CONTROLLER_DATA controllerData;
+
+ //
+ // Take care of the controller struct first
+ //
+
+ controllerData = (PMAP_CONTROLLER_DATA)
+ ((PUCHAR)Srb->DataBuffer + sizeof(SRB_IO_CONTROL));
+
+ controllerData->NextController = NULL;
+
+ //
+ // calculate offset from the beginning of the controller data area.
+ //
+
+ controllerData->LogicalDriveList =
+ (PMAP_LOGICALDRIVE_DATA)(controllerData + 1);
+ controllerData->EisaId = deviceExtension->EisaId;
+ controllerData->BmicIoAddress = (ULONG)deviceExtension->Bmic;
+ controllerData->IrqLevel = deviceExtension->IrqLevel;
+
+ IdaMoveMemory((PUCHAR)&controllerData->ControllerInfo,
+ (PUCHAR)&deviceExtension->IdentifyData,
+ sizeof(IDENTIFY_CONTROLLER));
+
+ //
+ // Now look for logical units until one is not found. In the future
+ // support non-consecutive logical units, for now, stop searching.
+ //
+
+ currentId = 0;
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ (UCHAR)currentId,
+ Srb->Lun);
+
+ LdriveData = controllerData->LogicalDriveList;
+
+ while (luExtension) {
+
+ //
+ // Set the DeviceLengthXX sizes to 0, removed from CIM interface.
+ //
+
+ LdriveData->NextLogicalDrive = LdriveData + 1;
+ LdriveData->Controller = controllerData;
+ LdriveData->LogicalDriveNumber = currentId;
+ LdriveData->SystemDriveNumber = 0;
+ LdriveData->DeviceLengthLo = 0;
+ LdriveData->DeviceLengthHi = 0;
+ LdriveData->SectorSize = (ULONG)(1 << deviceExtension->SectorShift);
+ IdaMoveMemory((PUCHAR)&LdriveData->Configuration,
+ (PUCHAR)&luExtension->SenseData,
+ sizeof(SENSE_CONFIGURATION));
+
+ IdaMoveMemory((PUCHAR)&LdriveData->LogicalDriveInfo,
+ (PUCHAR)&luExtension->IdentifyData,
+ sizeof(IDENTIFY_LOGICAL_DRIVE));
+
+ currentId++;
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension, Srb->PathId,
+ (UCHAR)currentId, Srb->Lun);
+
+ if (!luExtension) {
+ break;
+ }
+
+ LdriveData = LdriveData + 1;
+ }
+
+ LdriveData->NextLogicalDrive = NULL;
+
+ //
+ // Need to convert NextLogicalDrive fields to offsets from virtual
+ // addresses. currentId is the last ID that was found.
+ //
+
+ if (currentId) {
+ controllerData->LogicalDriveList =
+ (PMAP_LOGICALDRIVE_DATA)sizeof(MAP_CONTROLLER_DATA);
+ LdriveData = (PMAP_LOGICALDRIVE_DATA)(controllerData + 1);
+ LdriveData->NextLogicalDrive = NULL;
+
+ for (i=0;i<(currentId-1);i++,LdriveData++) {
+ LdriveData->NextLogicalDrive =
+ (PMAP_LOGICALDRIVE_DATA)(sizeof(MAP_CONTROLLER_DATA)
+ + ((i+1)*sizeof(MAP_LOGICALDRIVE_DATA)));
+ }
+
+ } else {
+ controllerData->LogicalDriveList = NULL;
+ }
+
+ status = CPQ_CIM_COMPLETED;
+ break;
+ }
+
+ case CPQ_IOCTL_PASSTHROUGH:
+ case CPQ_IOCTL_SCSIPASSTHROUGH: {
+
+ if (!(BuildCIMList(deviceExtension, Srb) == CPQ_CIM_CMDBUILT)) {
+ status = CPQ_CIM_COMPLETED;
+ } else {
+
+ //
+ // Submit command list to controller.
+ //
+
+ DebugPrint((3,
+ "IdaProcessIoctl(): Submitting PASSTHRU request to %x\n",
+ deviceExtension));
+
+ SubmitCommandList(deviceExtension,
+ (PCOMMAND_LIST)Srb->SrbExtension);
+ status = CPQ_CIM_ISSUED;
+ }
+ break;
+ }
+
+ case CPQ_IOCTL_CONFIGURATION_INFO: {
+ PIDA_CONFIGURATION pConfigData;
+
+ //
+ // Setup pointer to the Config Data area
+ //
+
+ pConfigData = (PIDA_CONFIGURATION)
+ ((PUCHAR)Srb->DataBuffer + sizeof(SRB_IO_CONTROL));
+
+ pConfigData->ulBaseMemoryAddress =
+ deviceExtension->HBAConfiguration.ulBaseIOAddress;
+ pConfigData->bIoBusType =
+ deviceExtension->HBAConfiguration.bHBAIoBusType;
+ pConfigData->ulBaseIOAddress = deviceExtension->BaseIOAddress;
+ pConfigData->ulControllerID = deviceExtension->EisaId;
+ IdaMoveMemory((PUCHAR)&pConfigData->IoBusData,
+ (PUCHAR)&deviceExtension->HBAConfiguration.HBAIoBusData,
+ sizeof(union _IO_BUS_DATA));
+ status = CPQ_CIM_COMPLETED;
+ break;
+ }
+
+ default:
+ pCPQ->Header.ReturnCode = CPQ_SCSI_ERR_BAD_CNTL_CODE;
+ status = CPQ_CIM_COMPLETED;
+ break;
+ }
+
+ return(status);
+}
+
+
+VOID
+BuildFlushDisable(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a shutdown command list suitable for submission to the
+ Compaq IDA controller, from an SRB.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ Srb - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCOMMAND_LIST commandList = Srb->SrbExtension;
+ ULONG length,i;
+ PFLUSH_DISABLE pFlushDisable;
+ PSG_DESCRIPTOR sgList;
+
+ sgList = commandList->SgDescriptor;
+
+ // clear out reserved area
+
+ for (i=0;i<MAXIMUM_SG_DESCRIPTORS;i++) {
+ sgList[i].Address = 0;
+ sgList[i].Length = 0;
+ }
+
+ //
+ // Save SRB address for interrupt routine.
+ //
+
+ commandList->SrbAddress = Srb;
+
+ //
+ // Set up Command List Header.
+ //
+
+ commandList->CommandListHeader.LogicalDriveNumber = 0;
+
+ commandList->CommandListHeader.RequestPriority = CL_NORMAL_PRIORITY;
+
+ commandList->CommandListHeader.Flags =
+ CL_FLAGS_NOTIFY_LIST_COMPLETE + CL_FLAGS_NOTIFY_LIST_ERROR;
+
+ //
+ // Set up Request Header.
+ //
+ // Terminate request list.
+ //
+
+ commandList->RequestHeader.NextRequestOffset = 0;
+
+ commandList->Flags = 0;
+
+ //
+ // Reset error code.
+ //
+
+ commandList->RequestHeader.ErrorCode = 0;
+
+ //
+ // Clear reserved field.
+ //
+
+ commandList->RequestHeader.Reserved = 0;
+
+ //
+ // Check for special Compaq passthrough command.
+ //
+
+ commandList->RequestHeader.BlockCount = (USHORT)1;
+ commandList->RequestHeader.BlockNumber = (ULONG)0;
+ commandList->RequestHeader.CommandByte = RH_COMMAND_FLUSH_DISABLE_CACHE;
+
+ pFlushDisable = (PFLUSH_DISABLE)&(sgList[1].Length);
+ pFlushDisable->disable_flag = 1; //disable cache also
+
+ sgList[0].Address =
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ commandList,
+ &length).LowPart;
+
+ //
+ // ScsiPortGetPhysicalAddress only accepts certain virtual addresses,
+ // so use the commandList and then increment over to the second s/g
+ // descriptor where the structure for the flush/disable command is
+ // located.
+ //
+ // Note that since it is difficult to allocate nonpaged memory at this
+ // level of the driver, and the command has 510 bytes of reserved
+ // area in the structure then memory will be retrieved by the controller
+ // that is past the end of the defined commandlist allocated memory.
+ // This will not be a problem unless the memory extends beyond the
+ // actual physical end of memory in the machine.
+ //
+ // The IDA-2 controller requires a multiple of 512 for the length so
+ // to avoid code that is controller dependent just use 512 that is
+ // accepted by all controllers. This command returns an BAD REQUEST
+ // when issued to IDA controllers since those controllers have no
+ // memory on the board.
+ //
+
+ sgList[0].Address += (sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR));
+
+ sgList[0].Length = 512;
+ commandList->RequestHeader.BlockNumber = 0;
+ commandList->RequestHeader.ScatterGatherCount=1;
+
+ //
+ // Build physical address translation list entry.
+ //
+
+ commandList->CommandListSize = (sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR));
+}
+
+
+ULONG
+IdaFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function fills in the configuration information structure
+
+Arguments:
+
+ HwDeviceExtension - Supplies a pointer to the device extension.
+ Context - Supplies adapter initialization structure.
+ BusInformation - Unused.
+ ArgumentString - Unused.
+ ConfigInfo - Pointer to the configuration information structure.
+ Again - Indicates that system should continue search for adapters.
+
+Return Value:
+
+ SP_RETURN_FOUND - Indicates adapter found.
+ SP_RETURN_NOT_FOUND - Indicates adapter not found.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PACCESS_RANGE accessRange;
+ DebugPrint((9,"&deviceExtension=%x\n",&deviceExtension));
+ DebugPrint((9,"&deviceExtension->PCIoff=%x\n",&deviceExtension->PCIoff));
+
+ //
+ // Get access range.
+ //
+
+ accessRange = &((*(ConfigInfo->AccessRanges))[0]);
+
+ if (accessRange->RangeLength == 0) {
+
+ if (!SearchEisaBus(HwDeviceExtension, Context, ConfigInfo)) {
+
+ //
+ // Tell system nothing was found and not to call again.
+ //
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ }
+
+ //
+ // Get system-mapped controller address.
+ //
+
+ deviceExtension->Bmic =
+ ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ accessRange->RangeStart,
+ accessRange->RangeLength,
+ (BOOLEAN) !accessRange->RangeInMemory);
+
+ //
+ // Complete description of controller.
+ //
+
+ ConfigInfo->MaximumTransferLength = (ULONG)-1;
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+
+ //
+ // Get noncached extension for identify requests.
+ //
+
+ deviceExtension->EisaId =
+ ScsiPortReadPortUlong(&deviceExtension->Bmic->BoardId);
+
+ if ((deviceExtension->EisaId & IDA_EISA_ID_MASKID_LOW) >=
+ (IDA_EISA_ID_DAZZLER & IDA_EISA_ID_MASKID_LOW)) {
+
+ deviceExtension->HBAConfiguration.bHBAModel = IDA_EISA_DAZZLER;
+
+ deviceExtension->eisapci =
+ (PEISAPCI_CONTROLLER)(((ULONG)deviceExtension->Bmic & 0xf000));
+
+ DebugPrint((9,"Found EISA DAZZLER: deviceExtension->eisapci=%x\n",
+ deviceExtension->eisapci));
+
+ ConfigInfo->MaximumNumberOfTargets = 32;
+ } else {
+ deviceExtension->HBAConfiguration.bHBAModel = IDA_BASE_CONTROLLER;
+ }
+
+ //
+ // Setup some vars needed for the IDENTIFY commands
+ //
+
+ deviceExtension->IrqLevel = (UCHAR)ConfigInfo->BusInterruptLevel;
+ deviceExtension->SectorShift = 9;
+
+ deviceExtension->IdentifyBuffer =
+ ScsiPortGetUncachedExtension(deviceExtension,
+ ConfigInfo,
+ 512);
+ ConfigInfo->CachesData = TRUE;
+
+ deviceExtension->HBAConfiguration.HBAIoBusData.usEisaSlot =
+ (USHORT)ConfigInfo->SlotNumber;
+
+ deviceExtension->BaseIOAddress = ConfigInfo->SlotNumber * 0x1000;
+ deviceExtension->HBAConfiguration.bHBAIoBusType = EISA_BUS;
+
+ //
+ // Tell system to look for more adapters.
+ //
+
+ *Again = TRUE;
+
+ return SP_RETURN_FOUND;
+
+} // end IdaFindAdapter()
+
+
+ULONG
+BuildCIMList(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a command list suitable for submission to the
+ Compaq IDA controller, from an SRB.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ Srb - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCOMMAND_LIST commandList = Srb->SrbExtension;
+ PUCHAR dataPointer;
+ ULONG physicalAddress;
+ ULONG bytesLeft;
+ ULONG descriptor;
+ ULONG length;
+ ULONG bufferOffset;
+ ULONG status;
+ PSRB_IO_CONTROL pSrb;
+ PSCSI_PASSTHRU scsipass;
+
+ //
+ // Save SRB address for interrupt routine.
+ //
+
+ commandList->SrbAddress = Srb;
+
+ //
+ // Set up Command List Header.
+ //
+
+ commandList->CommandListHeader.LogicalDriveNumber = Srb->TargetId;
+ commandList->CommandListHeader.RequestPriority = CL_NORMAL_PRIORITY;
+
+ commandList->CommandListHeader.Flags =
+ CL_FLAGS_NOTIFY_LIST_COMPLETE + CL_FLAGS_NOTIFY_LIST_ERROR;
+
+ commandList->RequestHeader.NextRequestOffset = 0;
+ commandList->Flags = 0;
+ commandList->RequestHeader.ErrorCode = 0;
+ commandList->RequestHeader.Reserved = 0;
+ commandList->RequestHeader.BlockCount = 0;
+ commandList->RequestHeader.BlockNumber = 0;
+
+ status = CPQ_CIM_ERROR;
+ pSrb = (PSRB_IO_CONTROL)Srb->DataBuffer;
+
+ switch (pSrb->ControlCode) {
+ case CPQ_IOCTL_PASSTHROUGH:
+ {
+ PMAP_PARAMETER_PACKET pParmPkt = (PMAP_PARAMETER_PACKET)
+ (((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+
+ commandList->CommandListHeader.LogicalDriveNumber = pParmPkt->TargetId;
+ commandList->RequestHeader.BlockCount = pParmPkt->BlockCount;
+ commandList->RequestHeader.BlockNumber = pParmPkt->BlockNumber;
+ commandList->RequestHeader.CommandByte = pParmPkt->IdaLogicalCommand;
+
+ //
+ // Build scatter/gather descriptor list.
+ //
+
+ descriptor = 0;
+ bufferOffset = sizeof(SRB_IO_CONTROL) + sizeof(MAP_PARAMETER_PACKET);
+ dataPointer = (PUCHAR)Srb->DataBuffer + bufferOffset;
+ bytesLeft = Srb->DataTransferLength - bufferOffset -
+ sizeof(IDA_ERROR_BITS);
+
+ do {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length)
+ );
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ //
+ // Fill in descriptor.
+ //
+
+ commandList->SgDescriptor[descriptor].Address = physicalAddress;
+ commandList->SgDescriptor[descriptor].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = dataPointer + length;
+ bytesLeft -= length;
+ descriptor++;
+
+ } while (bytesLeft);
+
+ //
+ // Calculate size of command list.
+ //
+
+ commandList->RequestHeader.ScatterGatherCount=(UCHAR)descriptor;
+ commandList->CommandListSize = (sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SG_DESCRIPTOR) *
+ descriptor);
+
+ status = CPQ_CIM_CMDBUILT;
+ break;
+ }
+
+ case CPQ_IOCTL_SCSIPASSTHROUGH:
+
+ //
+ // Build scatter/gather descriptor list.
+ //
+
+ descriptor = 0;
+
+ bufferOffset = (sizeof(SRB_IO_CONTROL) +
+ sizeof(SCSI_PASSTHRU) +
+ sizeof(SCSI_BUFFER_HEADER));
+
+ dataPointer = (PUCHAR)Srb->DataBuffer + bufferOffset;
+ bytesLeft = Srb->DataTransferLength - bufferOffset;
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length)
+ );
+ //
+ // get to the scsi cdb area, and then copy to the end of the cmdlist
+ // which is after the first s/g descriptor.
+ // modify to move after the last USED s/g area when more than 1 s/g
+ // functions in the controller f/w.
+ //
+
+ scsipass = (PSCSI_PASSTHRU)(((PUCHAR)Srb->DataBuffer +
+ sizeof(SRB_IO_CONTROL)));
+ IdaMoveMemory((PUCHAR)&commandList->SgDescriptor[1].Length,
+ (PUCHAR)scsipass,
+ sizeof(SCSI_PASSTHRU_HEADER) +
+ scsipass->scsi_header.cdb_length
+ );
+
+ bufferOffset = (sizeof(SG_DESCRIPTOR) +
+ sizeof(COMMAND_LIST_HEADER) +
+ sizeof(REQUEST_HEADER) +
+ sizeof(SCSI_PASSTHRU_HEADER) +
+ scsipass->scsi_header.cdb_length);
+
+ //
+ // If length of physical memory is less than needed space
+ // attempt to use nonpaged memory left in the command list
+ // else return error since allocating memory is not possible
+ // under the miniport design.
+ //
+
+ if (length < bytesLeft) {
+
+ if (( (MAXIMUM_SG_DESCRIPTORS * sizeof(SG_DESCRIPTOR)) -
+ sizeof(SG_DESCRIPTOR) -
+ sizeof(SCSI_PASSTHRU)) < bytesLeft) {
+
+ DebugPrint((3,
+ "BuildCIMList(): Returning CPQ_SCSI_ERR_NONCONTIGUOUS\n"));
+
+ pSrb->ReturnCode = CPQ_SCSI_ERR_NONCONTIGUOUS;
+ return(CPQ_CIM_NONCONTIGUOUS);
+ }
+
+ //
+ // Get the physical address of the start of the command list and then
+ // increment to the first non-used byte in the s/g descriptor list.
+ // There are limitations on what physical addresses can be obtained
+ // from the ScsiPort calls so use what we know is nonpaged memory.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ commandList,
+ &length)
+ );
+
+ physicalAddress += bufferOffset;
+
+ //
+ // set BlockNumber to flag that a copy from end of commandList is needed
+ // when the request is completed.
+ //
+
+ commandList->RequestHeader.BlockNumber = 1;
+ }
+
+ commandList->RequestHeader.CommandByte = RH_COMMAND_SCSI_PASS_THRU;
+ commandList->CommandListSize = (USHORT)bufferOffset;
+ commandList->SgDescriptor[descriptor].Address = physicalAddress;
+ commandList->SgDescriptor[descriptor].Length = bytesLeft;
+ commandList->RequestHeader.ScatterGatherCount = 1;
+ commandList->CommandListHeader.LogicalDriveNumber = 0;
+
+ status = CPQ_CIM_CMDBUILT;
+ break;
+
+ default:
+
+ DebugPrint((1,
+ "BuildCIMList(): Returning CPQ_SCSI_ERR_BAD_CNTL_CODE\n"));
+ pSrb->ReturnCode = CPQ_SCSI_ERR_BAD_CNTL_CODE;
+ status = CPQ_CIM_ERROR;
+ break;
+ }
+
+ return(status);
+
+} // end BuildCIMList()
+
+VOID
+IdaMoveMemory(
+ OUT PUCHAR pDestination,
+ IN PUCHAR pSource,
+ IN ULONG ulLength
+ )
+
+{
+ while (ulLength--)
+ *pDestination++ = *pSource++;
+ return;
+}
+
+BOOLEAN
+IdaStrCmp(
+ IN PUCHAR p1,
+ IN PUCHAR p2
+ )
+{
+ ULONG count=0;
+ ULONG p1count=0;
+ ULONG p2count=0;
+
+ //
+ // Get count of number of bytes in first
+ // Get count for second
+ // Perform while loop until out of greater number of bytes.
+ //
+
+ while ((p1[count] < 0x7f) && (p1[count] > 0x1f))
+ count++;
+
+ p1count = count;
+
+ while ((p2[count] < 0x7f) && (p2[count] > 0x1f))
+ count++;
+
+ p2count = count;
+
+ if (p1count != p2count)
+ return(TRUE);
+
+ count = p2count;
+
+ while (count) {
+ if (p1[count-1] != p2[count-1])
+ return(TRUE);
+ count--;
+ }
+
+ return(FALSE);
+
+}
+
+
+// Device extension global variable. This variable is needed for the
+// pci_bios function since there is no way to pass in this value. The
+// ScsiPortGetBusData and ScsiPortSetBusDataByOffset require a pointer
+// to the device extension as an argument to the function.
+
+STATIC PVOID gpDeviceExtension = NULL;
+
+//
+// Internal module function prototypes
+//
+
+STATIC
+ULONG
+GetPciSpecifics(
+ IN OUT PVOID pDeviceExtension,
+ IN OUT PIDA_CONTEXT pIDAContext,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo,
+ IN PPCI_SLOT_NUMBER pPciSlotNumber
+ );
+
+STATIC
+ULONG
+GetPciResources(
+ IN PVOID pDeviceExtension,
+ IN PPCI_COMMON_CONFIG pPciConfigHeader,
+ IN ULONG ulPciSlotNumber,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo
+ );
+
+
+
+ULONG
+IDAFindPci(
+ IN OUT PVOID pDeviceExtension,
+ IN OUT PVOID pContext,
+ IN PVOID pBusInformation,
+ IN PCHAR pArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo,
+ OUT PBOOLEAN pAgain
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the SCSI port driver to find SMART-2/P
+ controllers on the system's PCI buses. This routine searches only
+ the input PCI bus number in the port configuration information. If
+ a controller is found, the function fills out the controller's resource
+ requirements in the port configuration information and begins the
+ initialization process for the controller.
+
+
+Arguments:
+
+ pDeviceExtension - pointer to the miniport driver's per-controller
+ storage area
+ pContext - pointer to the context value passed to ScsiPortInitialize()
+ pBusInformation - pointer to bus type specific information
+ pArgumentString - pointer to null-terminated ASCII string
+ pConfigInfo - pointer to SCSI port configuration information
+
+
+Return Values:
+
+ pDeviceExtension - Minport driver's per-controller storage area
+ pContext - Context value passed to ScsiPortInitialize()
+ pConfigInfo - pointer to SCSI port configuration information
+ pAgain - Indicates to call function again to find more controllers.
+
+
+ Function Return Values:
+
+ SP_RETURN_FOUND - Indicates a host adapter was found and the configuration
+ information was successfully determined.
+
+ SP_RETURN_ERROR - Indicates a host adapter was found but an error occurred
+ obtaining the configuration information.
+
+ SP_RETURN_NOT_FOUND - Indicates no host adapter was found for the supplied
+ configuration information.
+
+ SP_RETURN_BAD_CONFIG - Indicates the supplied configuration information
+ was invalid.
+
+-- */
+
+{
+ BYTE bDeviceNumber;
+ BYTE bFunctionNumber;
+ BYTE bStartDeviceNumber;
+ BYTE bStartFunctionNumber;
+ PCI_SLOT_NUMBER PciSlotNumber;
+ PIDA_CONTEXT pIDAContext = pContext;
+ PCI_COMMON_CONFIG PciConfigHeader;
+ ULONG ulBytes;
+ ULONG ulInitStatus;
+ ULONG ulTmp1;
+ ULONG ulTmp2;
+
+
+ UNREFERENCED_PARAMETER(pBusInformation);
+ UNREFERENCED_PARAMETER(pArgumentString);
+
+
+ DebugPrint((4, "\nDAZZLER: Enter function IDAFindPci.\n"));
+
+ //
+ // Set the input pAgain argument to TRUE. This ensures that the function
+ // will be called for every PCI bus in the system.
+ //
+
+ *pAgain = TRUE;
+
+ // Clear the slot number.
+
+ PciSlotNumber.u.AsULONG = 0;
+
+
+ // Set the initial search starting numbers.
+
+ bStartDeviceNumber = pIDAContext->PciAddress.bDeviceNumber;
+ bStartFunctionNumber = pIDAContext->PciAddress.bFunctionNumber;
+
+ DebugPrint((4, "DAZZLER: Beginning search on system PCI bus %u.\n",
+ pConfigInfo->SystemIoBusNumber));
+
+
+ // Look at each device.
+
+ for (bDeviceNumber = bStartDeviceNumber;
+ bDeviceNumber < PCI_MAX_DEVICES;
+ bDeviceNumber++ ) {
+
+ // Set the device number in the PCI slot number.
+
+ PciSlotNumber.u.bits.DeviceNumber = bDeviceNumber;
+
+ // Look at each function of the device.
+
+ for (bFunctionNumber = bStartFunctionNumber;
+ bFunctionNumber < PCI_MAX_FUNCTION;
+ bFunctionNumber++) {
+ // Set the function number in the PCI slot number.
+
+ PciSlotNumber.u.bits.FunctionNumber = bFunctionNumber;
+
+ // Get the PCI configuration data for the slot.
+
+ DebugPrint( (4, "DAZZLER: Searching device %#x, function %x.\n",
+ bDeviceNumber, bFunctionNumber) );
+
+ ulBytes = ScsiPortGetBusData(pDeviceExtension,
+ PCIConfiguration,
+ pConfigInfo->SystemIoBusNumber,
+ PciSlotNumber.u.AsULONG,
+ &PciConfigHeader,
+ PCI_COMMON_HDR_LENGTH);
+
+ if (ulBytes == 0) {
+ // Out of PCI data for this bus.
+
+ DebugPrint((4, "DAZZLER: No more PCI devices on bus!\n"));
+
+ pIDAContext->PciAddress.bDeviceNumber = 0;
+ pIDAContext->PciAddress.bFunctionNumber = 0;
+
+ return (SP_RETURN_NOT_FOUND);
+ }
+
+ // Check for a valid vendor ID.
+
+#ifdef DBG
+ if (PciConfigHeader.VendorID != PCI_INVALID_VENDORID) {
+
+ // print out the PciConfigHeader
+
+ DebugPrint((4,
+ "PciConfigHeader: VendorId=%x DeviceId=%x Command=%x Status=%x\n"
+ ,PciConfigHeader.VendorID,
+ PciConfigHeader.DeviceID,
+ PciConfigHeader.Command) );
+
+ DebugPrint((4,
+ "RevisionID=%x ProgIf=%x SubClass=%x BaseClass=%x CacheLineSize=%x\n",
+ PciConfigHeader.RevisionID,
+ PciConfigHeader.ProgIf,
+ PciConfigHeader.SubClass,
+ PciConfigHeader.BaseClass,
+ PciConfigHeader.CacheLineSize) );
+
+ DebugPrint((4,"LatencyTimer=%x HeaderType=%x BIST=%x\n",
+ PciConfigHeader.LatencyTimer,
+ PciConfigHeader.HeaderType,
+ PciConfigHeader.BIST) );
+ }
+#endif
+
+ if (PciConfigHeader.VendorID == PCI_INVALID_VENDORID) {
+ // No PCI device or no more functions on the current device.
+ // Go to the next device.
+
+ break;
+ }
+
+
+ // PCI controller found. Next check to see if it is one of the
+ // controllers being searched for.
+
+ if ((PciConfigHeader.VendorID ==
+ pIDAContext->PciIdentifier.usVendorID) &&
+ (PciConfigHeader.DeviceID ==
+ pIDAContext->PciIdentifier.usDeviceID)) {
+ DebugPrint( (4, "DAZZLER: Found PCI controller.\n") );
+
+ // Check if the controller is enabled.
+
+ if ((PciConfigHeader.Command & PCI_ENABLE_IO_SPACE) &&
+ (PciConfigHeader.Command & PCI_ENABLE_MEMORY_SPACE)) {
+ DebugPrint( (4, "DAZZLER: Controller is enabled.\n") );
+
+ //
+ // Get PCI Id placed in offset 0x2c and place into the
+ // device extension EisaId.
+ //
+
+// ulTmp1 = ulTmp2 = PciConfigHeader.u.type0.Reserved1[1];
+ ulTmp1 = ulTmp2 = ((((ULONG) PciConfigHeader.u.type0.SubSystemID) << 16) |
+ PciConfigHeader.u.type0.SubVendorID);
+
+ // Fix it because the bytes are swapped
+
+ ulTmp1 &= 0xff00ff00;
+ ulTmp2 &= 0x00ff00ff;
+
+ ulTmp1 = ulTmp1 >> 8;
+ ulTmp2 = ulTmp2 << 8;
+
+ ((PDEVICE_EXTENSION)pDeviceExtension)->EisaId = ulTmp1 | ulTmp2;
+
+ // Set starting address for the next search.
+
+ pIDAContext->PciAddress.bDeviceNumber = bDeviceNumber;
+ pIDAContext->PciAddress.bFunctionNumber = bFunctionNumber + 1;
+
+
+ // Get the PCI resource requirements for the controller.
+
+ ulInitStatus = GetPciResources(pDeviceExtension,
+ &PciConfigHeader,
+ PciSlotNumber.u.AsULONG,
+ pConfigInfo);
+
+ if (ulInitStatus != SP_RETURN_FOUND) {
+
+ DebugPrint((0,
+ "DAZZLER: Could not get PCI resources for controller!\n"));
+
+ return (ulInitStatus);
+ }
+
+ // Get the PCI specifics for the controller.
+
+ ulInitStatus = GetPciSpecifics(pDeviceExtension,
+ pIDAContext,
+ pConfigInfo,
+ &PciSlotNumber);
+
+ if (ulInitStatus != SP_RETURN_FOUND) {
+ DebugPrint((0, "DAZZLER: Could not get PCI specifics for controller!\n") );
+ }
+
+ return (ulInitStatus);
+
+ } else {
+ DebugPrint( (4, "DAZZLER: Controller is disabled.\n") );
+ continue;
+ }
+
+ } // end if ((PciConfigHeader.VendorID == ...) &&
+
+
+ } // end for (bFunctionNumber = bStartFunctionNumber; ...)
+
+
+ // Reset the initial starting function number.
+
+ bStartFunctionNumber = 0;
+
+ } // end for (bDeviceNumber = bStartDeviceNumber; ...)
+
+
+ // A controller was not found.
+
+ DebugPrint( (4,
+ "DAZZLER: Failed to find any PCI controllers this pass.\n") );
+
+ pIDAContext->PciAddress.bDeviceNumber = 0;
+ pIDAContext->PciAddress.bFunctionNumber = 0;
+
+ return (SP_RETURN_NOT_FOUND);
+
+} // end IDAFindPci()
+
+
+
+STATIC
+ULONG
+GetPciResources(
+ IN PVOID pDeviceExtension,
+ IN PPCI_COMMON_CONFIG pPciConfigHeader,
+ IN ULONG ulPciSlotNumber,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo
+ )
+
+
+/*++
+
+Routine Description:
+
+ This routine gets the resources required by the input PCI controller.
+
+
+Arguments:
+
+ pDeviceExtension - pointer to the miniport driver's per-controller
+ storage area
+ pPciConfigHeader - pointer to the controller's PCI configuration header
+ ulPciSlotNumber - the PCI controller's address represented as a ULONG
+ pConfigInfo - pointer to SCSI port configuration information
+
+
+Return Values:
+
+ pConfigInfo - pointer to SCSI port configuration information. The access
+ range elements of the structure are filled in with the resources
+ required by the controller.
+
+ Function Return Values:
+
+ SP_RETURN_FOUND - Used to indicate that the HBA was successfully
+ initialized.
+
+ SP_RETURN_ERROR - Used to indicate that the HBA could not be properly
+ initilaized.
+
+-- */
+
+{
+ PACCESS_RANGE pAccessRange;
+ PCI_COMMON_CONFIG PciTmpCfgHdr;
+ ULONG ulAddressSpaceMask = 0xFFFFFFFF;
+ ULONG ulAddressSpace, ulAddressLength, ulBytes;
+ USHORT i;
+
+
+ DebugPrint( (2, "\nDAZZLER: Enter function GetPciResources.\n") );
+
+
+ // Verify the number of available access ranges.
+
+ if (pConfigInfo->NumberOfAccessRanges > IDA_PCI_NUM_ACCESS_RANGES) {
+
+ DebugPrint((0,
+ "DAZZLER: # of access ranges invalid for PCI controller.\n"));
+
+ return (SP_RETURN_ERROR);
+ }
+
+
+ // Get the resources required for each PCI base address.
+
+ for (i = 0; i < IDA_PCI_NUM_ACCESS_RANGES; i++) {
+ // Get pointer to the access range element to fill out.
+
+ pAccessRange = &((*(pConfigInfo->AccessRanges))[i]);
+
+
+ // Check to see if the PCI base address is memory or I/O.
+
+ if (pPciConfigHeader->u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_SPACE) {
+
+ // Address is an I/O address.
+
+ pAccessRange->RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(pPciConfigHeader->
+ u.type0.BaseAddresses[i] &
+ ~PCI_ADDRESS_IO_SPACE);
+
+ pAccessRange->RangeInMemory = FALSE;
+ } else {
+ // Address is a memory address.
+
+ ASSERT((pPciConfigHeader->u.type0.BaseAddresses[i] &
+ PCI_ADDRESS_MEMORY_TYPE_MASK) & PCI_TYPE_32BIT);
+
+ pAccessRange->RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(pPciConfigHeader->
+ u.type0.BaseAddresses[i] &
+ 0xfffffff0);
+
+ pAccessRange->RangeInMemory = TRUE;
+
+ DebugPrint((4, "pAccessRange->RangeStart.Hi/Low=%x %x ->RangeLength=%x\n",
+ pAccessRange->RangeStart.HighPart,pAccessRange->
+ RangeStart.LowPart,
+ pAccessRange->RangeLength));
+ }
+
+
+ // Get the amount of address space required. This is done by writing all
+ // 1's to the register and then reading the value back. The device will
+ // return 0's in all don't care bits. The first signficant bit set beyond
+ // those used to indicate memory or I/O determines the address space
+ // required. Finally, the register is restored with the original address.
+
+ ulBytes = ScsiPortSetBusDataByOffset(pDeviceExtension, PCIConfiguration,
+ pConfigInfo->SystemIoBusNumber,
+ ulPciSlotNumber,
+ (PVOID) &ulAddressSpaceMask,
+ FIELD_OFFSET(PCI_COMMON_CONFIG,
+ u.type0.BaseAddresses[i]),
+ sizeof(ULONG)
+ );
+
+ if (ulBytes == 0) {
+ DebugPrint((0,
+ "DAZZLER: Could not set PCI slot information for slot %u.\n",
+ ulPciSlotNumber));
+
+ return (SP_RETURN_ERROR);
+ }
+
+
+ // Read the value back.
+
+ ulBytes = ScsiPortGetBusData( pDeviceExtension,
+ PCIConfiguration,
+ pConfigInfo->SystemIoBusNumber,
+ ulPciSlotNumber,
+ &PciTmpCfgHdr,
+ PCI_COMMON_HDR_LENGTH );
+
+ if (ulBytes == 0) {
+
+ DebugPrint((0,
+ "DAZZLER: Could not get PCI information for slot %u.\n",
+ ulPciSlotNumber)
+ );
+
+ return(SP_RETURN_ERROR);
+ }
+
+
+ // Determine the space required by finding the first bit set.
+
+ ulAddressSpace = PciTmpCfgHdr.u.type0.BaseAddresses[i];
+ ulAddressLength = 1 << ((ulAddressSpace & PCI_ADDRESS_IO_SPACE) ? 2 : 4);
+
+ while (!(ulAddressSpace & ulAddressLength) && ulAddressLength) {
+ ulAddressLength <<= 1;
+ }
+
+ // Set the access range length.
+
+ pAccessRange->RangeLength = ulAddressLength;
+
+ DebugPrint((4,
+ "pAccessRange->RangeStart.Hi/Low=%x %x ->RangeLength=%x\n",
+ pAccessRange->RangeStart.HighPart,pAccessRange->
+ RangeStart.LowPart,
+ pAccessRange->RangeLength)
+ );
+
+ // Reset the base address register to its original value.
+
+ ulBytes = ScsiPortSetBusDataByOffset(pDeviceExtension,
+ PCIConfiguration,
+ pConfigInfo->SystemIoBusNumber,
+ ulPciSlotNumber,
+ (PVOID) &pPciConfigHeader->
+ u.type0.BaseAddresses[i],
+ FIELD_OFFSET(PCI_COMMON_CONFIG,
+ u.type0.BaseAddresses[i]),
+ sizeof(ULONG)
+ );
+
+ if (ulBytes == 0) {
+
+ DebugPrint((0, "DAZZLER: Could not set PCI information for slot %u.\n",
+ ulPciSlotNumber));
+
+ return(SP_RETURN_ERROR);
+ }
+
+ } // end for (i = 0;...)
+
+
+ // Set the IRQ information in the port configuration data structure.
+
+ pConfigInfo->BusInterruptLevel = pPciConfigHeader->u.type0.InterruptLine;
+ pConfigInfo->InterruptMode = LevelSensitive;
+
+ // Return success.
+
+ return(SP_RETURN_FOUND);
+
+} // end GetPciResources
+
+
+
+
+STATIC
+ULONG
+GetPciSpecifics(
+ IN OUT PVOID pDeviceExtension,
+ IN OUT PIDA_CONTEXT pIDAContext,
+ IN OUT PPORT_CONFIGURATION_INFORMATION pConfigInfo,
+ IN PPCI_SLOT_NUMBER pPciSlotNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to complete initialization of the port configuration
+ information for the input controller. This function also begins the
+ configuration of the SMGR for the controller. Finally, the function makes
+ the call to initialize the controller.
+
+
+Arguments:
+
+ pDeviceExtension - Miniport driver's per-controller storage area
+ pIDAContext - Context value passed to ScsiPortInitialize()
+ pConfigInfo - pointer to SCSI port configuration information
+
+
+Return Values:
+
+ pDeviceExtension - Minport driver's per-controller storage area
+ pIDAContext - Context value passed to ScsiPortInitialize()
+ pConfigInfo - pointer to SCSI port configuration information
+
+
+ Function Return Values:
+
+ SP_RETURN_FOUND - Used to indicate that the HBA was successfully
+ initialized.
+
+ SP_RETURN_ERROR - Used to indicate that the HBA could not be properly
+ initilaized.
+
+-- */
+
+{
+ PACCESS_RANGE pAccessRange;
+ PDEVICE_EXTENSION pIDADeviceExtension = pDeviceExtension;
+ PVOID pBaseAddress, pIoAddress = NULL, pMemoryAddress = NULL;
+ ULONG ulInitStatus, ulPhysicalMemoryAddress;
+ USHORT i;
+
+
+ DebugPrint( (6, "Enter function GetPciSpecifics.\n") );
+
+
+ // Get and verify the access ranges and its length.
+
+ for (i = 0; i < IDA_PCI_NUM_ACCESS_RANGES - 1; i++) {
+ pAccessRange = &((*(pConfigInfo->AccessRanges))[i]);
+ ASSERT(pAccessRange->RangeLength != 0);
+
+ // Get the mapped system address.
+
+ pBaseAddress = ScsiPortGetDeviceBase(pDeviceExtension,
+ pConfigInfo->AdapterInterfaceType,
+ pConfigInfo->SystemIoBusNumber,
+ pAccessRange->RangeStart,
+ pAccessRange->RangeLength,
+ (BOOLEAN)!pAccessRange->RangeInMemory
+ );
+
+ if (pBaseAddress == NULL) {
+
+ DebugPrint( (0,
+ "DAZZLER: Error getting base addr. for PCI controller.\n"));
+
+ return (SP_RETURN_ERROR);
+ }
+
+
+ // Set the appropriate pointer to the mapped address.
+
+ if (pAccessRange->RangeInMemory) {
+ pMemoryAddress = pBaseAddress;
+
+ ulPhysicalMemoryAddress =
+ ScsiPortConvertPhysicalAddressToUlong( pAccessRange->RangeStart );
+
+ } else {
+ pIoAddress = pBaseAddress;
+ }
+
+ } // end for (i = 0;...)
+
+
+ // Debug checks
+
+ ASSERT(pIoAddress);
+ ASSERT(pMemoryAddress);
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller I/O base address = %0#10x\n",
+ pIoAddress)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller memory base address = %0#10x\n",
+ pMemoryAddress)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller physical memory address = %0#10x\n",
+ ulPhysicalMemoryAddress)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller bus number = %#x\n",
+ pConfigInfo->SystemIoBusNumber)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller device number = %#x\n",
+ pPciSlotNumber->u.bits.DeviceNumber)
+ );
+
+ DebugPrint((4,
+ "DAZZLER: PCI controller function number = %#x\n",
+ pPciSlotNumber->u.bits.FunctionNumber)
+ );
+
+ // Finish initalizing the port configuration information
+
+ pConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE;
+ pConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+ pConfigInfo->ScatterGather = TRUE;
+ pConfigInfo->Master = TRUE;
+ pConfigInfo->NumberOfBuses = 1;
+ pConfigInfo->Dma32BitAddresses = TRUE;
+ pConfigInfo->MaximumNumberOfTargets = 32;
+
+ //
+ // Setup some vars needed for the IDENTIFY commands
+ //
+
+ pConfigInfo->CachesData = TRUE;
+ pIDADeviceExtension->SectorShift = 9;
+ pIDADeviceExtension->IdentifyBuffer =
+ ScsiPortGetUncachedExtension(pDeviceExtension,
+ pConfigInfo,
+ 512);
+
+ // Fill in the HBA configuration data in the device extension.
+
+ if (pMemoryAddress) {
+
+ pIDADeviceExtension->HBAConfiguration.ulBaseIOAddress =
+ (ULONG)pMemoryAddress;
+
+ pIDADeviceExtension->CPFIFO =
+ (PULONG)((PUCHAR)pMemoryAddress+IDA_PCI_CPFIFO_OFFSET);
+
+ pIDADeviceExtension->CCFIFO =
+ (PULONG)((PUCHAR)pMemoryAddress+IDA_PCI_CCFIFO_OFFSET);
+
+ pIDADeviceExtension->InterruptMask =
+ (PULONG)((PUCHAR)pMemoryAddress+IDA_PCI_MASK_OFFSET);
+
+ pIDADeviceExtension->InterruptStatus = (PULONG)((PUCHAR)pMemoryAddress+
+ IDA_PCI_STATUS_OFFSET);
+
+ pIDADeviceExtension->InterruptPending = (PULONG)((PUCHAR)pMemoryAddress+
+ IDA_PCI_PENDING_OFFSET);
+
+ ulInitStatus = SP_RETURN_FOUND;
+ }
+
+ if (pIoAddress) {
+ pIDADeviceExtension->BaseIOAddress = (ULONG)pIoAddress;
+ }
+
+ pIDADeviceExtension->HBAConfiguration.bHBAModel = pIDAContext->bHBAModel;
+ pIDADeviceExtension->HBAConfiguration.bHBAIoBusType = PCI_BUS;
+
+ pIDADeviceExtension->HBAConfiguration.HBAIoBusData.PciAddress.
+ bPCIBusNumber = (BYTE)pConfigInfo->SystemIoBusNumber;
+
+ pIDADeviceExtension->HBAConfiguration.HBAIoBusData.PciAddress.
+ bDeviceNumber = (BYTE)pPciSlotNumber->u.bits.DeviceNumber;
+
+ pIDADeviceExtension->HBAConfiguration.HBAIoBusData.PciAddress.
+ bFunctionNumber = (BYTE)pPciSlotNumber->u.bits.FunctionNumber;
+
+ pIDADeviceExtension->HBAConfiguration.bNumScsiBuses =
+ pConfigInfo->NumberOfBuses;
+
+ DebugPrint((1,
+ "CCFIFO=0x%x CPFIFO=0x%x InterruptMask=0x%x InterruptStatus=0x%x InterruptPending=0x%x BaseIo=0x%x\n",
+ pIDADeviceExtension->CCFIFO,
+ pIDADeviceExtension->CPFIFO,
+ pIDADeviceExtension->InterruptMask,
+ pIDADeviceExtension->InterruptStatus,
+ pIDADeviceExtension->InterruptPending,
+ pIDADeviceExtension->BaseIOAddress )
+ );
+
+
+ if (ulInitStatus != SP_RETURN_FOUND) {
+
+ // Free the device base for this controller.
+
+ ScsiPortFreeDeviceBase(pDeviceExtension, pIoAddress);
+ ScsiPortFreeDeviceBase(pDeviceExtension, pMemoryAddress);
+
+ } // end if (ulInitStatus != SP_RETURN_FOUND)
+
+ return (ulInitStatus);
+
+} // end GetPciSpecifics()
+
+
+ULONG
+DriverEntry(
+ IN PVOID pDriverObject,
+ IN PVOID pArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point. This function initializes
+ the hardware initialization data structure and begins the process of
+ finding controllers that the driver supports.
+
+
+Arguments:
+
+ pDriverObject - Pointer to the driver's driver object.
+ pArgument2 - Pointer to driver's entry in the Registry.
+
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+-- */
+
+{
+ IDA_CONTEXT IDAContext;
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i, ulStatus, ulReturnStatus=0;
+ ULONG eisaSlotNumber;
+ UCHAR deviceId[8] = {'0', '0', '4', '0', '1', '1', '0', 'E'};
+
+ DebugPrint((0,"\n\nCompaq Disk Array Miniport Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = IdaInitialize;
+ hwInitializationData.HwResetBus = IdaResetBus;
+ hwInitializationData.HwStartIo = IdaStartIo;
+ hwInitializationData.HwInterrupt = IdaInterrupt;
+ hwInitializationData.HwFindAdapter = IdaFindAdapter;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize =
+ sizeof(DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize =
+ sizeof(LOGICAL_UNIT_EXTENSION);
+
+ //
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.NumberOfAccessRanges = 3;
+
+ //
+ // Ask for SRB extensions for command lists.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(COMMAND_LIST);
+
+ //
+ // Indicate that this controller supports multiple outstand
+ // requests to its devices.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // Set the context parameter to indicate that the search for controllers
+ // should start at the first EISA slot. This is only for a manual search
+ // by the miniport driver, if the system does not pass in predetermined
+ // configuration.
+ //
+
+ eisaSlotNumber = 0;
+
+ //
+ // Indicate EISA id.
+ //
+
+ hwInitializationData.DeviceId = &deviceId;
+ hwInitializationData.DeviceIdLength = 8;
+
+ //
+ // Call the system to search for this adapter.
+ //
+
+ ulReturnStatus = ScsiPortInitialize(pDriverObject, pArgument2,
+ &hwInitializationData,
+ &eisaSlotNumber
+ );
+
+ // Initialize hardware initialization data structure to zeroes.
+
+ for (i = 0; i < sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ // Fill in the hardware initialization data structure.
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ // Set driver entry points.
+
+ hwInitializationData.HwInitialize = IdaInitializePCI;
+ hwInitializationData.HwStartIo = IdaStartIo;
+ hwInitializationData.HwInterrupt = IdaInterrupt;
+ hwInitializationData.HwResetBus = IdaResetBus;
+ hwInitializationData.HwDmaStarted = NULL;
+ hwInitializationData.HwAdapterState = NULL;
+
+
+ // Specify size of extensions.
+
+ hwInitializationData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
+
+ hwInitializationData.SpecificLuExtensionSize =
+ sizeof(LOGICAL_UNIT_EXTENSION);
+
+ hwInitializationData.SrbExtensionSize = sizeof(COMMAND_LIST);
+
+
+ // Initialize other data.
+
+ hwInitializationData.MapBuffers = FALSE;
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+ hwInitializationData.TaggedQueuing = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.ReceiveEvent = FALSE;
+
+ //
+ // Indicate that this controller supports multiple outstanding
+ // requests to its devices.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ // Setup required values to find PCI Compaq 32-Bit Array controllers.
+
+ hwInitializationData.AdapterInterfaceType = PCIBus;
+ hwInitializationData.NumberOfAccessRanges = IDA_PCI_NUM_ACCESS_RANGES;
+ hwInitializationData.HwFindAdapter = IDAFindPci;
+
+ IDAContext.bHBAModel = IDA_PCI_DAZZLER;
+ IDAContext.PciAddress.bPCIBusNumber = 0;
+ IDAContext.PciAddress.bDeviceNumber = 0;
+ IDAContext.PciAddress.bFunctionNumber = 0;
+ IDAContext.PciIdentifier.usVendorID = IDA_PCI_COMPAQ_ID;
+ IDAContext.PciIdentifier.usDeviceID = IDA_PCI_DAZZLER_DEVICE_ID;
+
+
+ ulStatus = ScsiPortInitialize(pDriverObject,
+ pArgument2,
+ &hwInitializationData,
+ &IDAContext
+ );
+
+ DebugPrint((0, "DAZZLER: PCI search status = %0#10x\n", ulStatus));
+
+ ulReturnStatus = (ulReturnStatus < ulStatus) ? ulReturnStatus : ulStatus;
+
+ // Return the final status value.
+
+ DebugPrint( (4, "DAZZLER: Final status = %0#10x\n", ulReturnStatus) );
+
+ return (ulReturnStatus);
+
+} // end DriverEntry()
+
+VOID
+IdaDisableInts(
+ IN PDEVICE_EXTENSION pDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Called for SCSI inquiry processing (GetDiskIdentifyData) to eliminate
+ interupts generated at the controller. This was added to support
+ Online Blazer and the ability to recognize Logical Volumes that may
+ be added while the system is running. GetDiskIdentifyData submits
+ the inquiry packet and returns to Startio when this packet has been
+ processed by the controller. Interrupts at the adapter are temporarily
+ disabled because we must wait for completion and we want to get back
+ in a timely fashion.
+
+Arguments:
+
+ pDeviceExtension - pointer to adapter's device extension.
+
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = pDeviceExtension;
+ PULONG pIntMask;
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_PCI_DAZZLER) {
+
+ //
+ // we are looking at the Dazzler/P...use memapped io
+ //
+
+ pIntMask = deviceExtension->InterruptMask;
+ *pIntMask = 0L;
+ } else
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_EISA_DAZZLER
+ && !deviceExtension->PCIoff)
+
+ //
+ // we are dealing with Dazzler/E use mapped portio
+ //
+
+ ScsiPortWritePortUlong(&deviceExtension->eisapci->InterruptMask, 0L);
+ else {
+
+ //
+ // ida and prior adapter....BMIC interface
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->InterruptControl, 0);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SystemDoorBellMask, 0);
+ }
+
+} // end IdaDisableInts
+
+VOID
+IdaEnableInts(
+ IN PDEVICE_EXTENSION pDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Called for SCSI inquiry processing (GetDiskIdentifyData) to enable
+ interupts generated at the controller. This was added to support
+ Online Blazer and the ability to recognize Logical Volumes that may
+ be added while the system is running. GetDiskIdentifyData submits
+ the inquiry packet and returns to Startio when this packet has been
+ processed by the controller. Interrupts at the adapter are temporarily
+ disabled because we must wait for completion and we want to get back
+ in a timely fashion.
+
+Arguments:
+
+ pDeviceExtension - pointer to adapter's device extension.
+
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = pDeviceExtension;
+ PULONG pIntMask;
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_PCI_DAZZLER) {
+
+ //
+ // Dazzler/P...use memmapped io
+ //
+
+ pIntMask = deviceExtension->InterruptMask;
+ *pIntMask = 1L;
+ } else
+
+ if (deviceExtension->HBAConfiguration.bHBAModel == IDA_EISA_DAZZLER
+ && !deviceExtension->PCIoff)
+
+ //
+ // Dazzler/E...use 32bit port io
+ //
+
+ ScsiPortWritePortUlong(&deviceExtension->eisapci->InterruptMask, 1L);
+ else {
+
+ //
+ // ida and prior...use BMIC interface
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->InterruptControl, 1);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SystemDoorBellMask, 1);
+ }
+
+} // end IdaEnableInts
diff --git a/private/ntos/miniport/compaq/cpqarray.h b/private/ntos/miniport/compaq/cpqarray.h
new file mode 100644
index 000000000..843f67922
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqarray.h
@@ -0,0 +1,412 @@
+/*++
+
+Copyright (c) 1991-4 Microsoft Corporation
+
+Module Name:
+
+ cpqarray.h
+
+Abstract:
+
+ This file contains definitions of structures used to
+ communicate with the Compaq Intelligent Disk Array.
+
+Author:
+
+ Mike Glass (mglass)
+ Tom Bonola (Compaq)
+
+Notes:
+
+Revision History:
+
+--*/
+
+//
+// The Command List Header contiains information that applies to all
+// the Request Blocks in the Command List.
+//
+
+typedef struct _COMMAND_LIST_HEADER {
+
+ UCHAR LogicalDriveNumber;
+ UCHAR RequestPriority;
+ USHORT Flags;
+
+} COMMAND_LIST_HEADER, *PCOMMAND_LIST_HEADER;
+
+//
+// Request Priorities
+//
+
+#define CL_NORMAL_PRIORITY 0x02
+
+//
+// Flag word bit definitions
+//
+
+#define CL_FLAGS_NOTIFY_LIST_COMPLETE 0x0000
+#define CL_FLAGS_NOTIFY_REQUEST_COMPLETE 0x0001
+#define CL_FLAGS_NOTIFY_LIST_ERROR 0x0000
+#define CL_FLAGS_NOTIFY_REQUEST_ERROR 0x0002
+#define CL_FLAGS_ABORT_ON_ERROR 0x0004
+#define CL_FLAGS_ORDERED_REQUESTS 0x0008
+
+typedef struct _REQUEST_HEADER {
+
+ USHORT NextRequestOffset;
+ UCHAR CommandByte;
+ UCHAR ErrorCode;
+ ULONG BlockNumber;
+ USHORT BlockCount;
+ UCHAR ScatterGatherCount;
+ UCHAR Reserved;
+
+} REQUEST_HEADER, *PREQUEST_HEADER;
+
+//
+// Error code definitions
+//
+
+#define RH_SUCCESS 0x00
+#define RH_INVALID_REQUEST 0x10
+#define RH_REQUEST_ABORTED 0x08
+#define RH_FATAL_ERROR 0x04
+#define RH_RECOVERABLE_ERROR 0x02
+#define RH_WARNING 0x40
+#define RH_BAD_COMMAND_LIST 0x20
+
+//
+// Scatter/Gather descriptor definition
+//
+
+#define PAGE_SIZE (ULONG)0x1000
+#define MAXIMUM_SG_DESCRIPTORS 17
+#define MAXIMUM_TRANSFER_SIZE (MAXIMUM_SG_DESCRIPTORS - 1) * PAGE_SIZE
+
+typedef struct _SG_DESCRIPTOR {
+
+ ULONG Length;
+ ULONG Address;
+
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+//
+// Command List
+//
+
+typedef struct _COMMAND_LIST {
+
+ //
+ // Compaq RLH.
+ //
+
+ COMMAND_LIST_HEADER CommandListHeader;
+ REQUEST_HEADER RequestHeader;
+ SG_DESCRIPTOR SgDescriptor[MAXIMUM_SG_DESCRIPTORS];
+
+ //
+ // Next list entry
+ //
+
+ struct _COMMAND_LIST *NextEntry;
+
+ //
+ // SRB pointer
+ //
+
+ PSCSI_REQUEST_BLOCK SrbAddress;
+
+ //
+ // Request tracking flags
+ //
+
+ ULONG Flags;
+
+ //
+ // Command list size.
+ //
+
+ USHORT CommandListSize;
+
+} COMMAND_LIST, *PCOMMAND_LIST;
+
+//
+// Commands
+//
+
+#define RH_COMMAND_IDENTIFY_LOGICAL_DRIVES 0x10
+#define RH_COMMAND_IDENTIFY_CONTROLLER 0x11
+#define RH_COMMAND_IDENTIFY_LOGICAL_DRIVE_STATUS 0x12
+#define RH_COMMAND_READ 0x20
+#define RH_COMMAND_WRITE 0x30
+#define RH_COMMAND_SENSE_CONFIGURATION 0x50
+#define RH_COMMAND_SET_CONFIGURATION 0x51
+#define RH_COMMAND_FLUSH_DISABLE_CACHE 0xc2
+#define RH_COMMAND_SCSI_PASS_THRU 0x90
+
+//
+// Flag field bit definitions
+//
+
+#define CL_FLAGS_REQUEST_QUEUED 0x0001
+#define CL_FLAGS_REQUEST_STARTED 0x0002
+#define CL_FLAGS_REQUEST_COMPLETED 0x0004
+#define CL_FLAGS_IDENTIFY_REQUEST 0x0008
+
+//
+// Fixed Disk Parameter Table
+//
+
+#pragma pack(1)
+
+typedef struct _DISK_PARAMETER_TABLE {
+
+ USHORT MaximumCylinders; // BIOS translated
+ UCHAR MaximumHeads; // BIOS translated
+ UCHAR TranslationSignature;
+ UCHAR SectorsPerTrack; // physical characteristics
+ USHORT WritePrecompCylinder;
+ UCHAR MaximumECCBurst;
+ UCHAR DriveControl;
+ USHORT NumberOfCylinders; // physical characteristics
+ UCHAR NumberOfHeads; // physical characteristics
+ USHORT LandingZone;
+ UCHAR MaximumSectorsPerTrack; // BIOS translated
+ UCHAR CheckSum;
+
+} DISK_PARAMETER_TABLE, *PDISK_PARAMETER_TABLE;
+
+#define IDENTIFY_BUFFER_SIZE 512
+
+//
+// Identify Logical Drives
+//
+
+typedef struct _IDENTIFY_LOGICAL_DRIVE {
+
+ USHORT BlockLength;
+ ULONG NumberOfBlocks;
+ DISK_PARAMETER_TABLE ParameterTable;
+ UCHAR FaultToleranceType;
+ UCHAR Reserved[5];
+
+} IDENTIFY_LOGICAL_DRIVE, *PIDENTIFY_LOGICAL_DRIVE;
+
+//
+// Identify Controller information
+//
+
+typedef struct _IDENTIFY_CONTROLLER {
+
+ UCHAR NumberLogicalDrives;
+ ULONG ConfigurationSignature;
+ UCHAR FirmwareRevision[4];
+ UCHAR Reserved[247];
+
+} IDENTIFY_CONTROLLER, *PIDENTIFY_CONTROLLER;
+
+//
+// Set/Sense Configuration information
+//
+
+typedef struct _SENSE_CONFIGURATION {
+
+ ULONG ConfigurationSignature;
+ USHORT SiConfiguration;
+ USHORT OsConfiguration;
+ USHORT NumberPhysicalDrives;
+ USHORT PDrivesInLDrives;
+ USHORT FaultToleranceType;
+ UCHAR PhysicalDrive[16];
+ UCHAR LogicalDrive[16];
+ ULONG DriveAssignmentMap;
+ UCHAR Reserved[462];
+
+} SENSE_CONFIGURATION, *PCONFIGURATION;
+
+//
+// Fault Tolerance Type
+//
+
+#define FT_DATA_GUARD 0x0002
+#define FT_MIRRORING 0x0001
+#define FT_NONE_ 0x0000
+
+//
+// Drive Failure Assignment Map
+//
+
+typedef struct _DRIVE_FAILURE_MAP {
+
+ UCHAR LogicalDriveStatus;
+ UCHAR DriveFailureAssignmentMap[4];
+ UCHAR Reserved[251];
+
+} DRIVE_FAILURE_MAP, *PDRIVE_FAILURE_MAP;
+
+#pragma pack()
+
+typedef struct _MAILBOX {
+
+ ULONG Address;
+ USHORT Length;
+ UCHAR Status;
+ UCHAR TagId;
+
+} MAILBOX, *PMAILBOX;
+
+//
+// Command List Status bit definitions
+//
+
+#define CL_STATUS_LIST_COMPLETE 0x01
+#define CL_STATUS_NONFATAL_ERROR 0x02
+#define CL_STATUS_FATAL_ERROR 0x04
+#define CL_STATUS_ABORT 0x08
+
+//
+// 32-bit IDA Controller registers
+//
+
+typedef struct _IDA_CONTROLLER {
+
+ ULONG BoardId; // xC80
+ UCHAR Undefined[4]; // xC84
+ UCHAR Configuration; // xC88
+ UCHAR InterruptControl; // xC89
+ UCHAR Undefined1[2]; // xC8A
+ UCHAR LocalDoorBellMask; // xC8C
+ UCHAR LocalDoorBell; // xC8D
+ UCHAR SystemDoorBellMask; // xC8E
+ UCHAR SystemDoorBell; // xC8F
+ MAILBOX CommandListSubmit; // xC90
+ MAILBOX CommandListComplete; // xC98`
+ UCHAR Reserved[32]; // xCA0
+ UCHAR ControllerConfiguration; // xCC0
+
+} IDA_CONTROLLER, *PIDA_CONTROLLER;
+
+//
+// Controller bHBAModel definitions
+//
+#define IDA_UNDEFINED_CONTROLLER 0
+#define IDA_BASE_CONTROLLER 1
+#define IDA_PCI_DAZZLER 2
+#define IDA_EISA_DAZZLER 3
+
+//
+// DAZZLER PCI interface definitions for EISA I/O space
+//
+
+typedef struct _EISAPCI_CONTROLLER {
+
+ ULONG Timer; // x000
+ ULONG CPFIFO; // x004
+ ULONG CCFIFO; // x008
+ ULONG InterruptMask; // x00C
+ ULONG InterruptStatus; // x010
+ ULONG InterruptPending; // x014
+
+} EISAPCI_CONTROLLER, *PEISAPCI_CONTROLLER;
+
+#define IDA_PCI_TIMER_OFFSET 0
+#define IDA_PCI_CPFIFO_OFFSET 4
+#define IDA_PCI_CCFIFO_OFFSET 8
+#define IDA_PCI_MASK_OFFSET 12
+#define IDA_PCI_STATUS_OFFSET 16
+#define IDA_PCI_PENDING_OFFSET 20
+
+#define IDA_PCI_IRQ_DISABLE_MASK 0x00000000
+#define IDA_PCI_FIFO_NOT_EMPTY_MASK 0x00000001
+#define IDA_PCI_FIFO_NOT_FULL_MASK 0x00000002
+#define IDA_PCI_COMPLETION_STATUS_ACTIVE 0x00000001
+#define IDA_PCI_ISSUE_STATUS_CLEAR 0x00000002
+
+#define IDA_PCI_PHYS_ADDR_MASK 0xfffffffc
+#define IDA_PCI_COMPLETION_STATUS_MASK 0x00000003
+#define IDA_PCI_COMPLETION_ERROR 0x00000001
+
+#define IDA_PCI_COMPAQ_ID 0x00000E11
+#define IDA_PCI_DAZZLER_DEVICE_ID 0x0000AE10
+#define IDA_EISA_ID_MASKID_LOW 0xff000000
+
+#define IDA_PCI_NUM_ACCESS_RANGES 3
+
+typedef struct _PCI_IDENTIFIER {
+ USHORT usVendorID;
+ USHORT usDeviceID;
+} PCI_IDENTIFIER, *PPCI_IDENTIFIER;
+
+typedef struct _IDA_CONTEXT {
+ UCHAR bHBAModel;
+ USHORT usEisaSlot;
+ PCI_IDENTIFIER PciIdentifier;
+ PCI_ADDRESS PciAddress;
+} IDA_CONTEXT, *PIDA_CONTEXT;
+
+
+//
+// System Doorbell Interrupt Register bit definitions
+//
+
+#define SYSTEM_DOORBELL_COMMAND_LIST_COMPLETE 0x01
+#define SYSTEM_DOORBELL_SUBMIT_CHANNEL_CLEAR 0x02
+
+//
+// Local Doorbell Interrupt Register bit definitions
+//
+
+#define LOCAL_DOORBELL_COMMAND_LIST_SUBMIT 0x01
+#define LOCAL_DOORBELL_COMPLETE_CHANNEL_CLEAR 0x02
+
+//
+// Doorbell register channel clear bit
+//
+
+#define IDA_CHANNEL_CLEAR 0x01
+
+//
+// Interrupt Control register bit definitions
+//
+
+#define IDA_INTERRUPT_PENDING 0x02
+
+//
+// System doorbell register interrupt mask
+//
+
+#define IDA_COMPLETION_INTERRUPT_ENABLE 0x01
+
+//
+// Controller Configuration Register bit definitions
+//
+
+#define STANDARD_INTERFACE_ENABLE 0x01
+#define STANDARD_INTERFACE_SECONDARY_IO_ADDRESS 0x02
+#define BUS_MASTER_DISABLE 0x04
+#define SOFTWARE_RESET 0x08
+#define BUS_MASTER_INTERRUPT_11_ENABLE 0x10
+#define BUS_MASTER_INTERRUPT_10_ENABLE 0x20
+#define BUS_MASTER_INTERRUPT_14_ENABLE 0x40
+#define BUS_MASTER_INTERRUPT_15_ENABLE 0x80
+
+//
+// Disk configuration information
+//
+
+typedef struct _DISK_CONFIGURATION {
+
+ UCHAR NumberLogicalDrives;
+ IDENTIFY_LOGICAL_DRIVE LogicalDriveInformation[2];
+
+} DISK_CONFIGURATION, *PDISK_CONFIGURATION;
+
+//
+// structure for the flush/disable cache command
+//
+typedef struct _FLUSH_DISABLE {
+ USHORT disable_flag;
+ UCHAR reserved[30];
+} FLUSH_DISABLE, *PFLUSH_DISABLE;
+
diff --git a/private/ntos/miniport/compaq/cpqarray.rc b/private/ntos/miniport/compaq/cpqarray.rc
new file mode 100644
index 000000000..b6be0f39f
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqarray.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Compaq Disk Array Driver 2,01,01,001"
+#define VER_INTERNALNAME_STR "cpqarray.sys"
+#define VER_ORIGINALFILENAME_STR "cpqarray.sys"
+
+#include "common.ver"
+
+
diff --git a/private/ntos/miniport/compaq/cpqsczmp.h b/private/ntos/miniport/compaq/cpqsczmp.h
new file mode 100644
index 000000000..7c9198dc4
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqsczmp.h
@@ -0,0 +1,211 @@
+/*++
+
+Copyright Compaq Computer Corporation 1994. All Rights Reserved.
+
+
+Module Name:
+
+ CPQSCZMP.H
+
+
+Abstract:
+
+ This file contains data structures and definitions used by SCSI miniport
+ drivers that support Compaq Monitoring & Performance.
+
+
+Author:
+
+ Michael E. McGowen
+
+
+Revision History:
+
+ 1.00 MEM 04/01/94 Initial release.
+ 1.01 MEM 07/01/94 Added additional fields to HBA configuration.
+ 1.02 MEM 08/08/94 Changed IOCTL signature.
+
+
+-- */
+
+
+
+/**************************************************************************
+ *
+ * DATA TYPE PREFIX (Hungarian notation)
+ *
+ * f : BOOL (flag)
+ * ch : CHAR (signed 8 bit)
+ * s : SHORT (signed 16 bit)
+ * l : LONG (signed 32 bit)
+ * uch : UCHAR (unsigned 8 bit)
+ * us : USHORT (unsigned 16 bit)
+ * ul : ULONG (unsigned 32 bit)
+ * b : BYTE (unsigned 8 bit)
+ * sz : CHAR[] (ASCIIZ array of char)
+ * fb : UCHAR (bitmapped byte of flags)
+ * fs : USHORT (bitmapped short of flags)
+ * fl : ULONG (bitmapped long of flags)
+ * r : REAL (real number, single precision 32bit)
+ * rd : DOUBLE (real number, double precision 64bit)
+ * pfn : pointer to function
+ * x : x coordinate
+ * y : y coordinate
+ * sel : Segment selector
+ * p : Pointer (pch, pus, psz, ...)
+ * np : near pointer...
+ * a : array (ach, aus, asz, ...)
+ * i : index to array (ich, ius, ...)
+ * c : count (cb, cus, ...)
+ * d : delta ,difference (dx, dy, ...)
+ * h : handle
+ * id : ID
+ * g : Global variable
+ *
+ *************************************************************************/
+
+#ifndef _INCL_CPQSCZMP_H_
+#define _INCL_CPQSCZMP_H_
+
+
+// Common defines
+
+#define MAX_DRIVER_DESC_SIZE 81
+#define MAX_DRIVER_NAME_SIZE 13
+
+
+// HBA I/O Bus Types
+
+#define ISA_BUS 1
+#define EISA_BUS 2
+#define PCI_BUS 3
+#define PCMCIA_BUS 4
+
+
+// IOCTL defines supporting Compaq M&P
+
+#define CPQ_SCSI_IOCTL_SIGNATURE "SCSIM&P"
+#define CPQ_SCSI_IOCTL_TIMEOUT 10
+
+
+// IOCTL control codes
+
+#define CPQ_SCSI_IOCTL_GET_DRIVER_INFO 1
+#define CPQ_SCSI_IOCTL_GET_HBA_CONFIG 2
+#define CPQ_SCSI_IOCTL_GET_SCSI_BUS_DATA 3
+#define CPQ_SCSI_IOCTL_GET_DEVICE_DATA 4
+#define CPQ_SCSI_IOCTL_GET_DEVICE_ERRORS 5
+#define CPQ_SCSI_IOCTL_GET_AND_CLEAR_DEVICE_DATA 6
+#define CPQ_SCSI_IOCTL_GET_AND_CLEAR_DEVICE_ERRORS 7
+
+
+// IOCTL return codes
+
+#define CPQ_SCSI_ERR_OK 0
+#define CPQ_SCSI_ERR_FAILED 1
+#define CPQ_SCSI_ERR_BAD_CNTL_CODE 2
+#define CPQ_SCSI_ERR_REVISION 3
+#define CPQ_SCSI_ERR_MORE_DATA 4
+#define CPQ_SCSI_ERR_INVALID_DEVICE 5
+
+
+// Macros
+
+#define INCREMENT_ULONG(ulValue) \
+ { \
+ if (ulValue < 0xFFFFFFFE) \
+ ulValue++; \
+ } \
+
+
+// Data structures
+
+typedef struct _SCSI_MINIPORT_DRIVER_INFO {
+ CHAR szDriverName[MAX_DRIVER_NAME_SIZE];
+ CHAR szDriverDescription[MAX_DRIVER_DESC_SIZE];
+ SHORT sDriverMajorRev;
+ SHORT sDriverMinorRev;
+ BOOLEAN fMandPSupported;
+} SCSI_MINIPORT_DRIVER_INFO, *PSCSI_MINIPORT_DRIVER_INFO;
+
+typedef struct _PCI_ADDRESS {
+ BYTE bPCIBusNumber;
+ BYTE bDeviceNumber;
+ BYTE bFunctionNumber;
+ BYTE bReserved;
+} PCI_ADDRESS, *PPCI_ADDRESS;
+
+typedef union _IO_BUS_DATA {
+ USHORT usEisaSlot;
+ PCI_ADDRESS PciAddress;
+} IO_BUS_DATA, *PIO_BUS_DATA;
+
+typedef struct _HBA_CONFIGURATION {
+ ULONG ulBaseIOAddress;
+ BYTE bHBAModel;
+ BYTE bHBAIoBusType;
+ IO_BUS_DATA HBAIoBusData;
+ BYTE bNumScsiBuses;
+ BYTE abInitiatorBusId[8];
+ CHAR szFWVers[5];
+ CHAR szSWVers[5];
+ CHAR szSerialNumber[16];
+ ULONG ulBoardID;
+ BYTE bBoardRevision;
+ BOOLEAN fWideSCSI;
+} HBA_CONFIGURATION, *PHBA_CONFIGURATION;
+
+typedef struct _DEVICE_DATA {
+ SCSI_ADDRESS DeviceAddress;
+ CPQ_SCSI_DEVICE DeviceData;
+} DEVICE_DATA, *PDEVICE_DATA;
+
+typedef struct _DEVICE_ERRORS {
+ ULONG ulHardReadErrs;
+ ULONG ulHardWriteErrs;
+ ULONG ulEccCorrReads;
+ ULONG ulRecvReadErrs;
+ ULONG ulRecvWriteErrs;
+ ULONG ulSeekErrs;
+ ULONG ulTimeouts;
+} DEVICE_ERRORS, *PDEVICE_ERRORS;
+
+typedef struct _DEVICE_ERROR_DATA {
+ SCSI_ADDRESS DeviceAddress;
+ DEVICE_ERRORS DeviceErrors;
+} DEVICE_ERROR_DATA, *PDEVICE_ERROR_DATA;
+
+
+// IOCTL buffer data structures
+
+typedef struct _DRIVER_INFO_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ SCSI_MINIPORT_DRIVER_INFO DriverInfo;
+} DRIVER_INFO_BUFFER, *PDRIVER_INFO_BUFFER;
+
+typedef struct _HBA_CONFIGURATION_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ HBA_CONFIGURATION HBAConfiguration;
+} HBA_CONFIGURATION_BUFFER, *PHBA_CONFIGURATION_BUFFER;
+
+typedef struct _SCSI_BUS_DATA_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ CPQ_SCSI_CNTLR ScsiBus;
+} SCSI_BUS_DATA_BUFFER, *PSCSI_BUS_DATA_BUFFER;
+
+typedef struct _DEVICE_DATA_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ DEVICE_DATA ScsiDevice;
+} DEVICE_DATA_BUFFER, *PDEVICE_DATA_BUFFER;
+
+typedef struct _DEVICE_ERROR_DATA_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ DEVICE_ERROR_DATA ScsiDevice;
+} DEVICE_ERROR_DATA_BUFFER, *PDEVICE_ERROR_DATA_BUFFER;
+
+typedef struct _MORE_DATA_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ ULONG ulExpectedSize;
+} MORE_DATA_BUFFER, *PMORE_DATA_BUFFER;
+
+#endif // _INCL_CPQSCZMP_H_
diff --git a/private/ntos/miniport/compaq/cpqsmngr.h b/private/ntos/miniport/compaq/cpqsmngr.h
new file mode 100644
index 000000000..7fa592cc6
--- /dev/null
+++ b/private/ntos/miniport/compaq/cpqsmngr.h
@@ -0,0 +1,509 @@
+/*++
+
+
+Copyright (c) 1993 Microsoft Corporation
+Copyright (c) 1993 Compaq Computer Corporation
+
+Module Name:
+
+ cpqsmngr.h
+
+Abstract:
+
+ This file contains the data structures required to support Compaq's
+ Management and Performance.
+
+Author:
+
+ Tombo - Compaq Computer Corporation
+
+Notes:
+
+Revision History:
+
+--*/
+
+#ifndef CPQSMNGR
+#define CPQSMNGR
+
+#define IDA_DRIVER_NAME "Compaq Windows NT DriveArray"
+#define IDA_MAJOR_VERSION 2
+#define IDA_MINOR_VERSION 00
+
+//
+// The following defines identify the appropriate IDA controller types.
+//
+
+#define IDA_EISA_ID_TYPEMASK 0x00ffffff // Masks off the controller type
+#define IDA_EISA_ID_ARRAY 0x0040110e // 0x0e114000 Common for all IDAs
+
+#define IDA_EISA_ID_DISCO 0x0140110e // 0x0e114001
+#define IDA_EISA_ID_CANCUN 0x0240110e // 0x0e114002
+#define IDA_EISA_ID_STANZA 0x1040110e // 0x0e114010
+#define IDA_EISA_ID_WARRIOR 0x2040110e // 0x0e114020
+#define IDA_EISA_ID_DAZZLER 0x3040110e // 0x0e114030
+
+//
+// This macro checks the Irp for a device control function.
+//
+// The parameters for this macro are...
+//
+// IN PIRP Irp // Pointer to the IO request packet.
+//
+#define MAPISPASSTHROUGH( Irp ) \
+ ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction \
+ == \
+ IRP_MJ_DEVICE_CONTROL ) && \
+ (IoGetCurrentIrpStackLocation(Irp)->\
+ Parameters.DeviceIoControl.IoControlCode \
+ == \
+ MAP_IOCTL_PASSTHROUGH ))
+#ifndef NSCSIPASS
+#define MAPISSCSIPASSTHROUGH( Irp ) \
+ ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction \
+ == \
+ IRP_MJ_DEVICE_CONTROL ) && \
+ (IoGetCurrentIrpStackLocation(Irp)->\
+ Parameters.DeviceIoControl.IoControlCode \
+ == \
+ MAP_IOCTL_SCSIPASSTHROUGH ))
+#endif
+
+//
+// The following macro frees up any allocated resources beginning at
+// the specified controller device.
+//
+#define MAP_FREE_RESOURCES( ControllerDevice ){ \
+ PMAP_CONTROLLER_DEVICE Controller; \
+ PMAP_CONTROLLER_DEVICE tmpController; \
+ PMAP_DISK_DEVICE Disk; \
+ PMAP_DISK_DEVICE tmpDisk; \
+ \
+ for( Controller=ControllerDevice; Controller; Controller=tmpController ){\
+ for( Disk=Controller->DiskDeviceList; Disk; Disk=tmpDisk ){ \
+ tmpDisk = Disk->Next; \
+ ExFreePool( Disk ); \
+ } \
+ tmpController = Controller->Next; \
+ ExFreePool( Controller ); \
+ } \
+}
+
+//
+// The following macro obtains a pointer to the last CONTROLLER_DEVICE
+// in the chain of MAP controller devices.
+//
+#define MAP_GET_LAST_CONTROLLER( cd ){ \
+ PMAP_CONTROLLER_DEVICE c; \
+ if( FirstController ){ \
+ for( c = FirstController; \
+ c->Next; \
+ c = c->Next ); \
+ *((PMAP_CONTROLLER_DEVICE*)(cd)) = c; \
+ }else{ \
+ *((PMAP_CONTROLLER_DEVICE*)(cd)) = FirstController; \
+ } \
+}
+
+//
+// The following macro obtains a pointer to the last DISK_DEVICE
+// in the chain of MAP disk devices on the last controller.
+//
+#define MAP_GET_LAST_DISK( dd, cd ){ \
+ PMAP_DISK_DEVICE d; \
+ *((PMAP_DISK_DEVICE*)(dd)) = (PMAP_DISK_DEVICE)0; \
+ MAP_GET_LAST_CONTROLLER( (cd) ); \
+ if( *((PMAP_CONTROLLER_DEVICE*)(cd)) ){ \
+ if((*((PMAP_CONTROLLER_DEVICE*)(cd)))->DiskDeviceList){ \
+ for( d = (*((PMAP_CONTROLLER_DEVICE*)(cd)))->DiskDeviceList; \
+ d->Next; \
+ d = d->Next ); \
+ *((PMAP_DISK_DEVICE*)(dd)) = d; \
+ } \
+ } \
+}
+
+#pragma pack( 1 ) // All structures need to be byte packed.
+
+//
+// The following data structure represents the MAP header buffer filled
+// in by the MAP_COMMAND_IDDRIVER command.
+//
+// The Entries include...
+//
+// DriverName - Pointer to an Array of NUL terminated ASCII
+// characters representing the IDA driver name.
+//
+// ControllerCount - The number of IDA controllers in the system.
+//
+// LogicalDiskCount - The aggregate number of IDA logical disks found
+// in the system.
+//
+// RequiredMemory - The memory size required for the data buffer
+// used in the IDA_MAP_COMMAND_IDCONTROLLERS command.
+//
+// DriverMajorVersion - The version number to the right hand side
+// of the decimal point.
+//
+// DriverMinorVersion - The version number to the left hand side
+// of the decimal point.
+//
+
+typedef struct _MAP_HEADER{
+
+ UCHAR DriverName[32];
+ ULONG ControllerCount;
+ ULONG LogicalDiskCount;
+ ULONG RequiredMemory;
+ UCHAR DriverMajorVersion;
+ UCHAR DriverMinorVersion;
+
+}MAP_HEADER, *PMAP_HEADER;
+
+//
+// The following data structure represents the MAP header buffer filled
+// in by the MAP_COMMAND_IDCONTROLLERS command.
+//
+// The Entries include...
+//
+// NextController - Pointer to the next controller in the chain.
+// A value of NULL indicates no more controllers follow.
+//
+// LogicalDriveList - Pointer to the list of IDA logical drive
+// information for ALL of the IDA logical drives that exist
+// on this controller.
+//
+// EisaId - The Eisa ID number read as a 32 bit value from EISA IO
+// space zC80h - zC83h. The valid values include...
+//
+// IDA_EISA_ID_DISCO 0x0140110e // 0e 11 40 01
+// IDA_EISA_ID_CANCUN 0x0240110e // 0e 11 40 02
+// IDA_EISA_ID_STANZA 0x1040110e // 0e 11 40 10
+// IDA_EISA_ID_WARRIOR 0x2040110e // 0e 11 40 20
+//
+// BmicIoAddress - The IO address where this controller resides in
+// EISA IO space. The value will be some derivative of zC80h
+// where 'z' is the physical EISA slot the controller resides
+// in.
+//
+// IrqLevel - The controller's EISA bus interrupt level.
+//
+// ControllerInfo - The controller's information as received by the
+// "IdentifyController" IDA logical command.
+// The size of this data structure will be the largest size
+// required to accomodate ALL flavors of Compaq supported IDA
+// controllers.
+//
+
+typedef struct _MAP_CONTROLLER_DATA{
+
+ struct _MAP_CONTROLLER_DATA *NextController;
+ struct _MAP_LOGICALDRIVE_DATA *LogicalDriveList;
+ ULONG EisaId;
+ ULONG BmicIoAddress;
+ UCHAR IrqLevel;
+ IDENTIFY_CONTROLLER ControllerInfo; //"IdentifyController"
+
+}MAP_CONTROLLER_DATA, *PMAP_CONTROLLER_DATA;
+
+//
+// The following data structure represents the MAP header buffer filled
+// in by the MAP_COMMAND_IDCONTROLLERS command. This is a fragment
+// data structure that defines the IDA logical drive information for each
+// IDA controller.
+//
+// The Entries include...
+//
+// NextLogicalDrive - Pointer to the next IDA logical drive on this
+// controller. A value of NULL indicates that there are no more
+// IDA logical drives on this controller.
+//
+// Controller - Pointer to the Controller data structure that this
+// IDA logical drive resides on.
+//
+// LogicalDriveNumber - The IDA logical drive number assigned by this
+// controller.
+//
+// SystemDriveNumber - The NT drive number assigned to this IDA logical
+// drive by the IDA device driver. It is the number that represents
+// "\Device\HarddiskN" where "N" is the SystemDriveNumber.
+//
+// DeviceLengthLo - The Low 32 bits of the IDA logical device's RAW
+// partition length.
+//
+// DeviceLengthHi - The High 32 bits of the IDA logical drive's RAW
+// partition length.
+//
+// SectorSize - The sector size in bytes for this IDA logical device.
+//
+// Configuration - The logical drive's configuration information as
+// received by the "SenseConfiguration" IDA logical command.
+// The size of this data structure will be the largest size
+// required to accomodate ALL flavors of Compaq supported IDA
+// controllers.
+//
+// LogicalDriveInfo - The IDA logical drive information buffer as
+// received by the "IdentifyLogicalDrive" IDA logical command.
+// The size of this data structure will be the largest size
+// required to accomodate ALL flavors of Compaq supported IDA
+// controllers.
+//
+
+typedef struct _MAP_LOGICALDRIVE_DATA{
+
+ struct _MAP_LOGICALDRIVE_DATA *NextLogicalDrive;
+ struct _MAP_CONTROLLER_DATA *Controller;
+ ULONG LogicalDriveNumber;
+ ULONG SystemDriveNumber;
+ ULONG DeviceLengthLo;
+ ULONG DeviceLengthHi;
+ ULONG SectorSize;
+ SENSE_CONFIGURATION Configuration; //"SenseConfiguration"
+ IDENTIFY_LOGICAL_DRIVE LogicalDriveInfo; //"IdentifyLogicalDrive"
+
+}MAP_LOGICALDRIVE_DATA, *PMAP_LOGICALDRIVE_DATA;
+
+//
+// The following data structure represents the parameter packet buffer
+// specified in all of the M&P device controls to the IDA device driver.
+//
+// The Entries include...
+//
+// Reserved
+//
+// IdaLogicalCommand - The IDA logical command to passthrough to the
+// IDA controller. This field is read by the IDA device driver.
+//
+// BlockNumber - The starting block number on the IDA logical drive.
+//
+// BlockSize - The size in bytes of the passthrough data transfer.
+//
+// BlockCount - The number of blocks to transfer. A block is equal
+// to a sector worth of data.
+//
+
+typedef struct _MAP_PARAMETER_PACKET{
+
+ UCHAR TargetId;
+ IN UCHAR IdaLogicalCommand;
+ IN ULONG BlockNumber;
+ IN ULONG BlockSize;
+ IN USHORT BlockCount;
+
+}MAP_PARAMETER_PACKET, *PMAP_PARAMETER_PACKET;
+
+
+//
+// The following data structure represents the data packet buffer
+// specified in all of the M&P device controls to the IDA device driver.
+//
+// The Entries include...
+//
+// ControllerError - The error bits returned by the IDA controller.
+//
+// ControllerData - The requested data returned by the controller.
+//
+
+typedef struct _MAP_DATA_PACKET{
+
+ OUT ULONG ControllerError;
+ OUT UCHAR ControllerData[];
+
+}MAP_DATA_PACKET, *PMAP_DATA_PACKET;
+
+//
+// The following data structures are used to abstract Microsoft's use
+// of controller and device data structures to fit COMPAQ's M&P data
+// structure format. This permits Microsoft's data structures to remain
+// unaltered so that my buddy, Mr. Disk himself, Mike Glass (AKA Gumby)
+// can still support general Array functionalilty without having to
+// figure out what the hell I did!
+//
+
+typedef struct _MAP_CONTROLLER_DEVICE{
+
+ // Pointer to the next controller device structure.
+ struct _MAP_CONTROLLER_DEVICE* Next;
+
+ // Pointer to the Microsoft defined device extension for this controller.
+ PDEVICE_EXTENSION ControllerExtension;
+
+ // EISA ID for this controller device.
+ ULONG EisaID;
+
+ // Pointer to a list of MAP logical device data structures.
+ struct _MAP_DISK_DEVICE* DiskDeviceList;
+
+ // Array controller configuration information data area.
+ IDENTIFY_CONTROLLER ControllerInformation;
+
+}MAP_CONTROLLER_DEVICE, *PMAP_CONTROLLER_DEVICE;
+
+
+typedef struct _MAP_DISK_DEVICE{
+
+ // Pointer to the next disk device data structure.
+ struct _MAP_DISK_DEVICE* Next;
+
+ // Pointer to Microsoft's defined disk device extension.
+ PDEVICE_EXTENSION DeviceExtension;
+
+ // Disk device configuration information data area.
+ SENSE_CONFIGURATION DeviceConfiguration;
+
+ // Disk device information data area.
+ IDENTIFY_LOGICAL_DRIVE DeviceInformation;
+
+ // The logical drive number for this disk device on this controller.
+ ULONG LogicalDriveNumber;
+
+ // The NT system drive number assigned by NT.
+ ULONG SystemDriveNumber;
+
+ // Pointer to the controller device data area for the controller this
+ // logical disk device resides on.
+ PMAP_CONTROLLER_DEVICE ControllerDevice;
+
+}MAP_DISK_DEVICE, *PMAP_DISK_DEVICE;
+#ifndef NSCSIPASS
+typedef struct {
+ CHAR CmdError;
+ CHAR device_status;
+ CHAR machine_error;
+ CHAR reserved;
+ UCHAR data[512];
+} SCSI_BUFFER,*PSCSI_BUFFER;
+
+typedef struct _SCSI_PASSTHRU_HEADER {
+ UCHAR scsi_target_id;
+ UCHAR path_id;
+ UCHAR logical_unit;
+ ULONG time_out_value;
+ ULONG flags;
+ UCHAR device_status;
+ UCHAR machine_error;
+ UCHAR cdb_length;
+ UCHAR reserved[16];
+
+} SCSI_PASSTHRU_HEADER, *PSCSI_PASSTHRU_HEADER;
+
+#define MAX_CDB_LENGTH 24
+typedef struct _SCSI_PASSTHRU_CDB {
+ UCHAR cdb[MAX_CDB_LENGTH];
+} SCSI_PASSTHRU_CDB, *PSCSI_PASSTHRU_CDB;
+
+typedef struct _SCSI_PASSTHRU {
+ SCSI_PASSTHRU_HEADER scsi_header;
+ SCSI_PASSTHRU_CDB scsi_cdb;
+} SCSI_PASSTHRU, *PSCSI_PASSTHRU;
+#endif
+#define CPQ_SCSI_ERR_OK 0
+#define CPQ_SCSI_ERR_FAILED 1
+#define CPQ_SCSI_ERR_BAD_CNTL_CODE 2
+#define CPQ_SCSI_ERR_REVISION 3
+#define CPQ_SCSI_ERR_NONCONTIGUOUS 4
+
+
+//Arbitrary return values not associated to the same routines.
+
+#define CPQ_CIM_ISSUED 1
+#define CPQ_CIM_COMPLETED 2
+#define CPQ_CIM_CMDBUILT 3
+#define CPQ_CIM_NONCONTIGUOUS 4
+#define CPQ_CIM_ERROR 5
+
+//
+// Define header for I/O control SRB.
+//
+
+#ifdef NDAZ
+typedef struct _SRB_IO_CONTROL {
+ ULONG HeaderLength;
+ UCHAR Signature[8];
+ ULONG Timeout;
+ ULONG ControlCode;
+ ULONG ReturnCode;
+ ULONG Length;
+} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
+#endif
+
+
+typedef struct _IDA_ERROR_BITS {
+ ULONG ControllerError;
+} IDA_ERROR_BITS, *PIDA_ERROR_BITS;
+
+typedef struct _SCSI_BUFFER_HEADER {
+ UCHAR CmdError;
+ UCHAR device_status;
+ UCHAR machine_error;
+ UCHAR reserved;
+} SCSI_BUFFER_HEADER, *PSCSI_BUFFER_HEADER;
+
+typedef struct _IDA_SCSI_PASSTHRU {
+ SCSI_PASSTHRU scsipass;
+ SCSI_BUFFER scsibuffer;
+}IDA_SCSI_PASSTHRU, *PIDA_SCSI_PASSTHRU;
+
+typedef struct _CPQ_IDA_PASSTHRU {
+ SRB_IO_CONTROL Header;
+ MAP_PARAMETER_PACKET PassThru;
+ UCHAR ReturnData[1];
+}CPQ_IDA_PASSTHRU, *PCPQ_IDA_PASSTHRU;
+
+typedef struct _CPQ_IDA_SCSI_PASSTHRU {
+ SRB_IO_CONTROL Header;
+ IDA_SCSI_PASSTHRU ScsiPassThru;
+}CPQ_IDA_SCSI_PASSTHRU, *PCPQ_IDA_SCSI_PASSTHRU;
+
+typedef struct _CPQ_IDA_IDENTIFY {
+ SRB_IO_CONTROL Header;
+ UCHAR ReturnData[1];
+}CPQ_IDA_IDENTIFY, *PCPQ_IDA_IDENTIFY;
+
+typedef struct _IDA_CONFIGURATION {
+ ULONG ulBaseIOAddress;
+ ULONG ulBaseMemoryAddress;
+ ULONG ulControllerID;
+ BYTE bIoBusType;
+ IO_BUS_DATA IoBusData;
+} IDA_CONFIGURATION, *PIDA_CONFIGURATION;
+
+typedef struct _IDA_CONFIGURATION_BUFFER {
+ SRB_IO_CONTROL IoctlHeader;
+ IDA_CONFIGURATION IDAConfiguration;
+} IDA_CONFIGURATION_BUFFER, *PIDA_CONFIGURATION_BUFFER;
+
+#define CPQ_IOCTL_IDENTIFY_DRIVER 1
+#define CPQ_IOCTL_IDENTIFY_CONTROLLERS 2
+#define CPQ_IOCTL_PASSTHROUGH 3
+#define CPQ_IOCTL_SCSIPASSTHROUGH 4
+#define CPQ_IOCTL_CONFIGURATION_INFO 5
+
+#define IDA_SIGNATURE "IDAM&P"
+
+
+#pragma pack( )
+
+//
+// The following defines specify the possible Ioctl commands that
+// can be passed to the IDA device driver from the M&P agent.
+//
+
+#define MAP_IOCTL_IDENTIFY_DRIVER \
+ CTL_CODE(FILE_DEVICE_DISK,2048,METHOD_BUFFERED,FILE_ANY_ACCESS)
+
+#define MAP_IOCTL_IDENTIFY_CONTROLLERS \
+ CTL_CODE(FILE_DEVICE_DISK,2049,METHOD_BUFFERED,FILE_ANY_ACCESS)
+
+#define MAP_IOCTL_PASSTHROUGH \
+ CTL_CODE(FILE_DEVICE_DISK,2050,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+#define MAP_IOCTL_SCSIPASSTHROUGH \
+ CTL_CODE(FILE_DEVICE_DISK,2051,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+#define MAP_IOCTL_CONFIGURATION_INFO \
+ CTL_CODE(FILE_DEVICE_DISK,2052,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+#endif //CPQSMNGR
+
+
diff --git a/private/ntos/miniport/compaq/makefile b/private/ntos/miniport/compaq/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/compaq/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/compaq/pcibios.h b/private/ntos/miniport/compaq/pcibios.h
new file mode 100644
index 000000000..24ad70bc5
--- /dev/null
+++ b/private/ntos/miniport/compaq/pcibios.h
@@ -0,0 +1,27 @@
+/* pci_bios command codes */
+
+#define GENERATE_SPECIAL_CYCLE (unsigned char)0x06
+#define READ_CONFIG_BYTE (unsigned char)0x08
+#define READ_CONFIG_WORD (unsigned char)0x09
+#define READ_CONFIG_DWORD (unsigned char)0x0A
+#define WRITE_CONFIG_BYTE (unsigned char)0x0B
+#define WRITE_CONFIG_WORD (unsigned char)0x0C
+#define WRITE_CONFIG_DWORD (unsigned char)0x0D
+
+#define SUCCESSFUL 0x00
+#define FUNC_NOT_SUPPORTED 0x81
+#define BAD_VENDOR_ID 0x83
+#define DEVICE_NOT_FOUND 0x86
+#define BAD_REGISTER_NUMBER 0x87
+
+/* pci_bios will be call through a pointer */
+/* pci_bios returns 0x00 for sucess and non-zero for failure. */
+/* pci_bios should return the rom int return code for failure. */
+/* pci_bios can or 0x80 with the command for 32 bit calls. */
+
+int pci_bios( unsigned char cmd, /* PCI bios command to perform */
+ unsigned char bus, /* PCI bus number 0...255 */
+ unsigned char device, /* PCI device number 0...31 */
+ unsigned char func, /* PCI function number 0...7 */
+ unsigned char reg, /* PCI register number 0...255 */
+ unsigned long *value ); /* Data value used for command */
diff --git a/private/ntos/miniport/compaq/scsireg.h b/private/ntos/miniport/compaq/scsireg.h
new file mode 100644
index 000000000..66d83f6b9
--- /dev/null
+++ b/private/ntos/miniport/compaq/scsireg.h
@@ -0,0 +1,223 @@
+// (C) Copyright COMPAQ Computer Corporation 1994, All rights reserved.
+//***************************************************************************
+//
+// Module : SCSIREG.H
+//
+// Version: 1.0
+//
+// Author : David Green
+//
+//***************************************************************************
+//
+// Change Log:
+//
+// 06/30/94 DRG - Split SCSI Registry info from CPQNTREG.H
+//
+//****************************************************************************
+
+
+#ifndef _SCSIREG_H
+#define _SCSIREG_H
+
+
+#pragma pack(1)
+
+
+// ***************************************************************************
+//
+// COMPAQ SCSI SUPPORT MIB
+//
+// ***************************************************************************
+
+/* SCSI device types */
+#ifndef CPQ_REG_OTHER
+#define CPQ_REG_OTHER 1
+#endif
+#define SCSI_DEV_TYPE_DISK 2
+#define SCSI_DEV_TYPE_TAPE 3
+#define SCSI_DEV_TYPE_PRINTER 4
+#define SCSI_DEV_TYPE_PROCESSOR 5
+#define SCSI_DEV_TYPE_WORMDRIVE 6
+#define SCSI_DEV_TYPE_CDROM 7
+#define SCSI_DEV_TYPE_SCANNER 8
+#define SCSI_DEV_TYPE_OPTICAL 9
+#define SCSI_DEV_TYPE_JUKEBOX 10
+#define SCSI_DEV_TYPE_COMMDEV 11
+
+/* SCSI data bus width for both the controller & devices */
+// CPQ_REG_OTHER 1
+#define SCSI_WIDTH_NARROW 2
+#define SCSI_WIDTH_WIDE16 3
+
+/* SCSI device locations */
+// CPQ_REG_OTHER 1
+#define SCSI_DEV_LOC_PROLIANT 2
+
+// COMPAQ\SCSI\COMPONENT\DEVICE[xx]
+
+typedef struct _CPQ_SCSI_DEVICE {
+ BYTE devCntlrIndex;
+ BYTE devBusIndex;
+ BYTE devScsiIdIndex;
+ BYTE devType;
+ BYTE devLocation;
+ CHAR devModel[17];
+ CHAR devFWRev[5];
+ CHAR devVendor[9];
+ ULONG devParityErrs;
+ ULONG devPhasErrs;
+ ULONG devSelectTimeouts;
+ ULONG devMsgRejects;
+ ULONG devNegPeriod;
+ // New fields
+ ULONG devNegSpeed;
+ ULONG devPhysWidth;
+ ULONG devNegWidth;
+ BYTE bReserved[16]; // Not in MIB
+} CPQ_SCSI_DEVICE, * pCPQ_SCSI_DEVICE;
+
+
+/* SCSI controller models */
+// CPQ_REG_OTHER 1
+#define SCSI_CNTLR_MODEL_710 2 // c710 EISA
+#define SCSI_CNTLR_MODEL_94 3 // c94 EISA
+#define SCSI_CNTLR_MODEL_810 4 // c810 PCI
+#define SCSI_CNTLR_MODEL_825e 5 // c825 EISA
+#define SCSI_CNTLR_MODEL_825p 6 // c825 PCI
+#define SCSI_CNTLR_MODEL_974p 7 // AM53c974 PCI
+
+/* SCSI controller status */
+// CPQ_REG_OTHER 1
+#define SCSI_CNTLR_STATUS_OK 2
+#define SCSI_CNTLR_STATUS_FAILED 3
+
+// COMPAQ\SCSI\COMPONENT\SCSICNTLR[XX]
+
+typedef struct _CPQ_SCSI_CNTLR {
+ BYTE cntlrIndex;
+ BYTE cntlrBusIndex;
+ BYTE cntlrModel;
+ BYTE cntlrSlot;
+ BYTE cntlrStatus;
+ BYTE cntlrCondition;
+ CHAR cntlrFWVers[5];
+ CHAR cntlrSWVers[5];
+ ULONG cntlrHardResets;
+ ULONG cntlrSoftResets;
+ ULONG cntlrTimeouts;
+ ULONG cntlrBaseIOAddr;
+ BYTE cntlrSerialNumber[16];
+ ULONG cntlrBoardId;
+ ULONG cntlrBoardRevision;
+ ULONG cntlrBoardWidth;
+ BYTE bReserved[16]; // Not in MIB
+} CPQ_SCSI_CNTLR, * pCPQ_SCSI_CNTLR;
+
+
+// This is deprecated, but some code still references it
+
+/* SCSI logical drive fault tolerance values (defined with IDA) */
+// CPQ_REG_OTHER 1
+// FAULT_TOL_NONE 2
+// FAULT_TOL_MIRRORING 3
+// FAULT_TOL_RAID4 4
+// FAULT_TOL_RAID5 5
+
+/* SCSI logical drive status values (defined with IDA) */
+// CPQ_REG_OTHER 1
+// LOG_DRV_OK 2
+// LOG_DRV_FAILED 3
+// LOG_DRV_UNCONFIGURED 4
+// LOG_DRV_RECOVERING 5
+// LOG_DRV_READY_REBUILD 6
+// LOG_DRV_REBUILDING 7
+// LOG_DRV_WRONG_DRIVE 8
+// LOG_DRV_BAD_CONNECT 9
+
+// COMPAQ\SCSI\COMPONENT\LOGDRV[XX]
+
+typedef struct _CPQ_SCSI_LOGICAL {
+ BYTE logDrvCntlrIndex;
+ BYTE logDrvBusIndex;
+ BYTE logDrvIndex;
+ BYTE logDrvFaultTol;
+ BYTE logDrvStatus;
+ BYTE logDrvCondition;
+ ULONG logDrvSize;
+ BYTE logDrvPhyDrvIDs[33];
+} CPQ_SCSI_LOGICAL, * pCPQ_SCSI_LOGICAL;
+
+
+/* SCSI physical drive status */
+// CPQ_REG_OTHER 1
+#define SCSI_PHYS_STATUS_OK 2
+#define SCSI_PHYS_STATUS_FAILED 3
+#define SCSI_PHYS_STATUS_NOT_CONFIGURED 4
+#define SCSI_PHYS_STATUS_BAD_CABLE 5
+#define SCSI_PHYS_STATUS_MISSING_WAS_OK 6
+#define SCSI_PHYS_STATUS_MISSING_WAS_FAILED 7
+
+/* SCSI physical drive statistics preservation */
+// CPQ_REG_OTHER 1
+#define SCSI_PHYS_PRES_NVRAM 2
+#define SCSI_PHYS_PRES_DISK 3
+#define SCSI_PHYS_PRES_NO_CPU 4
+#define SCSI_PHYS_PRES_NO_NVRAM 5
+#define SCSI_PHYS_PRES_NO_DRV 6
+#define SCSI_PHYS_PRES_NO_SW 7
+
+/* Physical drive placement values */
+// CPQ_REG_OTHER 1
+// PHYS_DRV_PLACE_INTERNAL 2
+// PHYS_DRV_PLACE_EXTERNAL 3
+
+/* Physical drive hot plug values */
+// CPQ_REG_OTHER 1
+// PHYS_DRV_HOT_PLUG 2
+// PHYS_DRV_NOT_HOT_PLUG 3
+
+
+// COMPAQ\SCSI\COMPONENT\PHYDRV[XX]
+
+typedef struct _CPQ_SCSI_PHYSICAL {
+ BYTE phyDrvCntlrIndex;
+ BYTE phyDrvBusIndex;
+ BYTE phyDrvIndex;
+ CHAR phyDrvModel[17];
+ CHAR phyDrvFWRev[5];
+ CHAR phyDrvVendor[9];
+ ULONG phyDrvSize;
+ BYTE phyDrvScsiId;
+ BYTE phyDrvStatus;
+ ULONG phyDrvServiceHours;
+ ULONG phyDrvReads;
+ ULONG phyDrvHReads;
+ ULONG phyDrvWrites;
+ ULONG phyDrvHWrites;
+ ULONG phyDrvHardReadErrs;
+ ULONG phyDrvHardWriteErrs;
+ ULONG phyDrvEccCorrReads;
+ ULONG phyDrvRecvReadErrs;
+ ULONG phyDrvRecvWriteErrs;
+ ULONG phyDrvSeekErrs;
+ ULONG phyDrvSpinupTime;
+ ULONG phyDrvUsedRealloc;
+ ULONG phyDrvTimeouts;
+ ULONG phyDrvPostErrs;
+ ULONG phyDrvPostCode;
+ BYTE phyDrvCondition;
+ BYTE phyDrvFuncTest1;
+ BYTE phyDrvFuncTest2;
+ BYTE phyDrvStatsPreserved;
+ CHAR phyDrvSerialNum[13];
+ BYTE phyDrvPlacement;
+ BYTE phyDrvParent;
+ ULONG phyDrvSectorSize;
+ BYTE phyDrvHotPlug;
+ BYTE phyDrvReserved[17]; // Reserved for alignment
+} CPQ_SCSI_PHYSICAL, * pCPQ_SCSI_PHYSICAL;
+
+
+#pragma pack()
+
+#endif
diff --git a/private/ntos/miniport/compaq/sources b/private/ntos/miniport/compaq/sources
new file mode 100644
index 000000000..2682269d9
--- /dev/null
+++ b/private/ntos/miniport/compaq/sources
@@ -0,0 +1,39 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=cpqarray
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+!IF $(ALPHA)
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib $(BASEDIR)\public\sdk\lib\*\libcntpr.lib
+!ENDIF
+
+SOURCES=cpqarray.c cpqarray.rc
+
diff --git a/private/ntos/miniport/dell/delldsa.c b/private/ntos/miniport/dell/delldsa.c
new file mode 100644
index 000000000..e2c7b203c
--- /dev/null
+++ b/private/ntos/miniport/dell/delldsa.c
@@ -0,0 +1,1767 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ DellDsa.c
+
+Abstract:
+
+ This is the device driver for the DELL Drive Arrays.
+
+Authors:
+
+ Mike Glass (mglass)
+
+Environment:
+
+ kernel mode only
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "scsi.h"
+#include "delldsa.h"
+
+//
+// Disk Device Extension
+//
+
+typedef struct _DEVICE_EXTENSION {
+
+ //
+ // BMIC registers
+ //
+
+ PDDA_REGISTERS Bmic;
+
+ //
+ // Buffer for IDENTIFY command.
+ //
+
+ PVOID IdentifyBuffer;
+
+ //
+ // The rest of the fields are for the controller itself.
+ //
+ // Firmware major version
+ // 1 : DDA
+ // 2 : DSA
+ //
+
+ USHORT MajorVersion;
+ USHORT MinorVersion;
+
+ UCHAR NumberOfLogicalDrives;
+ UCHAR EmulationMode;
+ UCHAR MaximumQueueDepth;
+ UCHAR MaximumNumberOfSgDescriptors;
+
+ //
+ // Keep track of state of verify.
+ //
+
+ ULONG CurrentSector;
+ ULONG RemainingSectors;
+
+ //
+ // Array of outstanding requests
+ //
+
+ PSCSI_REQUEST_BLOCK Srb[256];
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+BOOLEAN
+ExtendedCommand(
+ PDEVICE_EXTENSION DeviceExtension,
+ IN UCHAR LogicalDrive,
+ IN UCHAR Command
+ )
+
+/*++
+
+Routine Description:
+
+ Ring local doorbell and wait for completion bit in local doorbell to be set.
+ This function is only called during initialization.
+
+Arguments:
+
+ DeviceExtension - Controller data.
+ LogicalDrive - Logical drive defined on this controller.
+ Command - Command byte to be sent.
+
+Return Value:
+
+ TRUE - if completion bit set in local doorbell.
+ FALSE - if timeout occurred waiting for bit to be set.
+
+--*/
+
+{
+ ULONG i;
+
+ //
+ // Claim submission semaphore.
+ //
+
+ for (i=0; i<1000; i++) {
+
+ if (ScsiPortReadPortUchar(&DeviceExtension->Bmic->SubmissionSemaphore)) {
+ ScsiPortStallExecution(1);
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 1000) {
+ return FALSE;
+ }
+
+ //
+ // Claim submission semaphore
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->SubmissionSemaphore, 1);
+
+ //
+ // Write command byte to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->Command, Command);
+
+ //
+ // Write logical drive number to controller. Some extended commands
+ // do not require a logical drive number, but setting it doesn't hurt
+ // anything and makes this routine more flexible.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->DriveNumber, LogicalDrive);
+
+ //
+ // Ring submission doorbell.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->SubmissionDoorBell,
+ DDA_DOORBELL_EXTENDED_COMMAND);
+
+ //
+ // Spin for completion.
+ //
+
+ for (i=0; i<10000; i++) {
+
+ if (ScsiPortReadPortUchar(&DeviceExtension->Bmic->CompletionDoorBell) &
+ DDA_DOORBELL_EXTENDED_COMMAND) {
+ break;
+ } else {
+ ScsiPortStallExecution(10);
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 10000) {
+ return FALSE;
+ }
+
+ //
+ // Clear completion status
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->Bmic->CompletionDoorBell, 0xff);
+
+ return TRUE;
+
+} // end ExtendedCommand
+
+
+VOID
+BuildRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Translates a system SRB to a DDA request.
+
+ A DDA request has the following restrictions:
+
+ (1) Its scatter/gather list size is specified in
+ DeviceExtension->MaximumSGSize and is usually 16.
+ (2) Scatter/gather requests use sector counts rather than byte counts.
+ A scather/gather boundry cannot exist in the middle of a sector.
+ (3) The maximum size of a single DDA I/O is limited to 128 sectors.
+ This is because some early disk devices have bugs causing data
+ corruption in larger transfers.
+
+ DSA controllers do not have restriction (2), but some DSA firmware
+ have bugs such that byte SG hangs the controller.
+
+Arguments:
+
+ DeviceExtension - Represents the target disk.
+ SRB - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDDA_REQUEST_BLOCK ddaRequest = Srb->SrbExtension;
+ PUCHAR dataPointer;
+ ULONG descriptorNumber;
+ ULONG bytesLeft;
+ PSG_DESCRIPTOR sgList;
+ ULONG length;
+
+ //
+ // Set drive number if request packet.
+ //
+
+ ddaRequest->DriveNumber = Srb->TargetId;
+
+ //
+ // Use SRB tag as request id.
+ //
+
+ ddaRequest->RequestId = Srb->QueueTag;
+ DeviceExtension->Srb[Srb->QueueTag] = Srb;
+
+ //
+ // Determine starting block number.
+ //
+
+ ddaRequest->StartingSector =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+
+ //
+ // Get data pointer, byte count and index to scatter/gather list.
+ //
+
+ sgList = ddaRequest->SgList.Descriptor;
+ descriptorNumber = 0;
+ bytesLeft = Srb->DataTransferLength;
+ dataPointer = Srb->DataBuffer;
+
+ //
+ // Build the scatter/gather list.
+ //
+
+ while (bytesLeft) {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ sgList[descriptorNumber].Address =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ //
+ // Complete SG descriptor.
+ //
+
+ sgList[descriptorNumber].Count = length;
+
+ //
+ // Update pointers and counters.
+ //
+
+ bytesLeft -= length;
+ dataPointer += length;
+ descriptorNumber++;
+ }
+
+ //
+ // Convert to non-scatter/gather if possible. This improves
+ // command overhead by eliminating the SG list read across the bus.
+ //
+
+ if (descriptorNumber == 1) {
+
+ //
+ // Change data pointer and count.
+ //
+
+ ddaRequest->Size = (UCHAR)(sgList[0].Count / 512);
+ ddaRequest->PhysicalAddress = sgList[0].Address;
+
+ //
+ // Determine new command code.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ddaRequest->Command = DDA_COMMAND_READ;
+ } else {
+ ddaRequest->Command = DDA_COMMAND_WRITE;
+ }
+
+ } else {
+
+ ddaRequest->Size = (UCHAR)descriptorNumber;
+
+ //
+ // Calculate physical address of the scatter/gather list.
+ //
+
+ ddaRequest->PhysicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ sgList,
+ &length));
+
+ //
+ // Check firmware to determine whether scatter/gather
+ // descriptors must be converted to sector descripters or
+ // whether byte-level scatter/gather can be used.
+ //
+
+ if (DeviceExtension->MajorVersion == 1) {
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ddaRequest->Command = DDA_COMMAND_SG_READ;
+ } else {
+ ddaRequest->Command = DDA_COMMAND_SG_WRITE;
+ }
+
+ //
+ // Convert byte counts to sector counts.
+ //
+
+ for (descriptorNumber=0;
+ descriptorNumber < ddaRequest->Size; descriptorNumber++) {
+ sgList[descriptorNumber].Count /= 512;
+ }
+
+ } else {
+
+ //
+ // Use byte-level scatter/gather.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ddaRequest->Command = DDA_COMMAND_SG_READB;
+ } else {
+ ddaRequest->Command = DDA_COMMAND_SG_WRITEB;
+ }
+ }
+ }
+
+ return;
+
+} // end BuildRequest()
+
+
+VOID
+BuildVerifyRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ DeviceExtension - Represents the target disk.
+ SRB - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDDA_REQUEST_BLOCK ddaRequest = Srb->SrbExtension;
+ PUCHAR dataPointer;
+ ULONG descriptorNumber;
+ ULONG bytesLeft;
+ PSG_DESCRIPTOR sgList;
+ ULONG length;
+ USHORT sectorCount;
+
+ //
+ // Set drive number if request packet.
+ //
+
+ ddaRequest->DriveNumber = Srb->TargetId;
+
+ //
+ // Use SRB tag as request id.
+ //
+
+ ddaRequest->RequestId = Srb->QueueTag;
+ DeviceExtension->Srb[Srb->QueueTag] = Srb;
+
+ //
+ // Determine starting block number.
+ //
+
+ ddaRequest->StartingSector =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
+
+ //
+ // Get data pointer, byte count and index to scatter/gather list.
+ //
+
+ sectorCount = ((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8 | ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
+ DeviceExtension->CurrentSector = ddaRequest->StartingSector;
+
+ if (sectorCount > 0x80) {
+ DeviceExtension->RemainingSectors = sectorCount - 0x80;
+ sectorCount = 0x80;
+ } else {
+ DeviceExtension->RemainingSectors = 0;
+ }
+
+ ddaRequest->Size = (UCHAR)sectorCount;
+ ddaRequest->Command = DDA_COMMAND_VERIFY;
+ ddaRequest->PhysicalAddress = 0;
+
+ return;
+
+} // end BuildVerifyRequest()
+
+BOOLEAN
+SubmitRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PDDA_REQUEST_BLOCK DdaRequest
+ )
+
+/*++
+
+Routine Description:
+
+ Submit DDA/DSA request to controller.
+
+Arguments:
+
+ DeviceExtension - Address of adapter storage area.
+ DdaRequest - Request to be submitted.
+
+Return Value:
+
+ TRUE - if request submitted.
+ FALSE - if timeout occurred waiting for submission semaphore.
+
+--*/
+
+{
+ PDDA_REGISTERS bmic = DeviceExtension->Bmic;
+ ULONG i;
+
+ //
+ // Claim submission semaphore.
+ //
+
+ for (i=0; i<100; i++) {
+
+ if (ScsiPortReadPortUchar(&bmic->SubmissionSemaphore)) {
+ ScsiPortStallExecution(20);
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 100) {
+
+ DebugPrint((1,
+ "DELLDSA: SubmitRequest: Timeout waiting for submission channel %x\n",
+ DdaRequest));
+
+ return FALSE;
+ }
+
+ //
+ // Submit request.
+ //
+
+ ScsiPortWritePortUchar(&bmic->SubmissionSemaphore, 1);
+ ScsiPortWritePortUchar(&bmic->Command, DdaRequest->Command);
+ ScsiPortWritePortUchar(&bmic->DriveNumber, DdaRequest->DriveNumber);
+ ScsiPortWritePortUchar(&bmic->TransferCount, DdaRequest->Size);
+ ScsiPortWritePortUchar(&bmic->RequestIdOut, DdaRequest->RequestId);
+ ScsiPortWritePortUlong(&bmic->StartingSector, DdaRequest->StartingSector);
+ ScsiPortWritePortUlong(&bmic->DataAddress, DdaRequest->PhysicalAddress);
+ ScsiPortWritePortUchar(&bmic->SubmissionDoorBell,
+ DDA_DOORBELL_LOGICAL_COMMAND);
+
+ return TRUE;
+
+} // SubmitRequest()
+
+
+BOOLEAN
+DsaResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resets the controller and completes outstanding requests.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ PathId - Indicates adapter to reset.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG i;
+
+ //
+ // Reset controller.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 1);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionDoorBell,
+ DDA_DOORBELL_SOFT_RESET);
+
+ //
+ // Spin for reset completion.
+ //
+
+ for (i=0; i<1000000; i++) {
+
+ if (!(ScsiPortReadPortUchar(&deviceExtension->Bmic->SubmissionSemaphore) & 1)) {
+ break;
+ }
+
+ ScsiPortStallExecution(5);
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 1000000) {
+ return FALSE;
+ }
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(HwDeviceExtension,
+ (UCHAR)PathId,
+ 0xFF,
+ 0xFF,
+ SRB_STATUS_BUS_RESET);
+
+ //
+ // Clear all SRB entries in device extension.
+ //
+
+ for (i=0; i<256; i++) {
+ deviceExtension->Srb[i] = NULL;
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ HwDeviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end DsaResetBus()
+
+
+BOOLEAN
+DsaInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler for the DELL DDA/DSA controller.
+
+Arguments:
+
+ DeviceExtension - Represents the target controller.
+
+Return Value:
+
+ Return TRUE if controller is interrupting.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PDDA_REGISTERS bmic = deviceExtension->Bmic;
+ PDDA_REQUEST_BLOCK ddaRequest;
+ PSCSI_REQUEST_BLOCK srb;
+ UCHAR status;
+ UCHAR tag;
+
+ //
+ // Check if interrupt expected and clear it.
+ //
+
+ status = ScsiPortReadPortUchar(&deviceExtension->Bmic->CompletionDoorBell);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->CompletionDoorBell, status);
+
+ if (!(status & DDA_INTERRUPTS)) {
+
+ //
+ // Interrupt is spurious.
+ //
+
+ return FALSE;
+ }
+
+ if (status & DDA_DOORBELL_EXTENDED_COMMAND) {
+ return TRUE;
+ }
+
+ status = ScsiPortReadPortUchar(&bmic->Status);
+ tag = ScsiPortReadPortUchar(&bmic->RequestIdIn);
+
+ //
+ // Release completion semaphore.
+ //
+
+ ScsiPortWritePortUchar(&bmic->CompletionSemaphore, 0);
+
+ //
+ // Get SRB address.
+ //
+
+ srb = deviceExtension->Srb[tag];
+ deviceExtension->Srb[tag] = NULL;
+
+ if (!srb) {
+ return TRUE;
+ }
+
+ if (srb->Cdb[0] == SCSIOP_VERIFY) {
+
+ if (status == DDA_STATUS_NO_ERROR) {
+
+ //
+ // See if the verify isn't yet complete.
+ //
+
+ if (deviceExtension->RemainingSectors != 0) {
+
+ ULONG i;
+ USHORT sectorCount;
+
+ ddaRequest = srb->SrbExtension;
+ sectorCount = ddaRequest->Size;
+
+ //
+ // Determine the new starting block number.
+ //
+
+ ddaRequest->StartingSector += sectorCount;
+
+ sectorCount = (USHORT)deviceExtension->RemainingSectors;
+
+ if (sectorCount > 0x80) {
+ deviceExtension->RemainingSectors = sectorCount - 0x80;
+ sectorCount = 0x80;
+ } else {
+ deviceExtension->RemainingSectors = 0;
+ }
+
+
+ ddaRequest->Size = (UCHAR)sectorCount;
+ ddaRequest->Command = DDA_COMMAND_VERIFY;
+ ddaRequest->PhysicalAddress = 0;
+
+ ddaRequest->RequestId = srb->QueueTag;
+ deviceExtension->Srb[srb->QueueTag] = srb;
+
+ //
+ // Claim submission semaphore.
+ //
+
+ for (i=0; i<100; i++) {
+
+ if (ScsiPortReadPortUchar(&bmic->SubmissionSemaphore)) {
+ ScsiPortStallExecution(20);
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 100) {
+
+ DebugPrint((1,
+ "DELLDSA: SubmitRequest: Timeout waiting for submission channel %x\n",
+ ddaRequest));
+
+ status = DDA_STATUS_TIMEOUT;
+
+ } else {
+
+ //
+ // Submit request.
+ //
+
+ ScsiPortWritePortUchar(&bmic->SubmissionSemaphore, 1);
+ ScsiPortWritePortUchar(&bmic->Command, ddaRequest->Command);
+ ScsiPortWritePortUchar(&bmic->DriveNumber, ddaRequest->DriveNumber);
+ ScsiPortWritePortUchar(&bmic->TransferCount, ddaRequest->Size);
+ ScsiPortWritePortUchar(&bmic->RequestIdOut, ddaRequest->RequestId);
+ ScsiPortWritePortUlong(&bmic->StartingSector, ddaRequest->StartingSector);
+ ScsiPortWritePortUlong(&bmic->DataAddress, ddaRequest->PhysicalAddress);
+ ScsiPortWritePortUchar(&bmic->SubmissionDoorBell,
+ DDA_DOORBELL_LOGICAL_COMMAND);
+
+ return TRUE;
+ }
+ } else {
+
+ //
+ // Ask for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+
+ }
+ }
+ }
+
+ //
+ // Map DDA/DSA status to SRB status.
+ //
+
+ switch (status) {
+
+ case DDA_STATUS_NO_ERROR:
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ break;
+
+ case DDA_STATUS_TIMEOUT:
+
+ srb->SrbStatus = SRB_STATUS_TIMEOUT;
+ break;
+
+ case DDA_STATUS_TRACK0_NOT_FOUND:
+ case DDA_STATUS_ABORTED:
+ case DDA_STATUS_UNCORRECTABLE_ERROR:
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case DDA_STATUS_CORRECTABLE_ERROR:
+
+ srb->SrbStatus = SRB_STATUS_ERROR_RECOVERY;
+ break;
+
+ case DDA_STATUS_SECTOR_ID_NOT_FOUND:
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ break;
+
+ case DDA_STATUS_BAD_BLOCK_FOUND:
+ case DDA_STATUS_WRITE_ERROR:
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ break;
+ }
+
+ //
+ // Inform system that this request is complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ return TRUE;
+
+} // end DsaInterrupt()
+
+
+BOOLEAN
+DsaStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This is routine is called by the system to start a request on the adapter.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ Srb - Address of the request to be started.
+
+Return Value:
+
+ TRUE - The request has been started.
+ FALSE - The controller was busy.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ UCHAR status;
+ ULONG i;
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ if (!DsaResetBus(deviceExtension,
+ Srb->PathId)) {
+
+ status = SRB_STATUS_ERROR;
+
+ } else {
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_VERIFY:
+
+
+ BuildVerifyRequest(deviceExtension,Srb);
+
+ if (SubmitRequest(deviceExtension,
+ (PDDA_REQUEST_BLOCK)Srb->SrbExtension)) {
+
+ status = SRB_STATUS_PENDING;
+
+ //
+ // return, upon completion the verify path will ask for the next request.
+ //
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Timed out waiting for submission channel to clear.
+ //
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ break;
+
+
+ case SCSIOP_WRITE:
+ case SCSIOP_READ:
+
+ //
+ // Build command list from SRB.
+ //
+
+ BuildRequest(deviceExtension,
+ Srb);
+
+ //
+ // Submit request to controller.
+ //
+
+ if (SubmitRequest(deviceExtension,
+ (PDDA_REQUEST_BLOCK)Srb->SrbExtension)) {
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+
+ //
+ // Timed out waiting for submission channel to clear.
+ //
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+
+ status = SRB_STATUS_SUCCESS;
+
+ break;
+
+ case SCSIOP_READ_CAPACITY:
+
+ //
+ // Issue extended command to get disk geometry.
+ //
+
+ if (!ExtendedCommand(deviceExtension,
+ Srb->TargetId,
+ DDA_GET_LOGICAL_GEOMETRY)) {
+
+ DebugPrint((1,"DsaStartIo: Couldn't get logical drive geometry\n"));
+ status = SRB_STATUS_ERROR;
+
+ } else {
+
+ ULONG blockSize = 512;
+ UCHAR sectorsPerTrack =
+ ScsiPortReadPortUchar(&((PDDA_GET_GEOMETRY)deviceExtension->Bmic)->SectorsPerTrack);
+ UCHAR numberOfHeads =
+ ScsiPortReadPortUchar(&((PDDA_GET_GEOMETRY)deviceExtension->Bmic)->NumberOfHeads);
+ USHORT numberOfCylinders =
+ ScsiPortReadPortUshort(&((PDDA_GET_GEOMETRY)deviceExtension->Bmic)->NumberOfCylinders);
+ ULONG numberOfBlocks;
+
+ //
+ // Release semaphore.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 0);
+
+ DebugPrint((1,
+ "DsaStartIo: Block size %x\n",
+ blockSize));
+
+ DebugPrint((1,
+ "DsaStartIo: Sectors per track %x\n",
+ sectorsPerTrack));
+
+ DebugPrint((1,
+ "DsaStartIo: Number of heads %x\n",
+ numberOfHeads));
+
+ DebugPrint((1,
+ "DsaStartIo: Number of cylinders %x\n",
+ numberOfCylinders));
+
+ //
+ // Calculate number of sectors on this disk.
+ //
+
+ numberOfBlocks =
+ sectorsPerTrack *
+ numberOfHeads *
+ numberOfCylinders;
+
+ //
+ // Get blocksize and number of blocks from identify
+ // data.
+ //
+
+ REVERSE_BYTES(&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock,
+ &blockSize);
+
+ REVERSE_BYTES(&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress,
+ &numberOfBlocks);
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ case SCSIOP_INQUIRY:
+
+ //
+ // Only respond at logical unit 0;
+ //
+
+ if (Srb->Lun != 0 ||
+ Srb->TargetId >=
+ deviceExtension->NumberOfLogicalDrives) {
+
+ //
+ // Indicate no device found at this address.
+ //
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+
+ } else {
+
+ PINQUIRYDATA inquiryData = Srb->DataBuffer;
+
+ //
+ // Zero INQUIRY data structure.
+ //
+
+ for (i = 0; i < Srb->DataTransferLength; i++) {
+ ((PUCHAR)Srb->DataBuffer)[i] = 0;
+ }
+
+ //
+ // Dell DDA/DSA only supports disks.
+ //
+
+ inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
+
+ //
+ // Fill in vendor identification fields.
+ //
+
+ inquiryData->VendorId[0] = 'D';
+ inquiryData->VendorId[1] = 'e';
+ inquiryData->VendorId[2] = 'l';
+ inquiryData->VendorId[3] = 'l';
+ inquiryData->VendorId[4] = ' ';
+ inquiryData->VendorId[5] = ' ';
+ inquiryData->VendorId[6] = ' ';
+ inquiryData->VendorId[7] = 'D';
+ inquiryData->VendorId[8] = 'i';
+ inquiryData->VendorId[9] = 's';
+ inquiryData->VendorId[10] = 'k';
+ inquiryData->VendorId[11] = ' ';
+ inquiryData->VendorId[12] = 'A';
+ inquiryData->VendorId[13] = 'r';
+ inquiryData->VendorId[14] = 'r';
+ inquiryData->VendorId[15] = 'a';
+ inquiryData->VendorId[16] = 'y';
+ inquiryData->VendorId[17] = ' ';
+ inquiryData->VendorId[18] = ' ';
+ inquiryData->VendorId[19] = ' ';
+ inquiryData->VendorId[20] = ' ';
+
+ //
+ // Initialize unused portion of product id.
+ //
+
+ for (i = 0; i < 4; i++) {
+ inquiryData->ProductId[12+i] = ' ';
+ }
+
+ //
+ // Move firmware revision from IDENTIFY data to
+ // product revision in INQUIRY data.
+ //
+
+ for (i = 0; i < 4; i += 2) {
+ inquiryData->ProductRevisionLevel[i] = ' ';
+ inquiryData->ProductRevisionLevel[i+1] = ' ';
+ }
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ default:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+
+ break;
+
+ } // end switch (Srb->Cdb[0])
+
+ break;
+
+ default:
+
+ status = SRB_STATUS_INVALID_REQUEST;
+
+ } // end switch
+
+ //
+ // Check if SRB should be completed.
+ //
+
+ if (status != SRB_STATUS_PENDING) {
+
+ //
+ // Set status in SRB.
+ //
+
+ Srb->SrbStatus = status;
+
+ //
+ // Inform system that this request is complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ } else {
+
+ //
+ // Indicate to system that the controller can take another request
+ // for this device.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ }
+
+
+ return TRUE;
+
+} // end DsaStartIo()
+
+
+BOOLEAN
+SearchEisaBus(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from DsaFindAdapter if the system fails to
+ pass in predetermined configuration data. It searches the EISA bus
+ data looking for information about controllers that this driver
+ supports.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+ Context - Used to track how many EISA slots have been searched.
+ ConfigInfo - System template for configuration information.
+
+Return Value:
+
+ TRUE - If Dell DDA/DSA controller found.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG length;
+ ULONG eisaSlotNumber;
+ PACCESS_RANGE accessRange;
+ PCM_EISA_SLOT_INFORMATION slotInformation;
+ PCM_EISA_FUNCTION_INFORMATION functionInformation;
+ ULONG numberOfFunctions;
+
+ //
+ // Get pointer to first configuration information structure access range.
+ //
+
+ accessRange = &((*(ConfigInfo->AccessRanges))[0]);
+
+ for (eisaSlotNumber=*((PULONG)Context);
+ eisaSlotNumber<16;
+ eisaSlotNumber++) {
+
+ //
+ // Get pointer to bus data for this EISA slot.
+ //
+
+ length = ScsiPortGetBusData(HwDeviceExtension,
+ EisaConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ eisaSlotNumber,
+ &slotInformation,
+ 0);
+
+ if (!length) {
+ continue;
+ }
+
+ //
+ // Check for Dell board id.
+ //
+
+ if ((slotInformation->CompressedId & 0xf0ffffff) != DDA_ID) {
+ continue;
+ }
+
+ //
+ // Set up default port address.
+ //
+
+ accessRange->RangeStart.LowPart =
+ (eisaSlotNumber * 0x1000) + 0x0C80;
+ accessRange->RangeLength = sizeof(DDA_REGISTERS);
+
+ accessRange++;
+
+ //
+ // Get the number of EISA configuration functions returned in bus data.
+ //
+
+ numberOfFunctions = slotInformation->NumberFunctions;
+
+ //
+ // Get first configuration record.
+ //
+
+ functionInformation =
+ (PCM_EISA_FUNCTION_INFORMATION)(slotInformation + 1);
+
+ //
+ // Walk configuration records to find EISA IRQ.
+ //
+
+ for (; 0 < numberOfFunctions; numberOfFunctions--, functionInformation++) {
+
+ //
+ // Check for IRQ.
+ //
+
+ if (functionInformation->FunctionFlags & EISA_HAS_IRQ_ENTRY) {
+
+ ConfigInfo->BusInterruptLevel =
+ functionInformation->EisaIrq->ConfigurationByte.Interrupt;
+ ConfigInfo->InterruptMode = Latched;
+ }
+
+ //
+ // Check for IO ranges.
+ //
+
+ if (functionInformation->FunctionFlags & EISA_HAS_PORT_RANGE) {
+
+ PEISA_PORT_CONFIGURATION eisaPort =
+ functionInformation->EisaPort;
+
+ //
+ // Search for emulation ranges.
+ //
+
+ while (eisaPort->PortAddress) {
+
+ //
+ // Check range to determine length.
+ //
+
+ switch (eisaPort->PortAddress) {
+
+ case 0x000001f0:
+ case 0x00000170:
+
+ accessRange->RangeStart.LowPart = eisaPort->PortAddress;
+ accessRange->RangeLength = 0x0000000F;
+ break;
+
+ case 0x000003f6:
+ case 0x00000176:
+
+ accessRange->RangeStart.LowPart = eisaPort->PortAddress;
+ accessRange->RangeLength = 0x00000001;
+ break;
+ }
+
+ DebugPrint((1,
+ "DELLDSA: SearchEisaBus: IO base %x\n",
+ eisaPort->PortAddress));
+
+ //
+ // Advance pointers to next IO range.
+ //
+
+ accessRange++;
+ eisaPort++;
+ }
+ }
+ }
+
+ //
+ // Indicate from which EISA slot to continue search.
+ //
+
+ *((PULONG)Context) = eisaSlotNumber + 1;
+
+ return TRUE;
+ }
+
+ return FALSE;
+
+} // end SearchEisaBus()
+
+
+BOOLEAN
+DsaInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the system during initialization to
+ prepare the controller to receive requests.
+
+Arguments:
+
+ HwDeviceExtension - Address of adapter storage area.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG i;
+
+ //
+ // Check if controller needs a reset.
+ //
+
+ if (ScsiPortReadPortUchar(&deviceExtension->Bmic->SubmissionSemaphore)) {
+
+ //
+ // Issue a soft reset.
+ //
+
+ DebugPrint((1,
+ "DellDsa: Submission channnel stuck; Resetting controller\n"));
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 1);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionDoorBell,
+ DDA_DOORBELL_SOFT_RESET);
+
+ //
+ // Spin for reset completion.
+ //
+
+ for (i=0; i<1000000; i++) {
+
+ if (!(ScsiPortReadPortUchar((PUCHAR)&deviceExtension->Bmic->SubmissionSemaphore) & 1)) {
+ break;
+ }
+
+ ScsiPortStallExecution(5);
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 1000000) {
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Enable completion interrupts.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->InterruptControl, 1);
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->CompletionInterruptMask,
+ DDA_DOORBELL_LOGICAL_COMMAND);
+
+ //
+ // Clear all SRB entries in device extension.
+ //
+
+ for (i=0; i<256; i++) {
+ deviceExtension->Srb[i] = NULL;
+ }
+
+ return TRUE;
+
+} // end DsaInitialize()
+
+
+ULONG
+DsaFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function fills in the configuration information structure
+
+Arguments:
+
+ HwDeviceExtension - Supplies a pointer to the device extension.
+ Context - Supplies adapter initialization structure.
+ BusInformation - Unused.
+ ArgumentString - Unused.
+ ConfigInfo - Pointer to the configuration information structure.
+ Again - Indicates that system should continue search for adapters.
+
+Return Value:
+
+ SP_RETURN_FOUND - Indicates adapter found.
+ SP_RETURN_NOT_FOUND - Indicates adapter not found.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PACCESS_RANGE accessRange;
+
+ //
+ // Get access range.
+ //
+
+ accessRange = &((*(ConfigInfo->AccessRanges))[0]);
+
+ if (accessRange->RangeLength == 0) {
+
+ if (!SearchEisaBus(HwDeviceExtension,
+ Context,
+ ConfigInfo)) {
+
+
+ //
+ // Tell system nothing was found and not to call again.
+ //
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+ }
+
+ //
+ // Get system-mapped controller address.
+ //
+
+ deviceExtension->Bmic =
+ ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ accessRange->RangeStart,
+ accessRange->RangeLength,
+ (BOOLEAN)!accessRange->RangeInMemory);
+
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+
+
+ //
+ // Initialize controller.
+ //
+
+ DsaInitialize(deviceExtension);
+
+ //
+ // Get firmware version.
+ //
+
+ if (!ExtendedCommand(deviceExtension,
+ 0,
+ DDA_GET_FIRMWARE_VERSION)) {
+
+ DebugPrint((1,"DsaFindAdapter: Couldn't get firmware version\n"));
+ return SRB_STATUS_ERROR;
+ }
+
+ deviceExtension->MajorVersion =
+ ScsiPortReadPortUshort((PUSHORT)&deviceExtension->Bmic->Command);
+
+ deviceExtension->MinorVersion =
+ ScsiPortReadPortUshort((PUSHORT)&deviceExtension->Bmic->TransferCount);
+
+ //
+ // Release semaphore.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 0);
+
+ //
+ // Beta versions of DDA do not have scatter/gather. Versions prior
+ // to 1.23 have a starvation bug that makes command queueing risky.
+ // We simply won't run on these dinosaurs.
+ //
+
+ if (deviceExtension->MajorVersion == 1 &&
+ deviceExtension->MinorVersion <= 22) {
+
+ //
+ // Log error and return.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_BAD_FW_ERROR,
+ 5 << 8);
+
+ return SRB_STATUS_ERROR;
+ }
+
+ //
+ // DDA adapters support scatter/gather with the caveat that the descriptors
+ // must be sector aligned and can't handle large transfers.
+ //
+
+ if (deviceExtension->MajorVersion == 1) {
+ ConfigInfo->AlignmentMask = 511;
+ ConfigInfo->MaximumTransferLength = 0x8000;
+ ConfigInfo->NumberOfPhysicalBreaks = 8;
+ } else {
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+ }
+
+ //
+ // Get noncached extension for identify requests.
+ //
+
+ deviceExtension->IdentifyBuffer =
+ ScsiPortGetUncachedExtension(deviceExtension,
+ ConfigInfo,
+ 512);
+
+ //
+ // Get hardware configuration.
+ //
+
+ if (!ExtendedCommand(deviceExtension,
+ 0,
+ DDA_GET_HARDWARE_CONFIGURATION)) {
+
+ DebugPrint((1,"DsaFindAdapter: Couldn't get hw configuration\n"));
+ return SRB_STATUS_ERROR;
+ }
+
+ //
+ // Record interrupt level.
+ //
+
+ ConfigInfo->BusInterruptLevel = ScsiPortReadPortUchar(&deviceExtension->Bmic->Command);
+
+ //
+ // Release semaphore.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 0);
+
+ //
+ // Read Number of drives and emulation mode.
+ //
+
+ if (!ExtendedCommand(deviceExtension,
+ 0,
+ DDA_GET_NUMBER_LOGICAL_DRIVES)) {
+
+ DebugPrint((1,"DsaFindAdapter: Couldn't get number of drives\n"));
+
+ return SRB_STATUS_ERROR;
+ }
+
+ deviceExtension->NumberOfLogicalDrives =
+ ScsiPortReadPortUchar(&deviceExtension->Bmic->Command);
+ deviceExtension->EmulationMode =
+ ScsiPortReadPortUchar(&deviceExtension->Bmic->DriveNumber);
+
+ //
+ // Release semaphore.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->Bmic->SubmissionSemaphore, 0);
+
+ //
+ // Check if any logical drives reported.
+ //
+
+ DebugPrint((1,
+ "DsaFindAdapter: numDrives %d emulation %d\n",
+ deviceExtension->NumberOfLogicalDrives,
+ deviceExtension->EmulationMode));
+
+ if (!deviceExtension->NumberOfLogicalDrives) {
+
+ DebugPrint((1,"DsaFindAdapter: No logical drives defined\n"));
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // Tell system to look for more adapters.
+ //
+
+ *Again = TRUE;
+
+ return SP_RETURN_FOUND;
+
+} // end DsaFindAdapter()
+
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initial entry point for system initialization.
+
+Arguments:
+
+ DriverObject - System's representation of this driver.
+ Argument2 - Not used.
+
+Return Value:
+
+ BOOLEAN
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG eisaSlotNumber;
+ ULONG i;
+
+ DebugPrint((1,"\n\nDELL DSA/DDA Miniport Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = DsaInitialize;
+ hwInitializationData.HwResetBus = DsaResetBus;
+ hwInitializationData.HwStartIo = DsaStartIo;
+ hwInitializationData.HwInterrupt = DsaInterrupt;
+ hwInitializationData.HwFindAdapter = DsaFindAdapter;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize =
+ sizeof(DEVICE_EXTENSION);
+
+ //
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.NumberOfAccessRanges = 3;
+
+ //
+ // Ask for SRB extensions for command lists.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(DDA_REQUEST_BLOCK);
+
+ //
+ // Indicate that this controller supports multiple outstand
+ // requests to its devices.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // Set the context parameter to indicate that the search for controllers
+ // should start at the first EISA slot. This is only for a manual search
+ // by the miniport driver, if the system does not pass in predetermined
+ // configuration.
+ //
+
+ eisaSlotNumber = 0;
+
+ //
+ // Call the system to search for this adapter.
+ //
+
+ return
+ ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &eisaSlotNumber);
+
+} // end DriverEntry()
+
diff --git a/private/ntos/miniport/dell/delldsa.h b/private/ntos/miniport/dell/delldsa.h
new file mode 100644
index 000000000..b26ebaab2
--- /dev/null
+++ b/private/ntos/miniport/dell/delldsa.h
@@ -0,0 +1,210 @@
+
+#pragma pack(1)
+
+#define DELLDSA_MAJOR_VERSION 1
+#define DELLDSA_MINOR_VERSION 0
+
+#define MAXIMUM_SG_DESCRIPTORS 16
+#define MAXIMUM_DDA_SG_DESCRIPTORS 8
+#define MAXIMUM_XFER_SIZE 0x8000
+
+#define DDA_ID 0x0040ac10 // Least significant nibble will be masked.
+
+//
+// Logical Identify Command
+//
+
+typedef struct _DDA_INDENTIFY {
+ ULONG TotalSectors;
+ USHORT LogicalNumberOfHeads;
+ USHORT LogicalSectorsPerTrack;
+ USHORT TotalLogicalCylinders;
+ USHORT PhysicalNumberOfHeads;
+ USHORT PhysicalSectorsPerTrack;
+ USHORT TotalPhysicalCylinders;
+ USHORT ReservedCylinders;
+ UCHAR MaximumTransfer;
+ UCHAR Multiple;
+ USHORT DataDriveBitMap;
+ USHORT ParityDriveBitMap;
+ UCHAR ConfiguredType;
+ UCHAR Type;
+ UCHAR Status;
+ UCHAR Reserved;
+ ULONG PatchAddress;
+ ULONG ErrorLogAddress;
+ ULONG NumberErrorEventsLogged;
+ ULONG NumberRemappedStripes;
+ ULONG ErrorsPerDrive[10];
+ ULONG FirmWareRevision;
+ UCHAR EmulationMode;
+ UCHAR MaximumReadAhead;
+ UCHAR PostWritesEnabled;
+ UCHAR CacheEnabled;
+ ULONG BmicBurstSize;
+ UCHAR SourceRevision[32];
+} DDA_IDENTIFY, *PDDA_IDENTIFY;
+
+//
+// DDA BMIC Registers
+//
+
+typedef struct _DDA_REGISTERS {
+ ULONG BoardId; // ?C80
+ UCHAR Reserved1[5]; // ?C84
+ UCHAR InterruptControl; // ?C89
+ UCHAR SubmissionSemaphore; // ?C8A
+ UCHAR CompletionSemaphore; // ?C8B
+ UCHAR Reserved2; // ?C8C
+ UCHAR SubmissionDoorBell; // ?C8D
+ UCHAR CompletionInterruptMask; // ?C8E
+ UCHAR CompletionDoorBell; // ?C8F
+ UCHAR Command; // ?C90
+ UCHAR DriveNumber; // ?C91
+ UCHAR TransferCount; // ?C92
+ UCHAR RequestIdOut; // ?C93
+ ULONG StartingSector; // ?C94
+ ULONG DataAddress; // ?C98
+ UCHAR Status; // ?C9C
+ UCHAR SectorsRemaining; // ?C9D
+ UCHAR RequestIdIn; // ?C9E
+} DDA_REGISTERS, *PDDA_REGISTERS;
+
+//
+// Logical command definitions
+//
+
+#define DDA_COMMAND_RECALIBRATE 0x00
+#define DDA_COMMAND_READ 0x01
+#define DDA_COMMAND_WRITE 0x02
+#define DDA_COMMAND_VERIFY 0x03
+#define DDA_COMMAND_SEEK 0x04
+#define DDA_COMMAND_GUARDED 0x05
+#define DDA_COMMAND_IDENTIFY 0x0A
+#define DDA_COMMAND_READLOG 0x0D
+#define DDA_COMMAND_SG_READ 0x0E
+#define DDA_COMMAND_SG_WRITE 0x0F
+#define DDA_COMMAND_INITLOG 0x10
+#define DDA_COMMAND_REMAP_BLOCK 0x12
+#define DDA_COMMAND_SG_READB 0x18
+#define DDA_COMMAND_SG_WRITEB 0x19
+#define DDA_COMMAND_READPUNLOG 0x1E
+#define DDA_COMMAND_INITPUNLOG 0x1F
+#define DDA_COMMAND_READCTLRLOG 0x20
+#define DDA_COMMAND_INITCTLRLOG 0x21
+#define DDA_COMMAND_CONVERTPDEV 0x22
+#define DDA_COMMAND_QUIESCEPUN 0x23
+#define DDA_COMMAND_SCANDEVICES 0x24
+#define DDA_COMMAND_RESERVED1 0x25
+
+//
+// Extended command definitiions
+//
+
+#define DDA_GET_FIRMWARE_VERSION 0x02
+#define DDA_GET_MAXIMUM_COMMANDS 0x03
+#define DDA_GET_NUMBER_LOGICAL_DRIVES 0x06
+#define DDA_GET_LOGICAL_GEOMETRY 0x07
+#define DDA_GET_HARDWARE_CONFIGURATION 0x0F
+
+//
+// Status register definitions
+//
+
+#define DDA_STATUS_NO_ERROR 0x00
+#define DDA_STATUS_TIMEOUT 0x01
+#define DDA_STATUS_TRACK0_NOT_FOUND 0x02
+#define DDA_STATUS_ABORTED 0x04
+#define DDA_STATUS_CORRECTABLE_ERROR 0x08
+#define DDA_STATUS_SECTOR_ID_NOT_FOUND 0x10
+#define DDA_STATUS_WRITE_ERROR 0x20
+#define DDA_STATUS_UNCORRECTABLE_ERROR 0x40
+#define DDA_STATUS_BAD_BLOCK_FOUND 0x80
+
+#define DDA_PUP_DEAD 0 // controller died
+#define DDA_PUP_OK 1 // normal
+#define DDA_PUP_NOTCONFIG 2 // no configuration (virgin)
+#define DDA_PUP_BADCONFIG 3 // bad drive configuration
+#define DDA_PUP_RECOVER 4 // new drive - recovery possible
+#define DDA_PUP_DF_CORR 5 // drive failed - correctable
+#define DDA_PUP_DF_UNCORR 6 // drive failed - uncorrectable
+#define DDA_PUP_NODRIVES 7 // no drives attached
+#define DDA_PUP_DRIVESADDED 8 // more drives than expected
+#define DDA_PUP_MAINTAIN 9 // maintain mode
+#define DDA_PUP_MANFMODE 10 // manufacturing mode
+#define DDA_PUP_NEW 11 // new - needs remap generated
+#define DDA_PUP_NONE 14 // no drive configuration
+
+//
+// DDA Scatter/Gather Descriptor definitions
+//
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Address;
+ ULONG Count;
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+typedef struct _SG_LIST {
+ SG_DESCRIPTOR Descriptor[MAXIMUM_SG_DESCRIPTORS];
+} SG_LIST, *PSG_LIST;
+
+#define DDA_REQUEST_IRP 0
+#define DDA_REQUEST_IOCTL 1
+
+typedef struct _DDA_REQUEST_BLOCK {
+ SG_LIST SgList;
+ struct _DDA_REQUEST_BLOCK *Next;
+ ULONG StartingSector;
+ ULONG PhysicalAddress;
+ UCHAR Command;
+ UCHAR DriveNumber;
+ UCHAR Size;
+ UCHAR RequestId;
+} DDA_REQUEST_BLOCK, *PDDA_REQUEST_BLOCK;
+
+//
+// Emulation mode definitions
+//
+
+#define DDA_EMULATION_NONE 0x00
+#define DDA_EMULATION_ADAPTEC 0x01
+
+//
+// Get Geometry registers
+//
+
+typedef struct _DDA_GET_GEOMETRY {
+ ULONG Reserved[4];
+ ULONG TotalCapacity;
+ UCHAR NumberOfHeads;
+ UCHAR SectorsPerTrack;
+ USHORT NumberOfCylinders;
+ USHORT PhysicalSpt;
+ UCHAR PhysicalHeads;
+ UCHAR CurrentStatus;
+} DDA_GET_GEOMETRY, *PDDA_GET_GEOMETRY;
+
+#pragma pack()
+
+//
+// Doorbell definitions
+//
+
+#define DDA_DOORBELL_SOFT_RESET 0x08
+#define DDA_DOORBELL_LOGICAL_COMMAND 0x10
+#define DDA_DOORBELL_PHYSICAL_COMMAND 0x20
+#define DDA_DOORBELL_EXTENDED_COMMAND 0x40
+#define DDA_DOORBELL_HARD_RESET 0x80
+
+#define DDA_INTERRUPTS (DDA_DOORBELL_LOGICAL_COMMAND|DDA_DOORBELL_EXTENDED_COMMAND)
+
+//
+// Interface mode values
+//
+
+#define IMODE_RUN 0
+#define IMODE_RESET 1
+#define IMODE_SUBMIT 2
+#define IMODE_EXTENDED 3
+#define IMODE_EXTDONE 4
+
diff --git a/private/ntos/miniport/dell/delldsa.rc b/private/ntos/miniport/dell/delldsa.rc
new file mode 100644
index 000000000..4281469e1
--- /dev/null
+++ b/private/ntos/miniport/dell/delldsa.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Dell Disk Array Driver"
+#define VER_INTERNALNAME_STR "delldsa.sys"
+#define VER_ORIGINALFILENAME_STR "delldsa.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/dell/makefile b/private/ntos/miniport/dell/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/dell/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/dell/sources b/private/ntos/miniport/dell/sources
new file mode 100644
index 000000000..80ff399f7
--- /dev/null
+++ b/private/ntos/miniport/dell/sources
@@ -0,0 +1,40 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=delldsa
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+!IF $(ALPHA)
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib $(BASEDIR)\public\sdk\lib\*\libcntpr.lib
+!ENDIF
+SOURCES=delldsa.c delldsa.rc
+
+
diff --git a/private/ntos/miniport/dirs b/private/ntos/miniport/dirs
new file mode 100644
index 000000000..287b6d29f
--- /dev/null
+++ b/private/ntos/miniport/dirs
@@ -0,0 +1,56 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=aha154x \
+ aha174x \
+ always \
+ \
+ \
+ atapi \
+ buslogic \
+ compaq \
+ dell \
+ \
+ dtc \
+ \
+ \
+ \
+ \
+ mitsumi \
+ mylex \
+ ncr53c94 \
+ oliscsi \
+ qlogic \
+ spock \
+ trantor \
+ ultra14f \
+ ultra124 \
+ ultra24f \
+ wd33c93 \
+ wd7000ex
+
+OPTIONAL_DIRS= \
+ \
+ \
+ scsiwdl \
+ \
+ symbios
diff --git a/private/ntos/miniport/dtc/dtc329x.c b/private/ntos/miniport/dtc/dtc329x.c
new file mode 100644
index 000000000..4be0fdeb7
--- /dev/null
+++ b/private/ntos/miniport/dtc/dtc329x.c
@@ -0,0 +1,2588 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dtc329x.c
+
+Abstract:
+
+ This is the port driver for the DTC 3290 and DTC 3292
+ EISA SCSI Adapter. This code is based on Microsoft NT aha154x.c
+ modified. ALL modifications can be turned off by setting DTC329X
+ to 0 in dtc3290.h file. Also all the names starting aha154x and a154x
+ have been changed to dtc329x and d329x.
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "dtc329x.h" // includes scsi.h
+
+//
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//
+
+CONST ULONG AdapterAddresses[] = {0X330, 0X334, 0X234, 0X134, 0X130, 0X230, 0};
+
+
+#ifdef DTC329X
+#define DTC_MAILBOX_INITIALIZATION 0x42
+CONST ULONG DTC3290IOAddresses[] = {0X330, 0X334, 0X230, 0X234, 0X130, 0X134, 0};
+CONST ULONG DTC3292IOAddresses[] = {0,0,0X130, 0X134, 0X230, 0X234, 0X330, 0X334, 0};
+#endif
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+
+typedef struct _NONCACHED_EXTENSION {
+
+ //
+ // Physical base address of mailboxes
+ //
+
+ ULONG MailboxPA;
+
+ //
+ // Mailboxes
+ //
+
+ MBO Mbo[MB_COUNT];
+ MBI Mbi[MB_COUNT];
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ //
+ // NonCached extension
+ //
+
+ PNONCACHED_EXTENSION NoncachedExtension;
+
+ //
+ // Adapter parameters
+ //
+
+ PBASE_REGISTER BaseIoAddress;
+
+ //
+ // Host Target id.
+ //
+
+ UCHAR HostTargetId;
+
+ BOOLEAN Dtc3290;
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+//
+// Logical unit extension
+//
+
+typedef struct _HW_LU_EXTENSION {
+ PSCSI_REQUEST_BLOCK CurrentSrb;
+} HW_LU_EXTENSION, *PHW_LU_EXTENSION;
+
+
+
+#ifdef DTC329X
+
+// Following algorithm provides the way to detect
+// DTC 3x90 or DTC3x92 presented in the system by
+// scanning EISA slot and check DTC controller ID
+// pattern
+
+
+#define ID_DTC_BYTE0 0x12
+#define ID_DTC_BYTE1 0x83
+#define ID_DTC_3x90_BYTE2 0x31
+#define ID_DTC_3x92_BYTE2 0x39
+#define D3292_IO_MASK 0x7
+#define D3290_IO_MASK 0xf
+
+
+
+#define DTC_GET_CONFIG_CMD 0x41
+#define DTC_ENABLE_INT_CMD 0x1
+#define DTC_CLR_INT_CMD 0x1
+#define DTC_RESET_CONFIG_CMD 0x0
+
+
+
+#define PROD_ID_REG 0xc80
+#define D3292_IO_REG 0xc9f
+#define D3290_IO_REG 0xc91
+
+#define D3290_CONFIG_IO_REG 0xc90
+#define D3290_DOOR_BELL_REG 0xc8d
+#define D3290_CLR_INT_IO_REG 0xc8f
+
+#define TOTAL_EISA_SLOT 0x10
+
+#endif
+
+
+//
+// Function declarations
+//
+// Functions that start with 'D329X' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+D329XEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+D329XDetermineInstalled(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount,
+ OUT PBOOLEAN Again
+ );
+
+ULONG
+D329XFindAdapter (
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+D329XHwInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+D329XStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+D329XInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+D329XResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+//
+// This function is called from D329XStartIo.
+//
+
+VOID
+BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BuildCcb.
+//
+
+VOID
+BuildSdl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from D329XInitialize.
+//
+
+BOOLEAN
+AdapterPresent(
+ IN PVOID HwDeviceExtension
+ );
+
+//
+// This function is called from D329XInterrupt.
+//
+
+UCHAR
+MapError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCCB Ccb
+ );
+
+BOOLEAN
+ReadCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR DataByte
+ );
+
+BOOLEAN
+WriteCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR AdapterCommand
+ );
+
+
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG adapterCount;
+ ULONG i;
+
+ DebugPrint((1,"\n\nSCSI DTC 329X MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = D329XHwInitialize;
+ hwInitializationData.HwResetBus = D329XResetBus;
+ hwInitializationData.HwStartIo = D329XStartIo;
+ hwInitializationData.HwInterrupt = D329XInterrupt;
+ hwInitializationData.HwFindAdapter = D329XFindAdapter;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
+
+ //
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.NumberOfAccessRanges = 1;
+
+ //
+ // Ask for SRB extensions for CCBs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(CCB);
+
+ //
+ // The adapter count is used by the find adapter routine to track how
+ // which adapter addresses have been tested.
+ //
+
+ adapterCount = 0;
+ return ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount);
+} // end D329XEntry()
+
+
+ULONG
+D329XFindAdapter (
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - Register base address
+ ConfigInfo - Configuration information structure describing HBA
+ This structure is defined in PORT.H.
+
+Return Value:
+
+ ULONG
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG length;
+ ULONG status;
+ UCHAR adapterTid;
+ UCHAR dmaChannel;
+ UCHAR irq;
+ UCHAR bit;
+
+ //
+ // Determine if there are any adapters installed. Determine installed
+ // will initialize the BaseIoAddress if an adapter is found.
+ //
+
+ status = D329XDetermineInstalled(deviceExtension,
+ ConfigInfo,
+ Context,
+ Again);
+
+ //
+ // If there are not adapter's found then return.
+ //
+
+ if (status != SP_RETURN_FOUND) {
+ return(status);
+ }
+
+#if 0
+ //
+ // Set up device extension pointer to 154x mailboxes
+ // in noncached extension.
+ //
+
+ deviceExtension->NoncachedExtension = 0;
+
+ //
+ // Convert virtual to physical mailbox address.
+ //
+
+ deviceExtension->NoncachedExtension->MailboxPA =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension->Mbo,
+ &length));
+
+ //
+ // Assume that physical address is below 16M
+ //
+
+ ASSERT(deviceExtension->NoncachedExtension->MailboxPA < 0x1000000);
+
+ //
+ // Reset the DTC329X.
+ //
+
+ if (!D329XResetBus(deviceExtension, 0)) {
+ DebugPrint((1,"D329XFindAdapter: Reset SCSI bus failed\n"));
+ return FALSE;
+ }
+
+ DebugPrint((1,"D329XFindAdapter: Reset completed\n"));
+#endif
+
+ //
+ // Issue adapter command to get IRQ.
+ //
+ // Returns 3 data bytes:
+ //
+ // Byte 0 Dma Channel
+ //
+ // Byte 1 Interrupt Channel
+ //
+ // Byte 2 Adapter SCSI ID
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ AC_RET_CONFIGURATION_DATA)) {
+ DebugPrint((1,"D329XFindAdapter: Get configuration data command failed\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Determine DMA channel.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&dmaChannel)) {
+ DebugPrint((1,"D329XFindAdapter: Couldn't read dma channel\n"));
+ return SP_RETURN_ERROR;
+ }
+
+#if 0 // Commented out because EISA should not do this: 4/18/94
+ WHICH_BIT(dmaChannel,bit);
+
+ ConfigInfo->DmaChannel = bit;
+
+ DebugPrint((2,"D329XFindAdapter: DMA channel is %x\n",
+ ConfigInfo->DmaChannel));
+#endif
+
+ //
+ // Determine hardware interrupt vector.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&irq)) {
+ DebugPrint((1,"D329XFindAdapter: Couldn't read adapter irq\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ WHICH_BIT(irq, bit);
+
+ ConfigInfo->BusInterruptLevel = (UCHAR) 9 + bit;
+
+ //
+ // Determine what SCSI bus id the adapter is on.
+ //
+
+ if (!ReadCommandRegister(deviceExtension,&adapterTid)) {
+ DebugPrint((1,"D329XFindAdapter: Couldn't read adapter SCSI id\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Set number of buses.
+ //
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InitiatorBusId[0] = adapterTid;
+ deviceExtension->HostTargetId = adapterTid;
+
+ ConfigInfo->MaximumTransferLength = MAX_TRANSFER_SIZE;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_DESCRIPTORS - 1;
+
+ //
+ // Allocate a Noncached Extension to use for mail boxes.
+ //
+
+ deviceExtension->NoncachedExtension = ScsiPortGetUncachedExtension(
+ deviceExtension,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ if (deviceExtension->NoncachedExtension == NULL) {
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 6 << 16
+ );
+
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // Convert virtual to physical mailbox address.
+ //
+
+ deviceExtension->NoncachedExtension->MailboxPA =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension->Mbo,
+ &length));
+
+ //
+ // Assume that physical address is below 16M
+ //
+
+ ASSERT(deviceExtension->NoncachedExtension->MailboxPA < 0x1000000);
+
+#if 0
+ //
+ // Reset the DTC329X.
+ //
+
+ if (!D329XResetBus(deviceExtension, 0)) {
+ DebugPrint((1,"D329XFindAdapter: Reset SCSI bus failed\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ DebugPrint((1,"D329XFindAdapter: Reset completed\n"));
+#endif
+
+ DebugPrint((3,"D329XFindAdapter: Configuration completed\n"));
+
+ return SP_RETURN_FOUND;
+
+} // end D329XFindAdapter()
+
+
+ULONG
+D329XDetermineInstalled(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if DTC 329X SCSI adapter is installed in system
+ by reading the status register as each base I/O address
+ and looking for a DTC EISA pattern. If an adapter is found,
+ the BaseIoAddres is initialized.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+ ConfigInfo - Supplies the known configuraiton information.
+
+ AdapterCount - Supplies the count of adapter slots which have been tested.
+
+ Again - Returns whehter the OS specific driver should call again.
+
+Return Value:
+
+ Returns a status indicating whether a driver is present or not.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PBASE_REGISTER baseIoAddress;
+ PUCHAR ioSpace;
+ PUCHAR slotSpace;
+ UCHAR portValue; // 03-27-93
+ BOOLEAN dtc3290; // 04-09-93, = true if dtc3290 else false
+ UCHAR status;
+
+#ifdef DTC329X
+ ULONG adapterio;
+ ULONG i;
+ ULONG j;
+ UCHAR loid;
+ UCHAR miid;
+ UCHAR hiid;
+ ULONG tempioindex;
+#endif
+
+ //
+ // Get the system physical address for this card. The card uses I/O space.
+ //
+
+ ioSpace = ScsiPortGetDeviceBase(
+ HwDeviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress(0),
+ 0x400, // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+ //
+ // Scan though the adapter address looking for adapters.
+ //
+
+ while (AdapterAddresses[*AdapterCount] != 0) {
+
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ baseIoAddress = (PBASE_REGISTER)(ioSpace +
+ AdapterAddresses[*AdapterCount]);
+
+#ifdef DTC329X
+ adapterio = AdapterAddresses[*AdapterCount];
+#endif
+
+
+ //
+ // Update the adapter count.
+ //
+
+ (*AdapterCount)++;
+
+ portValue = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ //
+ // Check for Adaptec adapter.
+ // The mask (0x29) are bits that may or may not be set.
+ // The bit 0x10 (IOP_SCSI_HBA_IDLE) should be set.
+ //
+
+ if (!((portValue & ~0x29) == IOP_SCSI_HBA_IDLE)) {
+
+ //
+ // Board in funky state. Reset it.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
+
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ DebugPrint((2,"ResetBus: Wait done\n"));
+
+ if (!(status & IOP_SCSI_HBA_IDLE)) {
+
+ //
+ // The DTC sometimes needs a soft reset to recover.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->BaseIoAddress->StatusRegister, IOP_SOFT_RESET);
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(5);
+
+ status = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ }
+ }
+
+ portValue = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
+
+ if ((portValue & ~0x29) == IOP_SCSI_HBA_IDLE) { /* 03-27-93 */
+
+#ifdef DTC329X
+
+ // following code will make sure that only dtc3292 or dtc3290 board
+ // is recoginzed by this driver by checking current dtc board IO
+ // address (get from EISA config reg).
+
+
+ for (i= 0x1000; i< TOTAL_EISA_SLOT * 0x1000; i=i+0x1000) {
+
+ slotSpace = ScsiPortGetDeviceBase(
+ HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(i),
+ 0x1000,
+ TRUE);
+ loid = ScsiPortReadPortUchar(slotSpace + PROD_ID_REG);
+ miid = ScsiPortReadPortUchar(slotSpace + PROD_ID_REG + 1);
+ hiid = ScsiPortReadPortUchar(slotSpace + PROD_ID_REG + 2);
+
+ if (loid == ID_DTC_BYTE0 && miid == ID_DTC_BYTE1 ) {
+
+ switch (hiid ) {
+ case ID_DTC_3x90_BYTE2:
+ ScsiPortReadPortUchar(slotSpace+D3290_CONFIG_IO_REG); // dummy read
+ ScsiPortWritePortUchar(slotSpace+D3290_CONFIG_IO_REG,DTC_GET_CONFIG_CMD);
+ ScsiPortWritePortUchar(slotSpace+D3290_DOOR_BELL_REG,DTC_ENABLE_INT_CMD);
+ for (j = 0; j < 2000000; j++) {
+ ScsiPortStallExecution(1);
+ if (ScsiPortReadPortUchar(slotSpace+D3290_CONFIG_IO_REG) & 0x80)
+ break;
+ }
+
+ tempioindex = ScsiPortReadPortUchar(slotSpace+D3290_IO_REG);
+ ScsiPortWritePortUchar(slotSpace+D3290_CLR_INT_IO_REG,DTC_CLR_INT_CMD);
+ ScsiPortWritePortUchar(slotSpace+D3290_CONFIG_IO_REG,DTC_RESET_CONFIG_CMD);
+
+ ScsiPortStallExecution(4000 * 1000); /* 03-27-93 */
+
+ if (adapterio == DTC3290IOAddresses[tempioindex & D3290_IO_MASK])
+ {
+ dtc3290 = TRUE;
+ goto find_dtc;
+ }
+ else
+ break;
+
+ case ID_DTC_3x92_BYTE2:
+ tempioindex = ScsiPortReadPortUchar(slotSpace+D3292_IO_REG);
+ if (adapterio == DTC3292IOAddresses[tempioindex & D3292_IO_MASK])
+ {
+ dtc3290 = FALSE;
+ goto find_dtc;
+ }
+ else
+ break;
+
+ default:
+ break;
+ }
+ }
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ (PVOID) slotSpace);
+ }
+
+ if (i == TOTAL_EISA_SLOT * 0x1000 )
+ continue;
+
+ find_dtc:
+#endif
+
+
+ DebugPrint((1,"D329X: Base IO address is %x\n", baseIoAddress));
+
+ //
+ // An adapter has been found. Set the base address in the device
+ // extension, and request another call.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_SOFT_RESET); /* 03-27-93 */
+ ScsiPortStallExecution(3000*1000);
+ HwDeviceExtension->BaseIoAddress = baseIoAddress;
+ *Again = TRUE;
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ AdapterAddresses[*AdapterCount - 1]);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = 4;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ deviceExtension->Dtc3290 = dtc3290;
+
+ if (dtc3290) ConfigInfo->CachesData = TRUE; // 04-09-93
+ else ConfigInfo->CachesData = FALSE;
+
+ return SP_RETURN_FOUND;
+ }
+ }
+
+ //
+ // The entire table has been searched and no adapters have been found.
+ // There is no need to call again and the device base can now be freed.
+ // Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *(AdapterCount) = 0;
+
+ ScsiPortFreeDeviceBase(
+ HwDeviceExtension,
+ ioSpace
+ );
+
+ return SP_RETURN_NOT_FOUND;
+
+} // end D329XDetermineInstalled()
+
+
+BOOLEAN
+D329XHwInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a required entry point.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR status;
+ ULONG i;
+
+ DebugPrint((2,"D329XHwInitialize: Reset DTC329X and SCSI bus\n"));
+
+ //
+ // Reset SCSI chip.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_SOFT_RESET);
+
+ ScsiPortStallExecution(2000*1000); /* 03-27-93 */
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+ }
+
+ //
+ // Inform the port driver that the bus has been reset.
+ //
+
+ ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
+
+ //
+ // Check if reset failed or succeeded.
+ //
+
+ if (!(status & IOP_SCSI_HBA_IDLE) || !(status & IOP_MAILBOX_INIT_REQUIRED)) {
+
+ DebugPrint((1, "D329XHwInitialize: Soft reset failed.\n"));
+
+ //
+ // If the soft reset does not work, try a hard reset.
+ //
+
+ if (!D329XResetBus(HwDeviceExtension, 0)) {
+ DebugPrint((1,"D329XHwInitialize: Reset SCSI bus failed\n"));
+ return FALSE;
+ }
+
+ DebugPrint((1,"D329XHwInitialize: Reset completed\n"));
+
+ return TRUE;
+ }
+
+ //
+ // Zero out mailboxes.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+
+ mailboxIn = &noncachedExtension->Mbi[i];
+ mailboxOut = &noncachedExtension->Mbo[i];
+
+ mailboxOut->Command = mailboxIn->Status = 0;
+ }
+
+ DebugPrint((3,"ResetBus: Initialize mailbox\n"));
+
+#ifndef DTC329X
+ if (!WriteCommandRegister(deviceExtension,AC_MAILBOX_INITIALIZATION)) {
+ DebugPrint((1,"D329XResetBus: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the middle byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+#else
+
+ if (!WriteCommandRegister(deviceExtension,DTC_MAILBOX_INITIALIZATION)) {
+ DebugPrint((1,"D329XResetBus: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+
+ for (i=0; i < 250000; i++)
+ ScsiPortStallExecution(1);
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+ //
+ // Send the 2nd byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the 3rd byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte3)) {
+ return FALSE;
+ }
+
+#endif
+
+ DebugPrint((3,"ResetBus: Initialize mailbox done\n"));
+ return TRUE;
+
+} // end D329XHwInitialize()
+
+
+BOOLEAN
+D329XStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel. The mailboxes are scanned for an empty one and
+ the CCB is written to it. Then the doorbell is rung and the
+ OS port driver is notified that the adapter can take
+ another request, if any are available.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PMBO mailboxOut;
+ PCCB ccb;
+ PHW_LU_EXTENSION luExtension;
+ ULONG physicalCcb;
+ ULONG length;
+ ULONG i = 0;
+
+ DebugPrint((3,"D329XStartIo: Enter routine\n"));
+
+ //
+ // Check if command is an ABORT request.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ if (!luExtension->CurrentSrb) {
+
+ DebugPrint((1, "D329XStartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get CCB to abort.
+ //
+
+ ccb = Srb->NextSrb->SrbExtension;
+
+ //
+ // Set abort SRB for completion.
+ //
+
+ ccb->AbortSrb = Srb;
+
+ } else {
+
+ ccb = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in CCB.
+ //
+
+ ccb->SrbAddress = Srb;
+ }
+
+ //
+ // Get CCB physical address.
+ //
+
+ physicalCcb = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, ccb, &length));
+
+ //
+ // Assume physical address is contiguous for size of CCB.
+ //
+
+ ASSERT(length >= sizeof(CCB));
+
+ //
+ // Find free mailboxOut.
+ //
+
+ do {
+
+ mailboxOut = &noncachedExtension->Mbo[i % MB_COUNT];
+ i++;
+
+ } while (mailboxOut->Command != MBO_FREE);
+
+ DebugPrint((3,"D329XStartIo: MBO address %lx, Loop count = %d\n", mailboxOut, i));
+
+ //
+ // Write CCB to mailbox.
+ //
+
+#ifndef DTC329X
+
+ FOUR_TO_THREE(&mailboxOut->Address,
+ (PFOUR_BYTE)&physicalCcb);
+#else
+
+ FOUR_TO_FOUR(&mailboxOut->Address,(PFOUR_BYTE)&physicalCcb);
+
+#endif
+
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1, "D329XStartIo: Abort request received\n"));
+
+ //
+ // NOTE: Race condition if aborts occur
+ // (what if CCB to be aborted
+ // completes after setting new SrbAddress?)
+ //
+
+ mailboxOut->Command = MBO_ABORT;
+
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset DTC329X and SCSI bus.
+ //
+
+ DebugPrint((1, "D329XStartIo: Reset bus request received\n"));
+
+ if (!D329XResetBus(
+ deviceExtension,
+ Srb->PathId
+ )) {
+
+ DebugPrint((1,"D329XStartIo: Reset bus failed\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ return TRUE;
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ //
+ // Move SRB to logical unit extension.
+ //
+
+ luExtension->CurrentSrb = Srb;
+
+ //
+ // Build CCB.
+ //
+
+ BuildCcb(deviceExtension, Srb);
+
+ mailboxOut->Command = MBO_START;
+
+ break;
+
+ case SRB_FUNCTION_SHUTDOWN:
+ case SRB_FUNCTION_FLUSH: // 04-09-93, implement flush cache
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ //
+ // Move SRB to logical unit extension.
+ //
+
+ luExtension->CurrentSrb = Srb;
+
+ //
+ // Build CCB.
+ //
+
+ BuildCcb(deviceExtension, Srb);
+
+ ccb->Cdb[0] = REZERO_UNIT_CMD; // re-zero will force F/W to
+ // flush cache
+ ccb->Cdb[1] = 0; // LU
+ ccb->Cdb[2] = 0; // reserved
+ ccb->Cdb[3] = 0; // reserved
+ ccb->Cdb[4] = 0; // reserved
+ ccb->Cdb[5] = 0; // control byte
+ ccb->CdbLength = 6;
+
+ mailboxOut->Command = MBO_START;
+
+ DebugPrint((1, "D329XStartIo: Flush cache sent\n"));
+
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ DebugPrint((1,"D329XStartIo: Reset device not supported\n"));
+
+ //
+ // Drop through to default.
+ //
+
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // Tell 154xb a CCB is available now.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,AC_START_SCSI_COMMAND)) {
+
+ //
+ // Let request time out and fail.
+ //
+
+ DebugPrint((1,"D329XStartIo: Can't write command to adapter\n"));
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end D329XStartIo()
+
+
+BOOLEAN
+D329XInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the adaptec 154x SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the CCB is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PCCB ccb;
+ PSCSI_REQUEST_BLOCK srb;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ PMBI mailboxIn;
+ ULONG physicalCcb;
+ PHW_LU_EXTENSION luExtension;
+ ULONG i;
+
+ UCHAR InterruptFlags;
+
+ InterruptFlags = ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister);
+
+ //
+ // Determine cause of interrupt.
+ //
+
+ if (InterruptFlags & IOP_COMMAND_COMPLETE) {
+
+ //
+ // Adapter command completed.
+ //
+
+ DebugPrint((2,"D329XInterrupt: Adapter Command complete\n"));
+ DebugPrint((3,"D329XInterrupt: Interrupt flags %x\n", InterruptFlags));
+ DebugPrint((3,"D329XInterrupt: Status %x\n",
+ ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ return TRUE;
+
+ } else if (InterruptFlags & IOP_MBI_FULL) {
+
+ DebugPrint((3,"D329XInterrupt: MBI Full\n"));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ } else if (InterruptFlags & IOP_SCSI_RESET_DETECTED) {
+
+ DebugPrint((1,"D329XInterrupt: SCSI Reset detected\n"));
+
+ //
+ // Clear interrupt on adapter.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
+
+ //
+ // Notify of reset.
+ //
+
+ ScsiPortNotification(ResetDetected,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } else {
+
+ DebugPrint((4,"D329XInterrupt: Spurious interrupt\n"));
+
+ return FALSE;
+ }
+
+ //
+ // Determine which MailboxIn location contains the CCB.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ mailboxIn = &noncachedExtension->Mbi[i];
+
+ //
+ // Look for a mailbox entry with a legitimate status.
+ //
+
+ if ((mailboxIn->Status == MBI_SUCCESS) ||
+ (mailboxIn->Status == MBI_ERROR) ||
+ (mailboxIn->Status == MBI_ABORT) ||
+ (mailboxIn->Status == MBI_NOT_FOUND)) {
+
+ //
+ // MBI found.
+ //
+
+ DebugPrint((3,"D329XInterrupt: MBI address %lx\n", mailboxIn));
+ break;
+ }
+ }
+
+ if (i == MB_COUNT) {
+
+ //
+ // No mail. Indicate interrupt was not serviced.
+ //
+
+ DebugPrint((1, "D329XInterrupt: No CCB in mailboxes\n"));
+
+ return TRUE;
+ }
+
+ //
+ // Convert CCB to big endian.
+ //
+
+#ifndef DTC329X
+
+ THREE_TO_FOUR((PFOUR_BYTE)&physicalCcb,
+ &mailboxIn->Address);
+#else
+
+ FOUR_TO_FOUR((PFOUR_BYTE)&physicalCcb, &mailboxIn->Address);
+
+#endif
+
+ DebugPrint((3, "D329XInterrupt: Physical CCB %lx\n", physicalCcb));
+
+ //
+ // Check if physical CCB is zero.
+ // This is done to cover for hardware errors.
+ //
+
+ if (!physicalCcb) {
+
+ DebugPrint((1,"D329XInterrupt: Physical CCB address is 0\n"));
+ return TRUE;
+ }
+
+ //
+ // Convert Physical CCB to Virtual.
+ //
+
+ ccb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalCcb));
+
+
+ DebugPrint((3, "D329XInterrupt: Virtual CCB %lx\n", ccb));
+
+ //
+ // Make sure the virtual address was found.
+ //
+
+ if (ccb == NULL) {
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 5 << 8
+ );
+
+ return(TRUE);
+
+ }
+
+ //
+ // Get SRB from CCB.
+ //
+
+ srb = ccb->SrbAddress;
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun);
+
+ //
+ // Make sure the luExtension was found and it has a current request.
+ //
+
+ if (luExtension == NULL || (luExtension->CurrentSrb == NULL &&
+ mailboxIn->Status != MBI_NOT_FOUND)) {
+
+
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (6 << 8) | mailboxIn->Status
+ );
+
+ return(TRUE);
+
+ }
+
+ //
+ // Check MBI status.
+ //
+
+ switch (mailboxIn->Status) {
+
+ case MBI_SUCCESS:
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ ASSERT(luExtension->CurrentSrb);
+
+ luExtension->CurrentSrb = NULL;
+
+ break;
+
+ case MBI_NOT_FOUND:
+
+ DebugPrint((1, "D329XInterrupt: CCB abort failed %lx\n", ccb));
+
+ srb = ccb->AbortSrb;
+
+ srb->ScsiStatus = SRB_STATUS_ABORT_FAILED;
+
+ //
+ // Check if SRB still outstanding.
+ //
+
+ if (luExtension->CurrentSrb) {
+
+ //
+ // Complete this SRB.
+ //
+
+ luExtension->CurrentSrb->SrbStatus = SRB_STATUS_TIMEOUT;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ luExtension->CurrentSrb);
+
+ luExtension->CurrentSrb = NULL;
+ }
+
+ break;
+
+ case MBI_ABORT:
+
+ DebugPrint((1, "D329XInterrupt: CCB aborted\n"));
+
+ //
+ // Update target status in aborted SRB.
+ //
+
+ srb->SrbStatus = SRB_STATUS_ABORTED;
+
+ //
+ // Call notification routine for the aborted SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ luExtension->CurrentSrb = NULL;
+
+ //
+ // Get the abort SRB from CCB.
+ //
+
+ srb = ccb->AbortSrb;
+
+ //
+ // Set status for completing abort request.
+ //
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ break;
+
+ case MBI_ERROR:
+
+ DebugPrint((2, "D329XInterrupt: Error occurred\n"));
+
+ srb->SrbStatus = MapError(deviceExtension, srb, ccb);
+
+ DebugPrint((2, "D329XInterrupt: SrbStatus = %x\n",srb->SrbStatus));
+ //
+ // Check if ABORT command.
+ //
+
+ if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Check if SRB still outstanding.
+ //
+
+ if (luExtension->CurrentSrb) {
+
+ //
+ // Complete this SRB.
+ //
+
+ luExtension->CurrentSrb->SrbStatus = SRB_STATUS_TIMEOUT;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ luExtension->CurrentSrb);
+
+ }
+
+ DebugPrint((1,"D329XInterrupt: Abort command failed\n"));
+ }
+
+ luExtension->CurrentSrb = NULL;
+
+ break;
+
+ default:
+
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (1 << 8) | mailboxIn->Status
+ );
+
+ DebugPrint((1, "D329XInterrupt: Unrecognized mailbox status\n"));
+
+ mailboxIn->Status = MBI_FREE;
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // Indicate MBI is available.
+ //
+
+ mailboxIn->Status = MBI_FREE;
+
+ DebugPrint((2, "D329XInterrupt: SCSI Status %x\n", srb->ScsiStatus));
+
+ DebugPrint((2, "D329XInterrupt: Adapter Status %x\n", ccb->HostStatus));
+
+ //
+ // Update target status in SRB.
+ //
+
+ srb->ScsiStatus = ccb->TargetStatus;
+
+ DebugPrint((2, "D329XInterrupt: Target Status %x\n", ccb->TargetStatus));
+
+ //
+ // Signal request completion.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ return TRUE;
+
+} // end D329XInterrupt()
+
+
+VOID
+BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build CCB for 154x.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PCCB ccb = Srb->SrbExtension;
+
+ DebugPrint((3,"BuildCcb: Enter routine\n"));
+
+ //
+ // Set CCB Operation Code.
+ //
+
+ ccb->OperationCode = SCATTER_GATHER_COMMAND;
+
+ //
+ // Set target id and LUN.
+ //
+
+ ccb->ControlByte = (UCHAR)(Srb->TargetId << 5) | Srb->Lun;
+
+ //
+ // Set transfer direction bit.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+ ccb->ControlByte |= CCB_DATA_XFER_OUT;
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ccb->ControlByte |= CCB_DATA_XFER_IN;
+ }
+
+ //
+ // 01h disables auto request sense.
+ //
+
+ ccb->RequestSenseLength = 1;
+
+ //
+ // Set CDB length and copy to CCB.
+ //
+
+ ccb->CdbLength = (UCHAR)Srb->CdbLength;
+
+ ScsiPortMoveMemory(ccb->Cdb, Srb->Cdb, ccb->CdbLength);
+
+ //
+ // Set reserved bytes to zero.
+ //
+
+ ccb->Reserved[0] = 0;
+ ccb->Reserved[1] = 0;
+
+ ccb->LinkIdentifier = 0;
+
+ //
+ // Zero link pointer.
+ //
+
+
+#ifdef DTC329X
+ ccb->LinkPointer.Byte0 = 0;
+ ccb->LinkPointer.Byte1 = 0;
+ ccb->LinkPointer.Byte2 = 0;
+ ccb->LinkPointer.Byte3 = 0;
+#else
+ ccb->LinkPointer.Lsb= 0;
+ ccb->LinkPointer.Msb = 0;
+ ccb->LinkPointer.Mid = 0;
+#endif
+
+ //
+ // Build SDL in CCB if data transfer.
+ //
+ if (Srb->DataTransferLength > 0) {
+
+ BuildSdl(DeviceExtension, Srb);
+
+ } else {
+ FOUR_TO_FOUR(&ccb->DataLength, (PFOUR_BYTE)&Srb->DataTransferLength);
+ FOUR_TO_FOUR(&ccb->DataPointer, (PFOUR_BYTE)&Srb->DataTransferLength);
+ ccb->OperationCode = SCSI_INITIATOR_COMMAND;
+
+ }
+
+ ccb->TargetStatus = 0;
+ ccb->HostStatus = 0;
+
+ return;
+
+} // end BuildCcb()
+
+
+VOID
+BuildSdl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list for the CCB.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PCCB ccb = Srb->SrbExtension;
+ PSDL sdl = &ccb->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG four;
+ ULONG i = 0;
+
+ DebugPrint((3,"BuildSdl: Enter routine\n"));
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SDL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SDL));
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+
+ DebugPrint((3, "BuildSdl: Data buffer %lx\n", dataPointer));
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "BuildSdl: Physical address %lx\n", physicalAddress));
+ DebugPrint((3, "BuildSdl: Data length %lx\n", length));
+ DebugPrint((3, "BuildSdl: Bytes left %lx\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ four = length;
+
+#ifndef DTC329X
+
+ //
+ // Convert length to 3-byte big endian format.
+ //
+
+ three = &sdl->Sgd[i].Length;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+
+#else
+ //
+ // Keep original little endian format
+ //
+ FOUR_TO_FOUR(&sdl->Sgd[i].Length,(PFOUR_BYTE)&four);
+
+#endif
+
+ four = (ULONG)physicalAddress;
+
+#ifndef DTC329X
+
+ //
+ // Convert physical address to 3-byte big endian format.
+ //
+
+ three = &sdl->Sgd[i].Address;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+
+#else
+ //
+ // Keep original little endian format
+ //
+ FOUR_TO_FOUR(&sdl->Sgd[i].Address,(PFOUR_BYTE)&four);
+
+#endif
+ i++;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+
+ } while (bytesLeft);
+
+ //
+ // Write SDL length to CCB.
+ //
+
+ four = i * sizeof(SGD);
+
+#ifndef DTC329X
+
+ three = &ccb->DataLength;
+ FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
+
+#else
+
+ FOUR_TO_FOUR(&ccb->DataLength, (PFOUR_BYTE)&four);
+
+#endif
+
+ DebugPrint((3,"BuildSdl: SDL length is %d\n", four));
+
+ //
+ // Write SDL address to CCB.
+ //
+
+#ifndef DTC329X
+
+ FOUR_TO_THREE(&ccb->DataPointer,
+ (PFOUR_BYTE)&physicalSdl);
+#else
+
+ FOUR_TO_FOUR(&ccb->DataPointer,(PFOUR_BYTE)&physicalSdl);
+
+#endif
+
+
+ DebugPrint((3,"BuildSdl: SDL address is %lx\n", sdl));
+
+ DebugPrint((3,"BuildSdl: CCB address is %lx\n", ccb));
+
+ return;
+
+} // end BuildSdl()
+
+
+BOOLEAN
+D329XResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Reset Adaptec 154X SCSI adapter and SCSI bus.
+ Initialize adpater mailbox.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR status;
+ ULONG i;
+
+ DebugPrint((2,"ResetBus: Reset DTC329X and SCSI bus\n"));
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)PathId,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ //
+ // Reset SCSI chip.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
+
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(1);
+
+ status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ DebugPrint((2,"ResetBus: Wait done\n"));
+
+ if (!(status & IOP_SCSI_HBA_IDLE)) {
+
+ //
+ // The DTC sometimes needs a soft reset to recover.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->BaseIoAddress->StatusRegister, IOP_SOFT_RESET);
+ ScsiPortStallExecution(500 * 1000);
+
+ //
+ // Wait up to 5000 microseconds for adapter to initialize.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ ScsiPortStallExecution(5);
+
+ status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
+
+ if (status & IOP_SCSI_HBA_IDLE) {
+ break;
+ }
+
+ }
+
+ }
+
+ if (!(status & IOP_SCSI_HBA_IDLE)) {
+ return(FALSE);
+ }
+
+ DebugPrint((2,"ResetBus: Hardreset OK\n"));
+
+ //
+ // Zero out mailboxes.
+ //
+
+ for (i=0; i<MB_COUNT; i++) {
+
+ PMBO mailboxOut;
+ PMBI mailboxIn;
+
+ mailboxIn = &noncachedExtension->Mbi[i];
+ mailboxOut = &noncachedExtension->Mbo[i];
+
+ mailboxOut->Command = mailboxIn->Status = 0;
+ }
+
+ DebugPrint((3,"D329XResetBus: Initialize mailbox\n"));
+
+#ifndef DTC329X
+ if (!WriteCommandRegister(deviceExtension,AC_MAILBOX_INITIALIZATION)) {
+ DebugPrint((1,"D329XResetBus: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the middle byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+#else
+
+
+ if (!WriteCommandRegister(deviceExtension,DTC_MAILBOX_INITIALIZATION)) {
+ DebugPrint((1,"D329XResetBus: Couldn't initialize mailboxes\n"));
+ return FALSE;
+ }
+
+
+ for (i=0; i < 250000; i++)
+ ScsiPortStallExecution(1);
+
+ //
+ // Send Adapter number of mailbox locations.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,MB_COUNT)) {
+ return FALSE;
+ }
+
+ //
+ // Send the least significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
+ return FALSE;
+ }
+
+ //
+ // Send the 2nd byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
+ return FALSE;
+ }
+
+ //
+ // Send the 3rd byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
+ return FALSE;
+ }
+
+ //
+ // Send the most significant byte of the mailbox physical address.
+ //
+
+ if (!WriteCommandRegister(deviceExtension,
+ ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte3)) {
+ return FALSE;
+ }
+
+#endif
+
+
+
+ DebugPrint((3,"D329XResetBus: Initialize mailbox ok\n"));
+
+
+
+ return TRUE;
+
+} // end D329XResetBus()
+
+
+UCHAR
+MapError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PCCB Ccb
+ )
+
+/*++
+
+Routine Description:
+
+ Translate D329X error to SRB error, and log an error if necessary.
+
+Arguments:
+
+ HwDeviceExtension - The hardware device extension.
+
+ Srb - The failing Srb.
+
+ Ccb - Command Control Block contains error.
+
+Return Value:
+
+ SRB Error
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ UCHAR status;
+ ULONG logError;
+
+ switch (Ccb->HostStatus) {
+
+
+#ifdef DTC329X
+
+ case CCB_SELECTION_TIMEOUT:
+ return SRB_STATUS_SELECTION_TIMEOUT;
+
+ case CCB_COMPLETE:
+ if (Ccb->TargetStatus != SCSISTAT_GOOD) {
+ return SRB_STATUS_ERROR;
+ } else if (!deviceExtension->Dtc3290) {
+
+ //
+ // The DTC 3292 does not update the scsi bus status assume the
+ // scsi bus status is a check condition.
+ //
+
+ Ccb->TargetStatus = SCSISTAT_CHECK_CONDITION;
+ return SRB_STATUS_ERROR;
+ }
+
+ //
+ // Fall through to the under run case.
+ //
+
+#else
+ case CCB_COMPLETE:
+ case CCB_SELECTION_TIMEOUT:
+ return SRB_STATUS_ERROR;
+#endif
+
+ case CCB_DATA_OVER_UNDER_RUN:
+ return SRB_STATUS_DATA_OVERRUN;
+
+ case CCB_UNEXPECTED_BUS_FREE:
+ status = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ logError = SP_UNEXPECTED_DISCONNECT;
+ break;
+
+ case CCB_PHASE_SEQUENCE_FAIL:
+ case CCB_INVALID_DIRECTION:
+ status = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ logError = SP_PROTOCOL_ERROR;
+ break;
+
+ case CCB_BAD_MBO_COMMAND:
+ case CCB_INVALID_OP_CODE:
+ case CCB_BAD_LINKED_LUN:
+ case CCB_DUPLICATE_CCB:
+ case CCB_INVALID_CCB:
+ status = SRB_STATUS_INVALID_REQUEST;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+
+ default:
+ status = SRB_STATUS_ERROR;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+ }
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ (2 << 8) | Ccb->HostStatus
+ );
+
+ return(status);
+
+} // end MapError()
+
+
+BOOLEAN
+ReadCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR DataByte
+ )
+
+/*++
+
+Routine Description:
+
+ Read command register.
+
+Arguments:
+
+ DeviceExtesion - Pointer to adapder extension
+ DataByte - Byte read from register
+
+Return Value:
+
+ TRUE if command register read.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+
+
+ //
+ // Wait up to 500 microseconds for adapter to be ready.
+ //
+
+#ifndef DTC329X
+
+ for (i=0; i<500; i++) {
+
+#else
+
+ for (i=0; i<5000; i++) { /* 03-27-93 */
+
+#endif
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_DATA_IN_PORT_FULL) {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+
+ } else {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+#ifndef DTC329X
+ if (i==500) {
+#else
+ if (i==5000) { /* 03-27-93 */
+#endif
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 8
+ );
+
+ DebugPrint((1, "DTC329X:ReadCommandRegister: Read command timed out\n"));
+ return FALSE;
+ }
+
+ *DataByte = ScsiPortReadPortUchar(&baseIoAddress->CommandRegister);
+
+ return TRUE;
+
+} // end ReadCommandRegister()
+
+
+BOOLEAN
+WriteCommandRegister(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR AdapterCommand
+ )
+
+/*++
+
+Routine Description:
+
+ Write operation code to command register.
+
+Arguments:
+
+ DeviceExtesion - Pointer to adapter extension
+ AdapterCommand - Value to be written to register
+
+Return Value:
+
+ TRUE if command sent.
+ FALSE if timed out waiting for adapter.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+
+ //
+ // Wait up to 500 microseconds for adapter to be ready.
+ //
+
+#ifndef DTC329X
+
+ for (i=0; i<500; i++) {
+
+#else
+
+ for (i=0; i<5000; i++) { /* 03-27-93 */
+#endif
+
+ if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
+ IOP_COMMAND_DATA_OUT_FULL) {
+
+ //
+ // Stall 1 microsecond before
+ // trying again.
+ //
+
+ ScsiPortStallExecution(1);
+
+ } else {
+
+ //
+ // Adapter ready. Break out of loop.
+ //
+
+ break;
+ }
+ }
+
+#ifndef DTC329X
+ if (i==500) {
+#else
+ if (i==5000) { /* 03-27-93 */
+#endif
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4 << 8
+ );
+
+ DebugPrint((1, "DTC329X:WriteCommandRegister: Write command timed out\n"));
+ return FALSE;
+ }
+
+ DebugPrint((3,"AdapterCommand = %x \n", AdapterCommand));
+
+ ScsiPortWritePortUchar(&baseIoAddress->CommandRegister, AdapterCommand);
+
+ return TRUE;
+
+} // end WriteCommandRegister()
diff --git a/private/ntos/miniport/dtc/dtc329x.h b/private/ntos/miniport/dtc/dtc329x.h
new file mode 100644
index 000000000..f75fc4e1f
--- /dev/null
+++ b/private/ntos/miniport/dtc/dtc329x.h
@@ -0,0 +1,399 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ aha154x.h
+
+Abstract:
+
+ This module contains the structures, specific to the Adaptec aha154x
+ host bus adapter, used by the SCSI miniport driver. Data structures
+ that are part of standard ANSI SCSI will be defined in a header
+ file that will be available to all SCSI device drivers.
+
+Revision History:
+
+ 03-27-93 Bob For March Beta
+--*/
+
+#include "scsi.h"
+
+// Flag to turn on the codes for DTC3290 and DTC3292
+#define DTC329X 1
+
+
+//
+// The following definitions are used to convert ULONG addresses
+// to Adaptec's 3 byte address format.
+//
+
+
+
+
+typedef struct _THREE_BYTE {
+ UCHAR Msb;
+ UCHAR Mid;
+ UCHAR Lsb;
+} THREE_BYTE, *PTHREE_BYTE;
+
+
+
+//
+// Convert four-byte Little Endian to three-byte Big Endian
+//
+
+#define FOUR_TO_THREE(Three, Four) { \
+ ASSERT(!((Four)->Byte3)); \
+ (Three)->Lsb = (Four)->Byte0; \
+ (Three)->Mid = (Four)->Byte1; \
+ (Three)->Msb = (Four)->Byte2; \
+}
+
+#define THREE_TO_FOUR(Four, Three) { \
+ (Four)->Byte0 = (Three)->Lsb; \
+ (Four)->Byte1 = (Three)->Mid; \
+ (Four)->Byte2 = (Three)->Msb; \
+ (Four)->Byte3 = 0; \
+}
+
+#ifdef DTC329X
+#define FOUR_TO_FOUR(FourTo, FourFrom) { \
+ (FourTo)->Byte0 = (FourFrom)->Byte0; \
+ (FourTo)->Byte1 = (FourFrom)->Byte1; \
+ (FourTo)->Byte2 = (FourFrom)->Byte2; \
+ (FourTo)->Byte3 = (FourFrom)->Byte3; \
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CCB - Adaptec SCSI Command Control Block
+//
+// The CCB is a superset of the CDB (Command Descriptor Block)
+// and specifies detailed information about a SCSI command.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Byte 0 Command Control Block Operation Code
+//
+
+#define SCSI_INITIATOR_COMMAND 0x00
+#define TARGET_MODE_COMMAND 0x01
+#define SCATTER_GATHER_COMMAND 0x02
+
+//
+// Byte 1 Address and Direction Control
+//
+
+#define CCB_TARGET_ID_SHIFT 0x06 // CCB Op Code = 00, 02
+#define CCB_INITIATOR_ID_SHIFT 0x06 // CCB Op Code = 01
+#define CCB_DATA_XFER_OUT 0x10 // Write
+#define CCB_DATA_XFER_IN 0x08 // Read
+#define CCB_LUN_MASK 0x07 // Logical Unit Number
+
+//
+// Byte 2 SCSI_Command_Length - Length of SCSI CDB
+//
+// Byte 3 Request Sense Allocation Length
+//
+
+#define FOURTEEN_BYTES 0x00 // Request Sense Buffer size
+#define NO_AUTO_REQUEST_SENSE 0x01 // No Request Sense Buffer
+
+//
+// Bytes 4, 5 and 6 Data Length // Data transfer byte count
+//
+// Bytes 7, 8 and 9 Data Pointer // SGD List or Data Buffer
+//
+// Bytes 10, 11 and 12 Link Pointer // Next CCB in Linked List
+//
+// Byte 13 Command Link ID // TBD (I don't know yet)
+//
+// Byte 14 Host Status // Host Adapter status
+//
+
+#define CCB_COMPLETE 0x00 // CCB completed without error
+#define CCB_LINKED_COMPLETE 0x0A // Linked command completed
+#define CCB_LINKED_COMPLETE_INT 0x0B // Linked complete with interrupt
+#define CCB_SELECTION_TIMEOUT 0x11 // Set SCSI selection timed out
+#define CCB_DATA_OVER_UNDER_RUN 0x12
+#define CCB_UNEXPECTED_BUS_FREE 0x13 // Target dropped SCSI BSY
+#define CCB_PHASE_SEQUENCE_FAIL 0x14 // Target bus phase sequence failure
+#define CCB_BAD_MBO_COMMAND 0x15 // MBO command not 0, 1 or 2
+#define CCB_INVALID_OP_CODE 0x16 // CCB invalid operation code
+#define CCB_BAD_LINKED_LUN 0x17 // Linked CCB LUN different from first
+#define CCB_INVALID_DIRECTION 0x18 // Invalid target direction
+#define CCB_DUPLICATE_CCB 0x19 // Duplicate CCB
+#define CCB_INVALID_CCB 0x1A // Invalid CCB - bad parameter
+
+//
+// Byte 15 Target Status
+//
+// See SCSI.H files for these statuses.
+//
+
+//
+// Bytes 16 and 17 Reserved (must be 0)
+//
+
+//
+// Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block
+//
+
+//
+// Bytes 18+n through 18+m-1, where m=buffer size Allocated for Sense Data
+//
+
+#define REQUEST_SENSE_BUFFER_SIZE 18
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Scatter/Gather Segment List Definitions
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Adapter limits
+//
+
+#define MAX_SG_DESCRIPTORS 17
+
+#define MAX_TRANSFER_SIZE 64 * 1024
+
+//
+// Scatter/Gather Segment Descriptor Definition
+//
+
+typedef struct _SGD {
+
+#ifndef DTC329X
+ THREE_BYTE Length;
+ THREE_BYTE Address;
+#else
+ FOUR_BYTE Length;
+ FOUR_BYTE Address;
+#endif
+} SGD, *PSGD;
+
+typedef struct _SDL {
+ SGD Sgd[MAX_SG_DESCRIPTORS];
+} SDL, *PSDL;
+
+#define SEGMENT_LIST_SIZE MAX_SG_DESCRIPTORS * sizeof(SGD)
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CCB Typedef
+//
+
+typedef struct _CCB {
+ UCHAR OperationCode;
+ UCHAR ControlByte;
+ UCHAR CdbLength;
+ UCHAR RequestSenseLength;
+#ifndef DTC329X
+ THREE_BYTE DataLength;
+ THREE_BYTE DataPointer;
+ THREE_BYTE LinkPointer;
+#else
+ FOUR_BYTE DataLength;
+ FOUR_BYTE DataPointer;
+ FOUR_BYTE LinkPointer;
+#endif
+ UCHAR LinkIdentifier;
+ UCHAR HostStatus;
+ UCHAR TargetStatus;
+ UCHAR Reserved[2];
+#ifndef DTC329X
+ UCHAR Cdb[10];
+#else
+ UCHAR Cdb[12];
+#endif
+ PVOID SrbAddress;
+ PVOID AbortSrb;
+ SDL Sdl;
+ UCHAR RequestSenseBuffer[REQUEST_SENSE_BUFFER_SIZE];
+} CCB, *PCCB;
+
+//
+// CCB and request sense buffer
+//
+
+#define CCB_SIZE sizeof(CCB)
+
+#define REZERO_UNIT_CMD 01 // 04-09-93, SCSI command to flush 3290 cache
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Adapter Command Overview
+//
+// Adapter commands are issued by writing to the Command/Data Out port.
+// They are used to initialize the host adapter and to establish control
+// conditions within the host adapter. They may not be issued when there
+// are outstanding SCSI commands.
+//
+// All adapter commands except Start SCSI(02) and Enable Mailbox-Out
+// Interrupt(05) must be executed only when the IDLE bit (Status bit 4)
+// is one. Many commands require additional parameter bytes which are
+// then written to the Command/Data Out I/O port (base+1). Before each
+// byte is written by the host to the host adapter, the host must verify
+// that the CDF bit (Status bit 3) is zero, indicating that the command
+// port is ready for another byte of information. The host adapter usually
+// clears the Command/Data Out port within 100 microseconds. Some commands
+// require information bytes to be returned from the host adapter to the
+// host. In this case, the host monitors the DF bit (Status bit 2) to
+// determine when the host adapter has placed a byte in the Data In I/O
+// port for the host to read. The DF bit is reset automatically when the
+// host reads the byte. The format of each adapter command is strictly
+// defined, so the host adapter and host system can always agree upon the
+// correct number of parameter bytes to be transferred during a command.
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Host Adapter Command Operation Codes
+//
+
+#define AC_NO_OPERATION 0x00
+#define AC_MAILBOX_INITIALIZATION 0x01
+#define AC_START_SCSI_COMMAND 0x02
+#define AC_START_BIOS_COMMAND 0x03
+#define AC_ADAPTER_INQUIRY 0x04
+#define AC_ENABLE_MBO_AVAIL_INT 0x05
+#define AC_SET_SELECTION_TIMEOUT 0x06
+#define AC_SET_BUS_ON_TIME 0x07
+#define AC_SET_BUS_OFF_TIME 0x08
+#define AC_SET_TRANSFER_SPEED 0x09
+#define AC_RET_INSTALLED_DEVICES 0x0A
+#define AC_RET_CONFIGURATION_DATA 0x0B
+#define AC_ENABLE_TARGET_MODE 0x0C
+#define AC_RETURN_SETUP_DATA 0x0D
+#define AC_WRITE_CHANNEL_2_BUFFER 0x1A
+#define AC_READ_CHANNEL_2_BUFFER 0x1B
+#define AC_WRITE_FIFO_BUFFER 0x1C
+#define AC_READ_FIFO_BUFFER 0x1D
+#define AC_ECHO_COMMAND_DATA 0x1F
+
+//
+// DMA Transfer Speeds
+//
+
+#define DMA_SPEED_50_MBS 0x00
+
+//
+// I/O Port Interface
+//
+
+typedef struct _BASE_REGISTER {
+ UCHAR StatusRegister;
+ UCHAR CommandRegister;
+ UCHAR InterruptRegister;
+} BASE_REGISTER, *PBASE_REGISTER;
+
+//
+// Base+0 Write: Control Register
+//
+
+#define IOP_HARD_RESET 0x80 // bit 7
+#define IOP_SOFT_RESET 0x40 // bit 6
+#define IOP_INTERRUPT_RESET 0x20 // bit 5
+#define IOP_SCSI_BUS_RESET 0x10 // bit 4
+
+//
+// Base+0 Read: Status
+//
+
+#define IOP_SELF_TEST 0x80 // bit 7
+#define IOP_INTERNAL_DIAG_FAILURE 0x40 // bit 6
+#define IOP_MAILBOX_INIT_REQUIRED 0x20 // bit 5
+#define IOP_SCSI_HBA_IDLE 0x10 // bit 4
+#define IOP_COMMAND_DATA_OUT_FULL 0x08 // bit 3
+#define IOP_DATA_IN_PORT_FULL 0x04 // bit 2
+#define IOP_INVALID_COMMAND 0X01 // bit 1
+
+//
+// Base+1 Write: Command/Data Out
+//
+
+//
+// Base+1 Read: Data In
+//
+
+//
+// Base+2 Read: Interrupt Flags
+//
+
+#define IOP_ANY_INTERRUPT 0x80 // bit 7
+#define IOP_SCSI_RESET_DETECTED 0x08 // bit 3
+#define IOP_COMMAND_COMPLETE 0x04 // bit 2
+#define IOP_MBO_EMPTY 0x02 // bit 1
+#define IOP_MBI_FULL 0x01 // bit 0
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Mailbox Definitions
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// Mailbox Definition
+//
+
+#define MB_COUNT 0x04 // number of mailboxes
+
+
+
+typedef struct _MBO {
+ UCHAR Command;
+#ifndef DTC329X
+ THREE_BYTE Address;
+#else
+ FOUR_BYTE Address;
+#endif
+} MBO, *PMBO;
+
+//
+// MBO Command Values
+//
+
+#define MBO_FREE 0x00
+#define MBO_START 0x01
+#define MBO_ABORT 0x02
+
+//
+// Mailbox In
+//
+
+typedef struct _MBI {
+ UCHAR Status;
+#ifndef DTC329X
+ THREE_BYTE Address;
+#else
+ FOUR_BYTE Address;
+#endif
+} MBI, *PMBI;
+
+//
+// MBI Status Values
+//
+
+#define MBI_FREE 0x00
+#define MBI_SUCCESS 0x01
+#define MBI_ABORT 0x02
+#define MBI_NOT_FOUND 0x03
+#define MBI_ERROR 0x04
+
+//
+// Mailbox Initialization
+//
+
+typedef struct _MAILBOX_INIT {
+ UCHAR Count;
+ THREE_BYTE Address;
+} MAILBOX_INIT, *PMAILBOX_INIT;
+
diff --git a/private/ntos/miniport/dtc/dtc329x.rc b/private/ntos/miniport/dtc/dtc329x.rc
new file mode 100644
index 000000000..eeb25f16f
--- /dev/null
+++ b/private/ntos/miniport/dtc/dtc329x.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "DTC 329x SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "dtc329x.sys"
+#define VER_ORIGINALFILENAME_STR "dtc329x.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/dtc/makefile b/private/ntos/miniport/dtc/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/miniport/dtc/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/dtc/sources b/private/ntos/miniport/dtc/sources
new file mode 100644
index 000000000..f4dfe44af
--- /dev/null
+++ b/private/ntos/miniport/dtc/sources
@@ -0,0 +1,9 @@
+TARGETNAME=dtc329x
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=dtc329x.c dtc329x.rc
diff --git a/private/ntos/miniport/mitsumi/makefile b/private/ntos/miniport/mitsumi/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/mitsumi/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/mitsumi/mitsumi.c b/private/ntos/miniport/mitsumi/mitsumi.c
new file mode 100644
index 000000000..3429a15b4
--- /dev/null
+++ b/private/ntos/miniport/mitsumi/mitsumi.c
@@ -0,0 +1,3365 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ Mitsumi.c
+
+Abstract:
+
+ This is the miniport driver for the Panasonic MKE CR5xx Proprietary CDROM drive.
+
+Author:
+
+ Chuck Park (chuckp)
+
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "Mitsumi.h"
+
+#if DBG
+#define GATHER_STATS 1
+#endif
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ //
+ // I/O port base address.
+ //
+
+ PREGISTERS BaseIoAddress;
+
+ //
+ // Srb being currently serviced.
+ //
+
+ PSCSI_REQUEST_BLOCK CurrentSrb;
+
+ //
+ // Pointer to data buffer
+ //
+
+ PUCHAR DataBuffer;
+
+ //
+ // Bytes left to transfer for current request.
+ //
+
+ ULONG ByteCount;
+
+ //
+ // Identifies the model.
+ //
+
+ DRIVE_TYPE DriveType;
+
+ //
+ // Current status of audio
+ //
+
+ ULONG AudioStatus;
+
+ //
+ // Saved position after pausing play.
+ //
+
+ ULONG SavedPosition;
+
+ //
+ // Ending LBA from last audio play.
+ //
+
+ ULONG EndPosition;
+
+ //
+ // Number of retries to get valid status.
+ //
+
+ ULONG StatusRetries;
+
+ //
+ // Number of microseconds to go away on CallBack requests
+ //
+
+ ULONG PollRate;
+ ULONG PollRateMultiplier;
+
+#ifdef GATHER_STATS
+
+ //
+ // Used to determine hit rate for various polling increments
+ //
+
+ ULONG Hits[4];
+ ULONG Misses[4];
+ ULONG Requests;
+ BOOLEAN FirstCall;
+ BOOLEAN FirstStatusTry;
+#endif
+
+ //
+ // Status from last NoOp
+ //
+
+ UCHAR DriveStatus;
+
+ //
+ // Determines whether MSF addressing is used.
+ //
+
+ BOOLEAN MSFAddress;
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+#define MAX_STATUS_RETRIES 512
+
+
+//
+// Function declarations
+//
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+
+ULONG
+MitsumiFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+MitsumiHwInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+MitsumiStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+MitsumiCallBack(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+MitsumiReset(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+BOOLEAN
+FindMitsumi(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension
+ );
+
+BOOLEAN
+ReadAndMapError(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+CheckStatus(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+MitsumiBuildCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+MitsumiSendCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+UCHAR
+WaitForSTEN(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+UpdateCurrentPosition(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ ULONG adapterCount;
+
+ DebugPrint((1,"\n\nMitsumi Proprietary CDROM Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i = 0; i < sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = MitsumiHwInitialize;
+ hwInitializationData.HwResetBus = MitsumiReset;
+ hwInitializationData.HwStartIo = MitsumiStartIo;
+ hwInitializationData.HwFindAdapter = MitsumiFindAdapter;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SrbExtensionSize = sizeof(CMD_PACKET);
+
+ //
+ // Specifiy the bus type and access ranges.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Isa;
+ hwInitializationData.NumberOfAccessRanges = 1;
+
+ //
+ // Indicate PIO device.
+ //
+
+ hwInitializationData.MapBuffers = TRUE;
+
+ adapterCount = 0;
+
+ return (ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount));
+
+} // end MitsumiEntry()
+
+
+ULONG
+MitsumiFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - Register base address
+ ConfigInfo - Configuration information structure describing HBA
+ This structure is defined in PORT.H.
+
+Return Value:
+
+ ULONG
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PULONG AdapterCount = Context;
+
+ CONST ULONG AdapterAddresses[] = {0x230, 0x250,0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360, 0x370, 0x380,
+ 0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0, 0};
+
+
+ while (AdapterAddresses[*AdapterCount] != 0) {
+
+ //
+ // Map I/O space.
+ //
+
+ deviceExtension->BaseIoAddress = (PREGISTERS)ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(
+ AdapterAddresses[*AdapterCount]),
+ 0x4,
+ TRUE
+ );
+ if (!deviceExtension->BaseIoAddress) {
+ return SP_RETURN_ERROR;
+ }
+
+ (*AdapterCount)++;
+
+ if (!FindMitsumi(deviceExtension)) {
+
+ //
+ // CD is not at this address.
+ //
+
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ deviceExtension->BaseIoAddress
+ );
+
+ continue;
+
+ } else {
+
+ //
+ // Indicate further searches are to be attempted.
+ // Why anyone would want more than one of these drives...
+ //
+
+ *Again = TRUE;
+
+ //
+ // Fill in the access ranges.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*AdapterCount - 1]);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = 4;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InitiatorBusId[0] = 1;
+
+ ConfigInfo->MaximumTransferLength = 0x8000;
+
+ deviceExtension->AudioStatus = AUDIO_STATUS_NO_STATUS;
+ return SP_RETURN_FOUND;
+
+ }
+
+ }
+
+ *Again = FALSE;
+ *AdapterCount = 0;
+
+ return SP_RETURN_NOT_FOUND;
+
+} // end MitsumiFindAdapter()
+
+
+BOOLEAN
+FindMitsumi(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if device found.
+
+--*/
+
+{
+
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PREGISTERS baseIoAddress = deviceExtension->BaseIoAddress;
+ ULONG i;
+ UCHAR status;
+ UCHAR driveId[2];
+
+ //
+ // If status is not 0xFF, something else is living at this location.
+ //
+
+ status = ScsiPortReadPortUchar(&baseIoAddress->Reset);
+ if (status != 0xFF) {
+ DebugPrint((1,
+ "FindMitsumi: Something else is living at %x\n",
+ baseIoAddress));
+
+ return FALSE;
+ }
+ status = ScsiPortReadPortUchar(&baseIoAddress->Data);
+ if (status != 0xFF) {
+ DebugPrint((1,
+ "FindMitsumi: Something else is living at %x\n",
+ baseIoAddress));
+
+ return FALSE;
+ }
+
+ //
+ // Reset the device.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Reset,0);
+ ScsiPortStallExecution(10);
+ ScsiPortWritePortUchar(&baseIoAddress->Status, 0);
+ ScsiPortStallExecution (10);
+
+ ScsiPortStallExecution(10000);
+ ReadStatus(deviceExtension,baseIoAddress,status);
+
+ //
+ // Issue read drive Id command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data,OP_READ_DRIVE_ID);
+
+ ReadStatus(deviceExtension,baseIoAddress,status);
+
+ if (!(status & STATUS_CMD_ERROR)) {
+
+ //
+ // Read the drive id and version #.
+ //
+
+ for (i = 0; i < 2; i++) {
+ ReadStatus(deviceExtension,baseIoAddress,driveId[i]);
+ if (driveId[i] == 0xFF) {
+ return FALSE;
+ }
+ }
+
+ //
+ // Check the id for validity and drive type.
+ //
+
+ switch (driveId[0]) {
+ case 'M':
+
+ DebugPrint((1,
+ "FindMitsumi: Found LU005 at %x\n",
+ baseIoAddress));
+
+ deviceExtension->DriveType = LU005;
+ break;
+
+ case 'D':
+
+ DebugPrint((1,
+ "FindMitsumi: Found FX001D at %x\n",
+ baseIoAddress));
+
+ deviceExtension->DriveType = FX001D;
+ break;
+
+ case 'F':
+
+ DebugPrint((1,
+ "FindMitsumi: Found FX001 at %x\n",
+ baseIoAddress));
+
+ deviceExtension->DriveType = FX001;
+ break;
+
+ default:
+ DebugPrint((1,
+ "FindMitsumi: No drive found at %x\n",
+ baseIoAddress));
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ DebugPrint((1,
+ "FindMitsumi: No drive found at %x\n",
+ baseIoAddress));
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+} // end FindMitsumi
+
+
+BOOLEAN
+MitsumiHwInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from ScsiPortInitialize
+ to set up the adapter so that it is ready to service requests.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ deviceExtension->PollRate = 1500;
+ deviceExtension->PollRateMultiplier = 15;
+ return TRUE;
+
+} // end MitsumiHwInitialize()
+
+
+BOOLEAN
+MitsumiStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PREGISTERS baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR status;
+
+ //
+ // Determine which function.
+ //
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Indicate that a request is active on the controller.
+ //
+
+ deviceExtension->CurrentSrb = Srb;
+
+ //
+ // Build the command packet.
+ //
+
+ if (!MitsumiBuildCommand(deviceExtension,Srb)) {
+ status = Srb->SrbStatus;
+ break;
+ }
+
+ //
+ // Send command to device.
+ //
+
+ if (MitsumiSendCommand(deviceExtension,Srb)) {
+
+ if ( Srb->SrbStatus == SRB_STATUS_PENDING) {
+
+ //
+ // Request a timer callback to finish request.
+ //
+
+ ScsiPortNotification(RequestTimerCall,
+ HwDeviceExtension,
+ MitsumiCallBack,
+ deviceExtension->PollRate * deviceExtension->PollRateMultiplier);
+ return TRUE;
+ }
+ }
+
+ status = Srb->SrbStatus;
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ if (!deviceExtension->CurrentSrb) {
+
+ //
+ // Complete abort SRB.
+ //
+
+ status = SRB_STATUS_ABORT_FAILED;
+
+ break;
+ }
+
+ //
+ // Fall through to reset
+ //
+
+ case SRB_FUNCTION_RESET_BUS:
+
+
+ //
+ // Reset the device.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Reset,0);
+ ScsiPortStallExecution(10);
+ ScsiPortWritePortUchar(&baseIoAddress->Status, 0);
+ ScsiPortStallExecution (10);
+
+ //
+ // Update drive status in device ext.
+ //
+
+ ReadStatus(deviceExtension,baseIoAddress,status);
+
+ //
+ // Port driver will give 5 sec. to recover.
+ //
+
+ status = SRB_STATUS_BUS_RESET;
+
+ break;
+
+ default:
+
+ //
+ // Indicate unsupported command.
+ //
+
+ status = SRB_STATUS_INVALID_REQUEST;
+
+ break;
+
+ } // end switch
+
+
+ if (status != SRB_STATUS_PENDING) {
+
+ //
+ // Clear current SRB.
+ //
+
+ deviceExtension->CurrentSrb = NULL;
+
+ //
+ // Map status to Srb status
+ //
+
+ Srb->SrbStatus = (UCHAR)status;
+
+ //
+ // Indicate command complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ //
+ // Indicate ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ return TRUE;
+
+} // end MitsumiStartIo()
+
+
+BOOLEAN
+MitsumiReadCapacity(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Extracts the 'TOC' data and manipulates it to determine
+ the size of the disc.
+
+Arguments:
+
+ DeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if command was successful.
+
+--*/
+
+{
+
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
+ PUCHAR data = DeviceExtension->DataBuffer;
+ ULONG dataLength,lba,i;
+ UCHAR minutes,seconds,frames;
+ UCHAR status;
+
+
+ dataLength = 8;
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ if (!(status & STATUS_DISC_IN) || (status & STATUS_DOOR_OPEN) ) {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ if (Srb->SenseInfoBufferLength) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ return FALSE;
+ }
+
+ if (!(status & STATUS_CMD_ERROR)) {
+
+ //
+ // Read the Toc data
+ //
+
+ for (i = 0; i < dataLength; i++) {
+ ReadStatus(DeviceExtension,baseIoAddress,*data);
+ if (*data == 0xFF) {
+
+ //
+ // Timeout occurred.
+ //
+
+ DebugPrint((1,
+ "MitsumiReadCapacity: Error occurred on data read.\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+ data++;
+ }
+
+ //
+ // All of the Toc data has been read. Now munge it into a form that is useable.
+ //
+
+ DeviceExtension->ByteCount = 0;
+
+ data = &DeviceExtension->DataBuffer[2];
+ minutes = *data++;
+ seconds = *data++;
+ frames = *data;
+
+ BCD_TO_DEC(minutes);
+ BCD_TO_DEC(seconds);
+ BCD_TO_DEC(frames);
+
+ lba = MSF_TO_LBA(minutes,seconds,frames);
+
+ DeviceExtension->DataBuffer[0] = ((PFOUR_BYTE)&lba)->Byte3;
+ DeviceExtension->DataBuffer[1] = ((PFOUR_BYTE)&lba)->Byte2;
+ DeviceExtension->DataBuffer[2] = ((PFOUR_BYTE)&lba)->Byte1;
+ DeviceExtension->DataBuffer[3] = ((PFOUR_BYTE)&lba)->Byte0;
+
+
+ *((ULONG *) &(DeviceExtension->DataBuffer[4])) = 0x00080000;
+
+ } else {
+
+ DebugPrint((1,
+ "MitsumiReadCapacity: Status %x\n",
+ status));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+
+ return TRUE;
+
+} //End MitsumiReadCapacity
+
+
+
+BOOLEAN
+MitsumiRead(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Carries out the read command. Each sector will be transferred to the
+ Srb's data buffer individually. Afterwards, a new timer call-back will
+ be requested.
+
+Arguments:
+
+ DeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if data transfer is complete.
+
+--*/
+
+{
+
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG dataLength = DeviceExtension->ByteCount;
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
+ PCMD_PACKET packet = (PCMD_PACKET)Srb->SrbExtension;
+ ULONG i,j;
+ UCHAR status;
+
+
+ while (DeviceExtension->ByteCount) {
+
+ //
+ // Check whether ready to transfer.
+ //
+
+ for (i = 0; i < 400; i++) {
+ status = ScsiPortReadPortUchar(&baseIoAddress->Status);
+ if (!(status & DTEN)) {
+
+ break;
+
+ } else if (!(status & STEN)){
+
+ ScsiPortWritePortUchar(&baseIoAddress->Control, 0x04);
+ status = ScsiPortReadPortUchar(&baseIoAddress->Data);
+ DeviceExtension->DriveStatus = status;
+ ScsiPortWritePortUchar(&baseIoAddress->Control, 0x0C);
+
+ if (status & STATUS_READ_ERROR) {
+
+ DebugPrint((1,
+ "MitsumiRead: Read error %x\n",
+ status));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+
+ }
+ }
+ ScsiPortStallExecution(10);
+ }
+
+ if (i == 400) {
+
+
+#ifdef GATHER_STATS
+ if (DeviceExtension->ByteCount == Srb->DataTransferLength) {
+ DeviceExtension->FirstCall = FALSE;
+ DeviceExtension->Misses[0]++;
+ } else {
+ DeviceExtension->Misses[1]++;
+ }
+#endif
+ if (DeviceExtension->StatusRetries >= MAX_STATUS_RETRIES) {
+
+ DebugPrint((1,
+ "MitsumiRead: Resetting due to timeout waiting for DTEN\n"));
+
+ DeviceExtension->StatusRetries = 0;
+
+ //
+ // Clear state fields.
+ //
+
+ DeviceExtension->CurrentSrb = NULL;
+ DeviceExtension->ByteCount = 0;
+ DeviceExtension->DataBuffer = NULL;
+
+ //
+ // Reset the device.
+ //
+
+ MitsumiReset((PVOID)DeviceExtension, Srb->PathId);
+
+ ScsiPortNotification(ResetDetected,
+ DeviceExtension,
+ NULL);
+
+ Srb->SrbStatus = SRB_STATUS_BUS_RESET;
+
+ return FALSE;
+
+ } else {
+
+ DeviceExtension->StatusRetries++;
+
+ //
+ // Schedule another callback.
+ //
+
+ DebugPrint((2,
+ "MitsumiRead: DTEN timed out waiting for seek. Scheduling another callback %x\n",
+ status));
+
+ ScsiPortNotification(RequestTimerCall,
+ (PVOID)DeviceExtension,
+ MitsumiCallBack,
+ DeviceExtension->PollRate);
+
+ return FALSE;
+ }
+ }
+#ifdef GATHER_STATS
+ else {
+ if (DeviceExtension->ByteCount == Srb->DataTransferLength) {
+ if (DeviceExtension->FirstCall) {
+ DeviceExtension->Hits[0]++;
+ DeviceExtension->FirstCall = FALSE;
+ }
+ } else {
+ DeviceExtension->Hits[1]++;
+ }
+ }
+#endif
+
+ //
+ // Some unknown check that seems to be essential.
+ //
+
+ if (DeviceExtension->DriveType != LU005) {
+
+ //
+ // TODO: Fix this loop. Don't want to spin forever.
+ //
+
+ while (TRUE) {
+ status = ScsiPortReadPortUchar(&baseIoAddress->Status);
+ if (status & 0x01) {
+ break;
+ } else {
+ ScsiPortStallExecution(20);
+ }
+ }
+ }
+
+ //
+ // Ready to transfer. Set the drive in 'data' mode.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Control, 0x04);
+
+ ScsiPortReadPortBufferUchar(&baseIoAddress->Data,
+ DeviceExtension->DataBuffer,
+ 2048);
+
+
+ //
+ // Set the drive back to 'status' mode.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Control, 0x0C);
+
+ //
+ // Adjust Bytes left and Buffer pointer
+ //
+
+ DeviceExtension->DataBuffer += 2048;
+ DeviceExtension->ByteCount -= 2048;
+ DeviceExtension->StatusRetries = 0;
+
+ if (DeviceExtension->ByteCount) {
+
+ //
+ // If ready to transfer another sector quick enough, go and
+ // do so.
+ //
+
+ for (j = 0; j < 20; j++) {
+ status = ScsiPortReadPortUchar(&baseIoAddress->Status);
+ if ((status & DTEN)) {
+ if (!(status & STEN)) {
+ ScsiPortWritePortUchar(&baseIoAddress->Control, 0x04);
+ status = ScsiPortReadPortUchar(&baseIoAddress->Data);
+ DeviceExtension->DriveStatus = status;
+ ScsiPortWritePortUchar(&baseIoAddress->Control, 0x0C);
+
+ if (status & STATUS_READ_ERROR) {
+
+ DebugPrint((1,
+ "MitsumiRead: Read error %x\n",
+ status));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+
+ }
+ }
+ } else {
+ break;
+ }
+
+ ScsiPortStallExecution(100);
+ }
+ if (j == 20) {
+
+#ifdef GATHER_STATS
+ DeviceExtension->Misses[2]++;
+#endif
+ DebugPrint((2,
+ "MitsumiRead: Request another timer\n"));
+
+ ScsiPortNotification(RequestTimerCall,
+ (PVOID)DeviceExtension,
+ MitsumiCallBack,
+ DeviceExtension->PollRate);
+
+ return FALSE;
+ }
+#ifdef GATHER_STATS
+ else {
+ DeviceExtension->Hits[2]++;
+ }
+#endif
+ //
+ // Update dataLength and try for another sector.
+ //
+
+ dataLength = DeviceExtension->ByteCount / 2048;
+
+ } else {
+
+ //
+ // Prepare to try for status.
+ //
+
+ DeviceExtension->StatusRetries = 0;
+#ifdef GATHER_STATS
+ DeviceExtension->FirstStatusTry = TRUE;
+#endif
+
+ ScsiPortNotification(RequestTimerCall,
+ (PVOID)DeviceExtension,
+ MitsumiCallBack,
+ DeviceExtension->PollRate / 2);
+ return FALSE;
+ }
+ }
+
+ //
+ // Read final status.
+ //
+
+ for (i = 0; i < 200; i++) {
+ status = ScsiPortReadPortUchar(&baseIoAddress->Status);
+ if (status & STEN) {
+ ScsiPortStallExecution(10);
+ } else {
+ break;
+ }
+ }
+
+ if (i == 200) {
+
+#ifdef GATHER_STATS
+ DeviceExtension->FirstStatusTry = FALSE;
+ DeviceExtension->Misses[3]++;
+#endif
+ if (DeviceExtension->StatusRetries >= MAX_STATUS_RETRIES) {
+
+ DebugPrint((1,
+ "MitsumiRead: Resetting due to timeout waiting for status\n"));
+
+ DeviceExtension->StatusRetries = 0;
+
+ //
+ // Clear state fields.
+ //
+
+ DeviceExtension->CurrentSrb = NULL;
+ DeviceExtension->ByteCount = 0;
+ DeviceExtension->DataBuffer = NULL;
+
+ //
+ // Reset the device.
+ //
+
+ MitsumiReset((PVOID)DeviceExtension, Srb->PathId);
+
+ ScsiPortNotification(ResetDetected,
+ DeviceExtension,
+ NULL);
+
+ Srb->SrbStatus = SRB_STATUS_BUS_RESET;
+
+ return FALSE;
+ } else {
+
+ DebugPrint((2,
+ "MitsumiRead: Status Retries for Status %x\n",
+ DeviceExtension->StatusRetries));
+
+ DeviceExtension->StatusRetries++;
+
+ //
+ // Request another callback to pick up the status
+ //
+
+ ScsiPortNotification(RequestTimerCall,
+ (PVOID)DeviceExtension,
+ MitsumiCallBack,
+ DeviceExtension->PollRate);
+ return FALSE;
+ }
+ }
+
+
+#ifdef GATHER_STATS
+ if (DeviceExtension->StatusRetries == 0) {
+ if (DeviceExtension->FirstStatusTry) {
+ DeviceExtension->Hits[3]++;
+ } else {
+ DebugPrint((1,"StatusRetries = 0, FirstStatusTry = FALSE\n"));
+ }
+ }
+#endif
+ ScsiPortWritePortUchar(&baseIoAddress->Control, 0x04);
+ status = ScsiPortReadPortUchar(&baseIoAddress->Data);
+ DeviceExtension->DriveStatus = status;
+ ScsiPortWritePortUchar(&baseIoAddress->Control, 0x0C);
+
+ if (status & STATUS_READ_ERROR) {
+
+ DebugPrint((1,
+ "MitsumiRead: Read error %x\n",
+ status));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+
+ }
+
+ return TRUE;
+
+} //End MitsumiRead
+
+
+
+BOOLEAN
+GetTrackData(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG NumberTracks
+ )
+
+/*++
+
+Routine Description:
+
+ Puts the drive in 'TOC' mode so the TOC info. can be extracted for the
+ Subchannel Q.
+
+Arguments:
+
+ DeviceExtension - HBA miniport driver's adapter data storage
+ NumberTracks - The number of tracks determined to be on the disc.
+
+Return Value:
+
+ TRUE - if successful.
+
+--*/
+
+{
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
+ PCMD_PACKET packet = (PCMD_PACKET)Srb->SrbExtension;
+ PUCHAR data = DeviceExtension->DataBuffer;
+ UCHAR mask[100];
+ ULONG tracksFound = 0;
+ ULONG i,lba;
+ ULONG dataLength;
+ UCHAR status,minutes,seconds,frames,control,track,index;
+ UCHAR controlLow, controlHigh;
+ UCHAR dataBuffer[10];
+ ULONG zeroCount = 0,retry = 20000;
+
+ for (i = 0; i < 100; i++) {
+ mask[i] = 0;
+ }
+
+ //
+ // Seek to start of disk
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_READ_PLAY);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 2);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0);
+
+ //
+ // Wait for seek to complete
+ //
+
+ for (i = 0; i < 40000; i++) {
+ status = ScsiPortReadPortUchar(&baseIoAddress->Status);
+ if (!(status & STEN)) {
+ break;
+ } else if (!(status & DTEN)){
+
+ DebugPrint((1,
+ "GetTrackData: DTEN active %x\n",
+ status));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+
+ } else {
+
+ ScsiPortStallExecution(10);
+ }
+ }
+ if (i == 40000) {
+
+ DebugPrint((1,
+ "GetTrackData: STEN timed out %x\n",
+ status));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ if (status & (STATUS_CMD_ERROR | STATUS_READ_ERROR)) {
+
+ DebugPrint((1,
+ "GetTrackData: Status %x\n",
+ status));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+
+ //
+ // Switch drive into "TOC DATA"
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0x5);
+ ScsiPortStallExecution(1500);
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ DebugPrint((2,
+ "GetTrackData: Status after SET_DRV_MODE %x\n",
+ status));
+
+ //
+ // Set buffer pointer to start of track descriptors.
+ //
+
+ dataLength = 10;
+
+ while (tracksFound < NumberTracks) {
+
+ //
+ // Read sub-q to extract the embedded TOC data. This isn't pretty.
+ // So for the faint at heart - goto line 1245.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_READ_SUB_CHANNEL);
+ ScsiPortStallExecution(500);
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ if (!(status & STATUS_CMD_ERROR)) {
+
+ //
+ // Read the Toc data
+ //
+
+ for (i = 0; i < dataLength; i++) {
+ ReadStatus(DeviceExtension,baseIoAddress,dataBuffer[i]);
+ if (dataBuffer[i] == 0xFF) {
+
+ //
+ // Timeout occurred.
+ //
+
+ DebugPrint((1,
+ "GetTrackData: Error occurred on data read.\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
+ ScsiPortStallExecution(1500);
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ return FALSE;
+ }
+ }
+ } else {
+
+ //
+ // Bogus packet.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
+ ScsiPortStallExecution(1500);
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ DebugPrint((1,
+ "GetTrackData: Error occurred sending command.\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+
+ //
+ // Update bitmask of tracks found, including dealing with First, last, and multisession.
+ //
+
+ track = BCD_TO_DEC(dataBuffer[1]);
+ index = BCD_TO_DEC(dataBuffer[2]);
+
+ if (track == 0 && retry--) {
+
+ switch (index) {
+
+ case 0xA0:
+
+ //
+ // First track
+ //
+
+ DebugPrint((2,"First track\n"));
+ break;
+
+ case 0xA1:
+
+ //
+ // Last track
+ //
+
+ DebugPrint((2,"Last track\n"));
+ break;
+
+ case 0xB0:
+
+ //
+ // Multi-session. Through it away.
+ //
+
+ break;
+
+ default:
+
+ //
+ // Normal tracks
+ //
+
+ if ( (!(mask[index])) && (index < 100)) {
+
+ DebugPrint((2,"Track %d\n",index));
+
+ //
+ // Set the appropriate bit.
+ //
+
+ mask[index] = 1;
+
+ //
+ // Munge data into buffer
+ //
+
+ DebugPrint((2,"GetTrackData: track %x raw control %x\n",
+ index,
+ dataBuffer[0]));
+
+ //
+ // These fines drives have ADR and CONTROL flipped. Have to
+ // swizzle the nibbles.
+ //
+
+ control = dataBuffer[0];
+ controlHigh = (control & 0xF0) >> 4;
+ controlLow = control & 0x0F;
+ control = controlHigh | (controlLow << 4);
+
+ DebugPrint((2,"GetTrackData: track %x munged control %x\n",
+ index,
+ control));
+
+ minutes = BCD_TO_DEC(dataBuffer[7]);
+ seconds = BCD_TO_DEC(dataBuffer[8]);
+ frames = BCD_TO_DEC(dataBuffer[9]);
+
+ DebugPrint((2,"GetTrackData: control %x, msf %x %x %x\n",
+ control,
+ minutes,
+ seconds,
+ frames));
+
+
+ if (!DeviceExtension->MSFAddress) {
+
+ lba = MSF_TO_LBA(minutes,seconds,frames);
+
+ //
+ // Swizzle the block address.
+ //
+
+ data[7+(8*(index-1))] = ((PFOUR_BYTE)&lba)->Byte3;
+ data[6+(8*(index-1))] = ((PFOUR_BYTE)&lba)->Byte2;
+ data[5+(8*(index-1))] = ((PFOUR_BYTE)&lba)->Byte1;
+ data[4+(8*(index-1))] = ((PFOUR_BYTE)&lba)->Byte0;
+
+ } else {
+
+ data[7+(8*(index-1))] = frames;
+ data[6+(8*(index-1))] = seconds;
+ data[5+(8*(index-1))] = minutes;
+ data[4+(8*(index-1))] = 0;
+ }
+
+ data[3+(8*(index-1))] = 0;
+ data[2+(8*(index-1))] = index;
+ data[1+(8*(index-1))] = control;
+ data[0+(8*(index-1))] = 0;
+
+ //
+ // Update number of tracks found.
+ //
+
+ tracksFound++;
+
+ }
+
+ break;
+
+ } // switch
+
+ } else {
+
+ if (zeroCount++ >= 2000) {
+
+ //
+ // A little defensive work. It's possible that this thing
+ // could spin forever.
+ //
+
+ DebugPrint((1,"Too many zeros\n"));
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
+ ScsiPortStallExecution(1500);
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+ }
+ } // while
+
+ DebugPrint((2,"Retry = %d\n",retry));
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
+
+ return TRUE;
+
+} // End ReadToc
+
+
+BOOLEAN
+MitsumiReadToc(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ DeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if successful.
+
+--*/
+{
+
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
+ PUCHAR data = DeviceExtension->DataBuffer;
+ PCDB cdb = (PCDB)Srb->Cdb;
+ ULONG dataLength;
+ ULONG i,j,lba;
+ UCHAR status,leadOutM,leadOutS,leadOutF;
+
+
+ if (cdb->READ_TOC.Format == 0) {
+
+ dataLength = 8;
+
+ //
+ // Ensure that the drive is ready for this.
+ //
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ if (!(status & STATUS_DISC_IN) || (status & STATUS_DOOR_OPEN) ) {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ if (Srb->SenseInfoBufferLength) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ return FALSE;
+ }
+
+ if (!(status & STATUS_CMD_ERROR)) {
+
+ //
+ // Read the Toc data
+ //
+
+ for (i = 0; i < dataLength; i++) {
+ ReadStatus(DeviceExtension,baseIoAddress,*data);
+ if (*data == 0xFF) {
+
+ //
+ // Timeout occurred.
+ //
+
+ DebugPrint((1,
+ "MitsumiReadToc: Error occurred on data read.\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+ data++;
+ }
+
+ //
+ // All of the 'Toc' data has been read. Now munge it into a form that is useable.
+ // The Mitsumi TOC data is abbreviated at best. The exciting GetTrackData routine
+ // gets the actual stuff in which we are interested.
+ //
+
+ DeviceExtension->ByteCount = 0;
+ data = DeviceExtension->DataBuffer;
+
+ leadOutM = BCD_TO_DEC(data[2]);
+ leadOutS = BCD_TO_DEC(data[3]);
+ leadOutF = BCD_TO_DEC(data[4]);
+
+ //
+ // Set First and Last track.
+ //
+
+ data[2] = BCD_TO_DEC(data[0]);
+ data[3] = BCD_TO_DEC(data[1]);
+
+ //
+ // Set sizeof TOC data
+ //
+
+ data[0] = ((( data[3] - data[2]) * 8) + 2) >> 8;
+ data[1] = ((( data[3] - data[2]) * 8) + 2) & 0xFF;
+
+ DeviceExtension->DataBuffer += 4;
+
+ if (!GetTrackData(DeviceExtension,(data[3] - data[2] + 1))) {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+
+ }
+
+ //
+ // Push buffer pointer to end of TOC data
+ //
+
+ DeviceExtension->DataBuffer += 8*(data[3]-data[2] + 1);
+
+ //
+ // Lead out area
+ //
+
+ DeviceExtension->DataBuffer[0] = 0;
+ DeviceExtension->DataBuffer[1] = 0x10;
+ DeviceExtension->DataBuffer[3] = 0;
+
+ DeviceExtension->DataBuffer[2] = 0xAA;
+
+ if (!DeviceExtension->MSFAddress) {
+
+ lba = MSF_TO_LBA(leadOutM,leadOutS,leadOutF);
+
+ DeviceExtension->DataBuffer[4] = ((PFOUR_BYTE)&lba)->Byte3;
+ DeviceExtension->DataBuffer[5] = ((PFOUR_BYTE)&lba)->Byte2;
+ DeviceExtension->DataBuffer[6] = ((PFOUR_BYTE)&lba)->Byte1;
+ DeviceExtension->DataBuffer[7] = ((PFOUR_BYTE)&lba)->Byte0;
+
+ } else {
+
+ DeviceExtension->DataBuffer[4] = 0;
+ DeviceExtension->DataBuffer[5] = leadOutM;
+ DeviceExtension->DataBuffer[6] = leadOutS;
+ DeviceExtension->DataBuffer[7] = leadOutF;
+ }
+
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+
+ } else {
+
+ //
+ // Session info.
+ //
+
+ dataLength = 4;
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ if (!(status & STATUS_DISC_IN) || (status & STATUS_DOOR_OPEN) ) {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ if (Srb->SenseInfoBufferLength) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ return FALSE;
+ }
+
+ if (!(status & STATUS_CMD_ERROR)) {
+
+ //
+ // Read the 'session info' data
+ //
+
+ for (i = 0; i < dataLength; i++) {
+ ReadStatus(DeviceExtension,baseIoAddress,*data);
+ if (*data == 0xFF) {
+
+ //
+ // Timeout occurred.
+ //
+
+ DebugPrint((1,
+ "MitsumiReadToc: Error occurred on data read.\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+ data++;
+ }
+
+ DeviceExtension->ByteCount = 0;
+ data = DeviceExtension->DataBuffer;
+
+ leadOutM = BCD_TO_DEC(data[1]);
+ leadOutS = BCD_TO_DEC(data[2]);
+ leadOutF = BCD_TO_DEC(data[3]);
+
+ if (!DeviceExtension->MSFAddress) {
+
+ lba = MSF_TO_LBA(leadOutM,leadOutS,leadOutF);
+
+ //
+ // Check for non-multi session disk. The data will
+ // be bogus if it is.
+ //
+
+ if ((LONG)lba < 0) {
+ lba = 0;
+ }
+
+ DeviceExtension->DataBuffer[8] = ((PFOUR_BYTE)&lba)->Byte3;
+ DeviceExtension->DataBuffer[9] = ((PFOUR_BYTE)&lba)->Byte2;
+ DeviceExtension->DataBuffer[10] = ((PFOUR_BYTE)&lba)->Byte1;
+ DeviceExtension->DataBuffer[11] = ((PFOUR_BYTE)&lba)->Byte0;
+
+ } else {
+
+ data[11] = leadOutF;
+ data[10] = leadOutS;
+ data[9] = leadOutM;
+ data[8] = 0;
+ }
+
+ //
+ // Stuff the rest of the buffer with meaningful data.(Look in the spec.)
+ //
+
+ data[7] = 0;
+ data[6] = 0;
+ data[5] = 0;
+ data[4] = 0;
+ data[3] = 0x1;
+ data[2] = 0x1;
+ data[1] = 0xA;
+ data[0] = 0;
+
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+MitsumiReadSubQ(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+{
+
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG dataLength = DeviceExtension->ByteCount;
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->CurrentSrb;
+ PUCHAR dataBuffer = DeviceExtension->DataBuffer;
+ PCDB cdb = (PCDB)Srb->Cdb;
+ ULONG i,j;
+ ULONG lba;
+ UCHAR status,minutes,seconds,frames;
+ UCHAR format = cdb->SUBCHANNEL.Format;
+
+ if (format == 1) {
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ if (!(status & STATUS_CMD_ERROR)) {
+
+ //
+ // Read the position data
+ //
+
+ for (i = 0; i < 9; i++) {
+ ReadStatus(DeviceExtension,baseIoAddress,dataBuffer[i]);
+ if (dataBuffer[i] == 0xFF) {
+
+ //
+ // Timeout occurred.
+ //
+
+ DebugPrint((1,
+ "GetTrackData: Error occurred on data read.\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ return FALSE;
+ }
+ }
+ } else {
+
+ //
+ // Bogus packet.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_SET_DRV_MODE);
+ ScsiPortWritePortUchar(&baseIoAddress->Data, 0x1);
+ ScsiPortStallExecution(1500);
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ DebugPrint((1,
+ "GetTrackData: Error occurred sending command.\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ return FALSE;
+ }
+
+ //
+ // Format the data correctly. Refer to the scsi spec.
+ //
+
+ if (DeviceExtension->MSFAddress) {
+
+ dataBuffer[15] = BCD_TO_DEC(dataBuffer[5]);
+ dataBuffer[14] = BCD_TO_DEC(dataBuffer[4]);
+ dataBuffer[13] = BCD_TO_DEC(dataBuffer[3]);
+ dataBuffer[12] = 0;
+ dataBuffer[11] = BCD_TO_DEC(dataBuffer[9]);
+ dataBuffer[10] = BCD_TO_DEC(dataBuffer[8]);
+ dataBuffer[9] = BCD_TO_DEC(dataBuffer[7]);
+ dataBuffer[8] = 0;
+
+ DebugPrint((3,"MitsumiSubQ: Current MSF %x %x %x\n",
+ dataBuffer[9],
+ dataBuffer[10],
+ dataBuffer[11]));
+
+ } else {
+
+ minutes = BCD_TO_DEC(dataBuffer[3]);
+ seconds = BCD_TO_DEC(dataBuffer[4]);
+ frames = BCD_TO_DEC(dataBuffer[5]);
+
+ lba = MSF_TO_LBA(minutes,seconds,frames);
+
+ dataBuffer[15] = ((PFOUR_BYTE)&lba)->Byte0;
+ dataBuffer[14] = ((PFOUR_BYTE)&lba)->Byte1;
+ dataBuffer[13] = ((PFOUR_BYTE)&lba)->Byte2;
+ dataBuffer[12] = ((PFOUR_BYTE)&lba)->Byte3;
+
+ minutes = BCD_TO_DEC(dataBuffer[7]);
+ seconds = BCD_TO_DEC(dataBuffer[8]);
+ frames = BCD_TO_DEC(dataBuffer[9]);
+
+ lba = MSF_TO_LBA(minutes,seconds,frames);
+
+ dataBuffer[11] = ((PFOUR_BYTE)&lba)->Byte0;
+ dataBuffer[10] = ((PFOUR_BYTE)&lba)->Byte1;
+ dataBuffer[9] = ((PFOUR_BYTE)&lba)->Byte2;
+ dataBuffer[8] = ((PFOUR_BYTE)&lba)->Byte3;
+
+ DebugPrint((3,"MitsumiSubQ: Current LBA %x\n",
+ lba));
+ }
+
+
+ dataBuffer[7] = BCD_TO_DEC(dataBuffer[2]);
+ dataBuffer[6] = BCD_TO_DEC(dataBuffer[1]);
+ dataBuffer[5] = BCD_TO_DEC(dataBuffer[0]);
+ dataBuffer[4] = format;
+
+ DebugPrint((3,"MitsumiSubQ: Track %x, index %x\n",
+ dataBuffer[6],
+ dataBuffer[7]));
+
+ dataBuffer[3] = 12;
+ dataBuffer[2] = 0;
+
+ if (status & STATUS_AUDIO) {
+ dataBuffer[1] = AUDIO_STATUS_PLAYING;
+ } else {
+ dataBuffer[1] = (UCHAR)DeviceExtension->AudioStatus;
+ DeviceExtension->AudioStatus = AUDIO_STATUS_NO_STATUS;
+ }
+
+ DebugPrint((3,"MitsumiSubQ: Audio Status %x\n",
+ dataBuffer[1]));
+
+ dataBuffer[0] = 0;
+
+ DeviceExtension->ByteCount = 0;
+
+ } else {
+
+ //
+ // Not supported right now.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ return FALSE;
+ }
+ return TRUE;
+
+}
+
+
+VOID
+MitsumiCallBack(
+ IN PVOID HwDeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ Timer call-back routine which functions as the ISR for this polling driver.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ None
+
+--*/
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PREGISTERS baseIoAddress = deviceExtension->BaseIoAddress;
+ ULONG dataLength = deviceExtension->ByteCount;
+ PSCSI_REQUEST_BLOCK Srb = deviceExtension->CurrentSrb;
+ PCMD_PACKET packet;
+ PCDB cdb;
+ BOOLEAN requestSuccess = FALSE;
+ UCHAR scsiOp;
+ UCHAR status;
+
+ if (!Srb) {
+
+ //
+ // Something is hosed, just return.
+ //
+
+ DebugPrint((1,
+ "MitsumiCallBack: Null Srb.\n"));
+ return;
+ }
+
+ cdb = (PCDB)Srb->Cdb;
+ packet = (PCMD_PACKET)Srb->SrbExtension;
+ scsiOp = Srb->Cdb[0];
+
+ switch (scsiOp) {
+ case SCSIOP_READ_CAPACITY:
+
+ if (MitsumiReadCapacity(deviceExtension)) {
+ requestSuccess = TRUE;
+ }
+ break;
+
+ case SCSIOP_READ:
+
+ if (MitsumiRead(deviceExtension)) {
+
+ //
+ // Read was successful
+ //
+
+ requestSuccess = TRUE;
+
+ } else if (Srb->SrbStatus == SRB_STATUS_PENDING) {
+
+ //
+ // We have more data to transfer. Go away while the lightning fast
+ // mechanism does its work.
+ //
+
+ return;
+ }
+
+ break;
+
+ case SCSIOP_READ_TOC:
+
+ if (MitsumiReadToc(deviceExtension)) {
+ requestSuccess = TRUE;
+ }
+ break;
+
+ case SCSIOP_READ_SUB_CHANNEL:
+
+ if (MitsumiReadSubQ(deviceExtension)) {
+ requestSuccess = TRUE;
+ }
+ break;
+
+ case SCSIOP_PLAY_AUDIO_MSF:
+
+ ReadStatus(deviceExtension,baseIoAddress,status);
+ if (SUCCESS(status)) {
+
+ deviceExtension->AudioStatus = AUDIO_STATUS_SUCCESS;
+ requestSuccess = TRUE;
+
+ } else {
+
+ deviceExtension->AudioStatus = AUDIO_STATUS_ERROR;
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ }
+
+ break;
+
+ case SCSIOP_PAUSE_RESUME:
+
+ if(cdb->PAUSE_RESUME.Action) {
+
+ ULONG i;
+ UCHAR minutes,seconds,frames;
+
+ //
+ // We did a seek to the saved position. Now issue a play from here
+ // to the saved ending MSF.
+ //
+
+ ReadStatus(deviceExtension,baseIoAddress,status);
+ if (SUCCESS(status)) {
+
+ deviceExtension->AudioStatus = AUDIO_STATUS_SUCCESS;
+ requestSuccess = TRUE;
+
+ } else {
+
+ deviceExtension->AudioStatus = AUDIO_STATUS_ERROR;
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ }
+
+ minutes = (UCHAR)(deviceExtension->EndPosition / (60 * 75));
+ seconds = (UCHAR)((deviceExtension->EndPosition % (60 * 75)) / 75);
+ frames = (UCHAR)((deviceExtension->EndPosition % (60 * 75)) % 75);
+
+ DebugPrint((2,
+ "MitsumiBuildCommand: resume: lba %x, m %x, s %x, f%x\n",
+ deviceExtension->SavedPosition,
+ minutes,
+ seconds,
+ frames));
+
+ //
+ // Convert MSF to BCD. Don't need to setup start address and opcode since they are
+ // already there.
+ //
+
+ packet->Parameters[3] = DEC_TO_BCD(minutes);
+ packet->Parameters[4] = DEC_TO_BCD(seconds);
+ packet->Parameters[5] = DEC_TO_BCD(frames);
+
+
+ //
+ // Send the packet.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data,packet->OperationCode);
+ for (i = 0; i < 6; i++) {
+ ScsiPortWritePortUchar(&baseIoAddress->Data,packet->Parameters[i]);
+ }
+
+ //
+ // Wait for completion, and update status.
+ //
+
+ ScsiPortStallExecution(4000);
+
+ ReadStatus(deviceExtension,baseIoAddress,status);
+ if (SUCCESS(status)) {
+
+ deviceExtension->AudioStatus = AUDIO_STATUS_SUCCESS;
+ requestSuccess = TRUE;
+
+ } else {
+
+ deviceExtension->AudioStatus = AUDIO_STATUS_ERROR;
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ }
+
+ } else {
+
+ ReadStatus(deviceExtension,baseIoAddress,status);
+ if (SUCCESS(status)) {
+ deviceExtension->AudioStatus = AUDIO_STATUS_PAUSED;
+
+ UpdateCurrentPosition(deviceExtension);
+
+ requestSuccess = TRUE;
+ } else {
+
+ DebugPrint((1,"MitsumiCallBack: Error on pause %x\n",
+ status));
+
+ deviceExtension->AudioStatus = AUDIO_STATUS_ERROR;
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ }
+ }
+
+ break;
+
+ case SCSIOP_START_STOP_UNIT:
+
+ ReadStatus(deviceExtension,baseIoAddress,status);
+ if (SUCCESS(status)) {
+ requestSuccess = TRUE;
+ } else {
+
+ DebugPrint((1,"MitsumiCallBack: Error on start/stop %x\n",
+ status));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ }
+
+ break;
+
+ default:
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ } //switch scsiOp
+
+
+ if (requestSuccess) {
+
+ //
+ // Update srb and scsi status.
+ //
+
+ if (deviceExtension->ByteCount) {
+ Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+ } else {
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ Srb->ScsiStatus = SCSISTAT_GOOD;
+ }
+
+ //
+ // Indicate command complete.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ //
+ // Indicate ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return;
+}
+
+
+BOOLEAN
+MitsumiReset(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PREGISTERS baseIoAddress = deviceExtension->BaseIoAddress;
+ UCHAR status;
+
+ //
+ // Clean out device extension and complete outstanding commands.
+ //
+
+ if (deviceExtension->CurrentSrb) {
+
+ //
+ // Complete outstanding request with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ (ULONG)SRB_STATUS_BUS_RESET);
+
+ }
+
+ //
+ // Clear state fields.
+ //
+
+ deviceExtension->CurrentSrb = NULL;
+ deviceExtension->ByteCount = 0;
+ deviceExtension->DataBuffer = NULL;
+
+ //
+ // Reset the device.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Reset,0);
+ ScsiPortStallExecution(10);
+ ScsiPortWritePortUchar(&baseIoAddress->Status, 0);
+ ScsiPortStallExecution (10);
+
+ ReadStatus(deviceExtension,baseIoAddress,status);
+
+ //
+ // Wait 1 second for unit to recover.
+ //
+
+ ScsiPortStallExecution (1000 * 1000);
+
+ //
+ // Indicate ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end MitsumiReset()
+
+BOOLEAN
+MitsumiBuildCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ HwDeviceExtension - The hardware device extension.
+
+ Srb - The current Srb.
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ PCMD_PACKET packet = (PCMD_PACKET)Srb->SrbExtension;
+ PCDB cdb = (PCDB)Srb->Cdb;
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+ UCHAR minutes,seconds,frames;
+
+ //
+ // Zero the packet.
+ //
+
+ packet->OperationCode = 0;
+ for (i = 0; i < 6; i++) {
+ packet->Parameters[i] = 0;
+ }
+
+ DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
+ DeviceExtension->ByteCount = Srb->DataTransferLength;
+ DeviceExtension->MSFAddress = FALSE;
+
+ Srb->SrbStatus = SRB_STATUS_PENDING;
+
+ //
+ // Map CDB to Panasonic packet command
+ //
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_READ:
+
+ DeviceExtension->StatusRetries = 0;
+
+#ifdef GATHER_STATS
+ DeviceExtension->Requests++;
+ DeviceExtension->FirstCall = TRUE;
+#endif
+ packet->OperationCode = (DeviceExtension->DriveType == FX001D) ? OP_READ_PLAY_DBL : OP_READ_PLAY;
+
+ //
+ // Convert starting LBA to MSF
+ //
+
+ LBA_TO_MSF(cdb,minutes,seconds,frames);
+
+ //
+ // Convert MSF to BCD
+ //
+
+ packet->Parameters[0] = DEC_TO_BCD(minutes);
+ packet->Parameters[1] = DEC_TO_BCD(seconds);
+ packet->Parameters[2] = DEC_TO_BCD(frames);
+
+ //
+ // Convert blocks to transfer to BCD
+ //
+
+ packet->Parameters[3] = 0;
+ packet->Parameters[4] = cdb->CDB10.TransferBlocksMsb;
+ packet->Parameters[5] = cdb->CDB10.TransferBlocksLsb;
+
+ packet->ParameterLength = 6;
+
+ break;
+
+ case SCSIOP_START_STOP_UNIT:
+
+ if (cdb->START_STOP.Start) {
+
+ if (cdb->START_STOP.LoadEject) {
+
+ //
+ // Load an ejected disk and spin up.
+ //
+
+ packet->OperationCode = OP_LOAD;
+ packet->ParameterLength = 0;
+
+
+ } else {
+
+ //
+ // Spin up the device by issuing a seek to start of disk.
+ //
+
+ packet->OperationCode = (DeviceExtension->DriveType == FX001D) ? OP_READ_PLAY_DBL : OP_READ_PLAY;
+ packet->Parameters[0] = 0;
+ packet->Parameters[1] = 2;
+ packet->Parameters[2] = 0;
+ packet->Parameters[3] = 0;
+ packet->Parameters[4] = 0;
+ packet->Parameters[5] = 0;
+
+ packet->ParameterLength = 6;
+
+
+ }
+ } else {
+
+ if (cdb->START_STOP.LoadEject) {
+
+ //
+ // Eject the disk
+ //
+
+ packet->OperationCode = OP_EJECT;
+ packet->ParameterLength = 0;
+
+ } else {
+
+ //
+ // Seek to start and hold.
+ //
+
+ packet->OperationCode = OP_READ_PLAY;
+ packet->Parameters[0] = 0;
+ packet->Parameters[1] = 2;
+ packet->Parameters[2] = 0;
+ packet->Parameters[3] = 0;
+ packet->Parameters[4] = 0;
+ packet->Parameters[5] = 0;
+
+ packet->ParameterLength = 6;
+ }
+ }
+
+ break;
+
+ case SCSIOP_PAUSE_RESUME:
+
+ //
+ // Issue pause/resume.
+ //
+
+
+ if(cdb->PAUSE_RESUME.Action) {
+
+ //
+ // Resume - issue a zero length play to the "saved" MSF.
+ //
+
+ packet->OperationCode = OP_READ_PLAY;
+
+ //
+ // Convert starting LBA to MSF
+ //
+
+ minutes = (UCHAR)(DeviceExtension->SavedPosition / (60 * 75));
+ seconds = (UCHAR)((DeviceExtension->SavedPosition % (60 * 75)) / 75);
+ frames = (UCHAR)((DeviceExtension->SavedPosition % (60 * 75)) % 75);
+
+ DebugPrint((2,
+ "MitsumiBuildCommand: resume: lba %x, m %x, s %x, f%x\n",
+ DeviceExtension->SavedPosition,
+ minutes,
+ seconds,
+ frames));
+
+ //
+ // Convert MSF to BCD
+ //
+
+ packet->Parameters[0] = DEC_TO_BCD(minutes);
+ packet->Parameters[1] = DEC_TO_BCD(seconds);
+ packet->Parameters[2] = DEC_TO_BCD(frames);
+
+ //
+ // Setup a 'play' of zero length.
+ //
+
+ packet->Parameters[3] = 0;
+ packet->Parameters[4] = 0;
+ packet->Parameters[5] = 0;
+
+ packet->ParameterLength = 6;
+
+
+ } else {
+
+ //
+ // Pause - issue Hold command.
+ //
+
+ packet->OperationCode = OP_PAUSE;
+ packet->ParameterLength = 0;
+
+ }
+
+
+ break;
+
+ case SCSIOP_PLAY_AUDIO_MSF:
+
+ //
+ // Update the status to ensure that a current audio play
+ // is not in progress.
+ //
+
+ CheckStatus(DeviceExtension);
+
+ if (DeviceExtension->DriveStatus & STATUS_AUDIO) {
+
+ //
+ // stop the current play by issuing hold command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_PAUSE);
+
+ ScsiPortStallExecution(1000);
+
+ CheckStatus(DeviceExtension);
+ if (DeviceExtension->DriveStatus & STATUS_AUDIO) {
+ DebugPrint((1,"MitsumiBuildcommand: Audio still not paused. %x\n",
+ DeviceExtension->DriveStatus));
+ }
+
+
+ }
+
+ packet->OperationCode = OP_READ_PLAY;
+
+ //
+ // Convert MSF to BCD
+ //
+
+ packet->Parameters[0] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.StartingM);
+ packet->Parameters[1] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.StartingS);
+ packet->Parameters[2] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.StartingF);
+
+ //
+ // Convert end address to BCD
+ //
+
+ packet->Parameters[3] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.EndingM);
+ packet->Parameters[4] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.EndingS);
+ packet->Parameters[5] = DEC_TO_BCD(cdb->PLAY_AUDIO_MSF.EndingF);
+
+ //
+ // Setup EndPosition in DevExt. since we may get a pause/resume.
+ //
+
+ DeviceExtension->EndPosition = MSF_TO_LBA(cdb->PLAY_AUDIO_MSF.EndingM,
+ cdb->PLAY_AUDIO_MSF.EndingS,
+ cdb->PLAY_AUDIO_MSF.EndingF);
+
+ //
+ // Determine is this is a seek. If so, zero the ending address fields to indicate
+ // a play of zero length.
+ //
+
+ if (packet->Parameters[0] == packet->Parameters[3] &&
+ packet->Parameters[1] == packet->Parameters[4] &&
+ packet->Parameters[2] == packet->Parameters[5] ) {
+
+ packet->Parameters[3] = 0;
+ packet->Parameters[4] = 0;
+ packet->Parameters[5] = 0;
+
+ }
+ packet->ParameterLength = 6;
+
+ break;
+
+
+ case SCSIOP_READ_TOC:
+
+ //
+ // See if MSF addresses are enabled.
+ //
+
+ if ( cdb->READ_TOC.Msf) {
+ DeviceExtension->MSFAddress = TRUE;
+ }
+
+ //
+ // Setup the appropriate command - full read toc or session info.
+ //
+
+ if (cdb->READ_TOC.Format == 0) {
+
+ packet->OperationCode = OP_READ_TOC;
+ packet->ParameterLength = 0;
+
+ } else {
+
+ packet->OperationCode = OP_READ_SESSION;
+ packet->ParameterLength = 0;
+ }
+
+ break;
+
+
+ case SCSIOP_INQUIRY: {
+
+ PINQUIRYDATA inquiryData = Srb->DataBuffer;
+
+ //
+ // For now, support only one drive at drive select 0 on this controller.
+ // Actually, I have no idea if more can be supported.
+ //
+
+ if (Srb->Lun > 0 || Srb->TargetId > 0) {
+
+ Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ return FALSE;
+
+ }
+
+ //
+ // Zero inquiry buffer.
+ //
+
+ for (i = 0; i < INQUIRYDATABUFFERSIZE; i++) {
+ ((PUCHAR)inquiryData)[i] = 0;
+ }
+
+ //
+ // Fill in the necessary fields of inquiry data.
+ //
+
+ inquiryData->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
+ inquiryData->RemovableMedia = 1;
+
+ inquiryData->VendorId[0] = 'M';
+ inquiryData->VendorId[1] = 'I';
+ inquiryData->VendorId[2] = 'T';
+ inquiryData->VendorId[3] = 'S';
+ inquiryData->VendorId[4] = 'U';
+ inquiryData->VendorId[5] = 'M';
+ inquiryData->VendorId[6] = 'I';
+ inquiryData->VendorId[7] = ' ';
+
+ inquiryData->ProductId[0] = 'C';
+ inquiryData->ProductId[1] = 'R';
+ inquiryData->ProductId[2] = 'M';
+ inquiryData->ProductId[3] = 'C';
+ inquiryData->ProductId[4] = '-';
+
+ if (DeviceExtension->DriveType == LU005) {
+
+ inquiryData->ProductId[5] = 'L';
+ inquiryData->ProductId[6] = 'U';
+ inquiryData->ProductId[9] = '5';
+ inquiryData->ProductId[10] = 'S';
+
+ } else if (DeviceExtension->DriveType == FX001) {
+
+ inquiryData->ProductId[5] = 'F';
+ inquiryData->ProductId[6] = 'X';
+ inquiryData->ProductId[9] = '1';
+ inquiryData->ProductId[10] = ' ';
+
+ } else {
+
+ inquiryData->ProductId[5] = 'F';
+ inquiryData->ProductId[6] = 'X';
+ inquiryData->ProductId[9] = '1';
+ inquiryData->ProductId[10] = 'D';
+
+ }
+
+ inquiryData->ProductId[7] = '0';
+ inquiryData->ProductId[8] = '0';
+ inquiryData->ProductId[11] = ' ';
+ inquiryData->ProductId[12] = ' ';
+ inquiryData->ProductId[13] = ' ';
+ inquiryData->ProductId[14] = ' ';
+ inquiryData->ProductId[15] = ' ';
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Srb->ScsiStatus = SCSISTAT_GOOD;
+
+ break;
+ }
+
+ case SCSIOP_READ_CAPACITY:
+
+ //
+ // Create the READ_TOC_DATA packet. The returned values will be munged
+ // into a usable form.
+ //
+
+ packet->OperationCode = OP_READ_TOC;
+ packet->ParameterLength = 0;
+
+ break;
+
+ case SCSIOP_READ_SUB_CHANNEL:
+
+
+ if ( cdb->SUBCHANNEL.Msf) {
+ DeviceExtension->MSFAddress = TRUE;
+ }
+
+ //
+ // determine what sub-channel data format is required, since this device has 3 different commands
+ // for the SCSI READ_SUB_CHANNEL Opcode. In the callback routine, the remaining calls, if any, will
+ // be issued.
+ //
+
+ switch (cdb->SUBCHANNEL.Format) {
+
+ case 1:
+
+ //
+ // Current position.
+ //
+
+ packet->OperationCode = OP_READ_SUB_CHANNEL;
+ packet->ParameterLength = 0;
+
+ break;
+
+ case 2:
+
+ //
+ // Media catalogue number. TODO: support the rest of these.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case 3:
+
+ //
+ // Track ISRC
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ default:
+
+ //
+ // Bogus value.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ return FALSE;
+ }
+
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+ case SCSIOP_REQUEST_SENSE:
+
+ break;
+
+ case SCSIOP_MODE_SENSE:
+ case SCSIOP_MODE_SELECT:
+ case SCSIOP_MEDIUM_REMOVAL:
+ case SCSIOP_READ_HEADER:
+
+ //
+ // Dont support this for now. Fall through to default.
+ //
+
+ default:
+
+ DebugPrint((1,
+ "MitsumiBuildCommand: Unsupported command %x\n",
+ Srb->Cdb[0]));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ return FALSE;
+
+ } // end switch
+
+ return TRUE;
+
+}
+
+BOOLEAN
+MitsumiSendCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ HwDeviceExtension - The hardware device extension.
+
+ Srb - The current Srb.
+
+Return Value:
+
+ TRUE if command sent successfully.
+
+--*/
+
+{
+
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ PCDB cdb = (PCDB)Srb->Cdb;
+ PCMD_PACKET packet = (PCMD_PACKET)Srb->SrbExtension;
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+ ULONG i;
+ UCHAR sessionData[6];
+ UCHAR minutes,seconds,frames,frameData;
+ UCHAR status = DeviceExtension->DriveStatus;
+
+
+ //
+ // Map CDB to Mitsumi packet command
+ //
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_READ:
+
+
+ break;
+
+ case SCSIOP_INQUIRY:
+
+ //
+ // Data buffer filled in during MitsumiBuildCommand.
+ //
+
+ return TRUE;
+
+ case SCSIOP_READ_TOC:
+ case SCSIOP_PAUSE_RESUME:
+ case SCSIOP_PLAY_AUDIO_MSF:
+ case SCSIOP_READ_CAPACITY:
+ case SCSIOP_READ_SUB_CHANNEL:
+ case SCSIOP_START_STOP_UNIT:
+
+ //
+ // Nothing to do here. Everything setup in BuildCommand.
+ //
+
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+
+
+ if (!CheckStatus(DeviceExtension)) {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ return FALSE;
+ }
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Srb->ScsiStatus = SCSISTAT_GOOD;
+
+ return TRUE;
+
+ case SCSIOP_REQUEST_SENSE:
+
+ //
+ // Issue the ReadAndMapError command, which will create a request sense packet.
+ //
+
+ if (ReadAndMapError(DeviceExtension,Srb)) {
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ Srb->ScsiStatus = SCSISTAT_GOOD;
+
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ }
+
+ //
+ // Update the drive status.
+ //
+
+ CheckStatus(DeviceExtension);
+
+ return TRUE;
+
+ case SCSIOP_MODE_SENSE:
+ case SCSIOP_MODE_SELECT:
+ case SCSIOP_READ_HEADER:
+ case SCSIOP_MEDIUM_REMOVAL:
+
+ //
+ // Dont support this for now. Fall through.
+ //
+
+ default:
+
+ DebugPrint((1,
+ "MitsumiSendCommand: Unsupported command %x\n",
+ Srb->Cdb[0]));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ } // end switch
+
+ if (Srb->SrbStatus == SRB_STATUS_PENDING) {
+
+ //
+ // Write the packet
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data,packet->OperationCode);
+ for (i = 0; i < packet->ParameterLength; i++) {
+ ScsiPortWritePortUchar(&baseIoAddress->Data,packet->Parameters[i]);
+ }
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+
+} // End MitsumiSendCommand()
+
+
+UCHAR
+WaitForSTEN(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ DeviceExtension - The device extension.
+
+
+Return Value:
+
+ TRUE if STEN signal asserted within timeout period.
+
+--*/
+
+{
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i;
+ UCHAR status;
+
+ for (i = 0; i < 40 * 1000; i++) {
+ status = ScsiPortReadPortUchar(&baseIoAddress->Status);
+ if (status & STEN) {
+ ScsiPortStallExecution(10);
+ } else {
+ break;
+ }
+ }
+ if (i == 1000 * 40) {
+ return 0xFF;
+ }
+ return status;
+}
+
+BOOLEAN
+CheckStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ DeviceExtension - The device extension.
+
+
+Return Value:
+
+ Drive status.
+
+--*/
+
+{
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ CMD_PACKET packet;
+ ULONG i;
+ UCHAR status;
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data,OP_READ_STATUS);
+ do {
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+ } while (status == 0xFF);
+
+ DeviceExtension->DriveStatus = status;
+ // TODO: Change to SUCCESS macro
+
+ if ( (status & (STATUS_DOOR_OPEN | STATUS_CMD_ERROR | STATUS_MEDIA_CHANGE | STATUS_READ_ERROR)) ||
+ (!(status & (STATUS_SPIN_UP | STATUS_DISC_IN))) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+
+BOOLEAN
+UpdateCurrentPosition(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ Determines the current MSF and stores it in the deviceExtension in LBA form.
+
+Arguments:
+
+ HwDeviceExtension - The hardware device extension.
+
+Return Value:
+
+ TRUE - If command succeeded.
+
+--*/
+{
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ ULONG i,
+ lba;
+ UCHAR status;
+ UCHAR dataBuffer[10];
+
+ //
+ // Issue SubQ command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data, OP_READ_SUB_CHANNEL);
+
+ ScsiPortStallExecution(1000);
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ if (!(status & STATUS_CMD_ERROR)) {
+
+ //
+ // Read the position data
+ //
+
+ for (i = 0; i < 9; i++) {
+ ReadStatus(DeviceExtension,baseIoAddress,dataBuffer[i]);
+ if (dataBuffer[i] == 0xFF) {
+
+ //
+ // Timeout occurred.
+ //
+
+ DebugPrint((1,
+ "UpdateCurrentPosition: Error occurred on data read. %x\n",
+ status));
+
+ return FALSE;
+ }
+ }
+ } else {
+
+ DebugPrint((1,
+ "UpdateCurrentPosition: Error occurred sending command. %x\n",
+ status));
+
+ return FALSE;
+ }
+
+ //
+ // Convert the MSF to LBA and store in devExt.
+ //
+
+ BCD_TO_DEC(dataBuffer[7]);
+ BCD_TO_DEC(dataBuffer[8]);
+ BCD_TO_DEC(dataBuffer[9]);
+
+ lba = MSF_TO_LBA(dataBuffer[7],dataBuffer[8],dataBuffer[9]);
+
+ DebugPrint((2,
+ "UpdateCurrentPosition: M %x, S %x, F %x LBA %x\n",
+ dataBuffer[7],
+ dataBuffer[8],
+ dataBuffer[9],
+ lba));
+
+ DeviceExtension->SavedPosition = lba;
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+ReadAndMapError(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ HwDeviceExtension - The hardware device extension.
+
+ Srb - The failing Srb.
+
+
+Return Value:
+
+ SRB Error
+
+--*/
+
+{
+ PREGISTERS baseIoAddress = DeviceExtension->BaseIoAddress;
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->DataBuffer;
+ UCHAR status = DeviceExtension->DriveStatus;
+ ULONG i;
+ UCHAR errorData;
+
+ //
+ // Check drive status. It may have been updated at the point of error.
+ //
+
+ if ( (status & STATUS_DOOR_OPEN) ||
+ !(status & STATUS_DISC_IN)) {
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+ return TRUE;
+ }
+
+
+ if (status & STATUS_CMD_ERROR ) {
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
+ senseBuffer->AdditionalSenseCode = 0x24;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+ return TRUE;
+ }
+
+ if (status & STATUS_MEDIA_CHANGE) {
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
+ senseBuffer->AdditionalSenseCodeQualifier = 0x0;
+ return TRUE;
+
+ }
+
+ if (!(status & STATUS_SPIN_UP)) {
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_LUN_NOT_READY;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+ return TRUE;
+ }
+
+
+ //
+ // Setup sense buffer common values.
+ //
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->IncorrectLength = FALSE;
+ senseBuffer->SenseKey = 0;
+ senseBuffer->AdditionalSenseCode = 0;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ if (status & STATUS_READ_ERROR ) {
+
+ //
+ // Issue the request sense command.
+ //
+
+ ScsiPortWritePortUchar(&baseIoAddress->Data,OP_REQUEST_SENSE);
+
+
+ ReadStatus(DeviceExtension,baseIoAddress,status);
+
+ if (!(status & STATUS_CMD_ERROR)) {
+
+ //
+ // Read the sense data
+ //
+
+ ReadStatus(DeviceExtension,baseIoAddress,errorData);
+ if (errorData == 0xFF) {
+
+ //
+ // Timeout occurred.
+ //
+
+ DebugPrint((1,
+ "ReadAndMapError: Error occurred on data read.\n"));
+ return FALSE;
+ }
+
+ } else {
+
+ DebugPrint((1,
+ "ReadAndMapError: Error reading sense data\n"));
+ return FALSE;
+ }
+
+
+
+ //
+ // Map Mitsumi error code to Srb status
+ //
+
+ switch (errorData) {
+ case 0:
+
+ //
+ // No error.
+ //
+
+ senseBuffer->SenseKey = 0x00;
+ senseBuffer->AdditionalSenseCode = 0x00;
+ senseBuffer->AdditionalSenseCodeQualifier = 0x0;
+
+ break;
+
+ case 1:
+
+ //
+ // Mode error.
+ //
+
+ senseBuffer->SenseKey = 0x02;
+ senseBuffer->AdditionalSenseCode = 0x30;
+ senseBuffer->AdditionalSenseCodeQualifier = 0x02;
+
+ break;
+
+ case 2:
+
+ //
+ // Address error.
+ //
+
+ senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_ILLEGAL_BLOCK;
+ break;
+
+ case 3:
+
+ //
+ // Fatal error.
+ //
+
+ senseBuffer->SenseKey = SCSI_SENSE_HARDWARE_ERROR;
+
+ break;
+
+ case 4:
+
+ //
+ // Seek error.
+ //
+
+ senseBuffer->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_SEEK_ERROR;
+
+ break;
+
+ default:
+
+ senseBuffer->SenseKey = 0x00;
+ senseBuffer->AdditionalSenseCode = 0x00;
+ senseBuffer->AdditionalSenseCodeQualifier = 0x0;
+
+ }
+ }
+
+ return TRUE;
+
+} // end ReadAndMapError()
+
+
diff --git a/private/ntos/miniport/mitsumi/mitsumi.h b/private/ntos/miniport/mitsumi/mitsumi.h
new file mode 100644
index 000000000..ed0407b53
--- /dev/null
+++ b/private/ntos/miniport/mitsumi/mitsumi.h
@@ -0,0 +1,145 @@
+ /*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ mitsumi.h
+
+Abstract:
+
+
+Author:
+
+
+
+Revision History:
+
+--*/
+
+#include "scsi.h"
+
+
+typedef struct _REGISTERS {
+
+ UCHAR Data;
+ UCHAR Status;
+ UCHAR Control;
+ UCHAR Reset;
+
+} REGISTERS, *PREGISTERS;
+
+//
+// Control signals
+//
+
+#define DTEN 0x02
+#define STEN 0x04
+
+typedef struct _CMD_PACKET {
+
+ UCHAR OperationCode;
+ UCHAR Parameters[6];
+ UCHAR ParameterLength;
+
+} CMD_PACKET, *PCMD_PACKET;
+
+//
+// Drive version identifiers
+//
+
+typedef enum _DRIVE_TYPE{
+ LU005,
+ FX001,
+ FX001D
+} DRIVE_TYPE, *PDRIVE_TYPE;
+
+//
+// Status register codes.
+//
+
+#define STATUS_CMD_ERROR 0x01
+#define STATUS_AUDIO 0x02
+#define STATUS_READ_ERROR 0x04
+#define STATUS_DISC_TYPE 0x08
+#define STATUS_SPIN_UP 0x10
+#define STATUS_MEDIA_CHANGE 0x20
+#define STATUS_DISC_IN 0x40
+#define STATUS_DOOR_OPEN 0x80
+
+//
+// Audio State status
+//
+
+#define AUDIO_STATUS_PLAYING 0x11
+#define AUDIO_STATUS_PAUSED 0x12
+#define AUDIO_STATUS_SUCCESS 0x13
+#define AUDIO_STATUS_ERROR 0x14
+#define AUDIO_STATUS_NO_STATUS 0x15
+
+//
+// Command code indexes.
+//
+
+
+//#define OP_SPIN_UP
+#define OP_SPIN_DOWN 0xF0
+#define OP_READ_STATUS 0x40
+#define OP_EJECT 0xF6
+#define OP_LOAD 0xF8
+#define OP_SET_DRV_MODE 0x50
+#define OP_READ_PLAY 0xC0
+#define OP_READ_PLAY_DBL 0xC1
+#define OP_PREVENT_ALLOW_REMOVAL 0xFE
+#define OP_PAUSE 0x70
+#define OP_REQUEST_SENSE 0x30
+#define OP_READ_DRIVE_ID 0xDC
+#define OP_MODE_SENSE 0xC2
+#define OP_READ_SUB_CHANNEL 0x20
+#define OP_READ_TOC 0x10
+#define OP_READ_SESSION 0x11
+
+//
+// Error codes from Request Sense command.
+//
+
+#define NO_ERROR 0x00
+#define MODE_ERROR 0x01
+#define ADDRESS_ERROR 0x02
+#define FATAL_ERROR 0x03
+#define SEEK_ERROR 0x04
+
+
+#define LBA_TO_MSF(Cdb,Minutes,Seconds,Frames) \
+{ \
+ PCDB convertCdb = (Cdb); \
+ ULONG lba; \
+ lba = (ULONG)(convertCdb->CDB10.LogicalBlockByte0 * 0x1000000 + \
+ convertCdb->CDB10.LogicalBlockByte1 * 0x10000 + \
+ convertCdb->CDB10.LogicalBlockByte2 * 0x100 + \
+ convertCdb->CDB10.LogicalBlockByte3 + 150 \
+ ); \
+ (Minutes) = (UCHAR)(lba / (60 * 75)); \
+ (Seconds) = (UCHAR)((lba % (60 * 75)) / 75); \
+ (Frames) = (UCHAR)((lba % (60 * 75)) % 75); \
+}
+
+#define MSF_TO_LBA(Minutes,Seconds,Frames) \
+ (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
+
+#define BCD_TO_DEC(x) ( ((x) >> 4) * 10 + ((x) & 0x0F) )
+#define DEC_TO_BCD(x) ( (((x) / 10) << 4) + ((x) % 10) )
+
+#define ReadStatus(DevExtension,BaseIoAddress, Status)\
+{\
+ Status = WaitForSTEN(DevExtension);\
+ if (Status != 0xFF) {\
+ ScsiPortWritePortUchar(&BaseIoAddress->Control, 0x04);\
+ Status = ScsiPortReadPortUchar(&BaseIoAddress->Data);\
+ DevExtension->DriveStatus = Status;\
+ ScsiPortWritePortUchar(&BaseIoAddress->Control, 0x0C);\
+ }\
+}
+
+#define SUCCESS(Status)\
+ (((Status & (STATUS_CMD_ERROR | STATUS_READ_ERROR | STATUS_MEDIA_CHANGE | STATUS_DOOR_OPEN)) == 0) && (Status & (STATUS_DISC_IN | STATUS_SPIN_UP)))
diff --git a/private/ntos/miniport/mitsumi/mitsumi.rc b/private/ntos/miniport/mitsumi/mitsumi.rc
new file mode 100644
index 000000000..03fee1d8b
--- /dev/null
+++ b/private/ntos/miniport/mitsumi/mitsumi.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Mitsumi Proprietary CD-ROM Miniport Driver"
+#define VER_INTERNALNAME_STR "mitsumi.sys"
+#define VER_ORIGINALFILENAME_STR "mitsumi.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/mitsumi/sources b/private/ntos/miniport/mitsumi/sources
new file mode 100644
index 000000000..e878f5235
--- /dev/null
+++ b/private/ntos/miniport/mitsumi/sources
@@ -0,0 +1,19 @@
+
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=mitsumi
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+!IF $(ALPHA) || $(PPC)
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib $(BASEDIR)\public\sdk\lib\*\libcntpr.lib
+!ENDIF
+
+SOURCES=mitsumi.c \
+ mitsumi.rc
diff --git a/private/ntos/miniport/mylex/dac960/d960api.h b/private/ntos/miniport/mylex/dac960/d960api.h
new file mode 100644
index 000000000..a76fdf94b
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/d960api.h
@@ -0,0 +1,56 @@
+#include "ntddscsi.h"
+#include "raidapi.h"
+
+//
+// Function prototype declarations
+//
+
+BOOLEAN
+SubmitRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+BOOLEAN
+SubmitCdbDirect(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+BOOLEAN
+SendIoctlDcmdRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+BOOLEAN
+SendIoctlCdbDirect(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+VOID
+SetupAdapterInfo(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+VOID
+SetupDriverVersionInfo(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+#define DRIVER_REVISION 0x0305
+#define DRIVER_BUILD_DATE 0x00052495
+
+typedef struct _IOCTL_REQ_HEADER {
+
+ SRB_IO_CONTROL SrbIoctl;
+ UCHAR Unused1[2];
+ USHORT DriverErrorCode;
+ USHORT CompletionCode;
+ UCHAR Unused2[10];
+ HBA_GENERIC_MBOX GenMailBox;
+
+} IOCTL_REQ_HEADER, *PIOCTL_REQ_HEADER;
diff --git a/private/ntos/miniport/mylex/dac960/dac960nt.c b/private/ntos/miniport/mylex/dac960/dac960nt.c
new file mode 100644
index 000000000..ce3b740ea
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/dac960nt.c
@@ -0,0 +1,4152 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ Dac960Nt.c
+
+Abstract:
+
+ This is the device driver for the Mylex 960 family of disk array controllers.
+
+Author:
+
+ Mike Glass (mglass)
+
+Environment:
+
+ kernel mode only
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "Dmc960Nt.h"
+#include "Dac960Nt.h"
+#include "D960api.h"
+
+//
+// Function declarations
+//
+
+BOOLEAN
+Dac960EisaPciSendInitTimeRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN ULONG TimeOutValue
+)
+
+/*++
+
+Routine Description:
+
+ Send Request to DAC960-EISA/PCI Controllers and poll for command
+ completion
+
+Assumptions:
+ Controller Interrupts are turned off
+ Supports Dac960 Type 5 Commands only
+
+Arguments:
+
+ DeviceExtension - Adapter state information.
+ TimeoutValue - TimeOut value (0xFFFFFFFF - Polled Mode)
+
+Return Value:
+
+ TRUE if commands complete successfully.
+
+--*/
+
+{
+ ULONG i;
+ BOOLEAN completionStatus = TRUE;
+
+ //
+ // Claim submission semaphore.
+ //
+
+ if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY)
+ {
+ //
+ // Clear any bits set in system doorbell and tell controller
+ // that the mailbox is free.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell,
+ ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell));
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DAC960_LOCAL_DOORBELL_MAILBOX_FREE);
+
+ //
+ // Check semaphore again.
+ //
+
+ if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY)
+ {
+ return FALSE;
+ }
+ }
+
+ //
+ // Issue Request
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->OperationCode,
+ DeviceExtension->MailBox.OperationCode);
+
+ ScsiPortWritePortUlong(&DeviceExtension->PmailBox->PhysicalAddress,
+ DeviceExtension->MailBox.PhysicalAddress);
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DAC960_LOCAL_DOORBELL_SUBMIT_BUSY);
+
+ //
+ // Poll for completion.
+ //
+
+ for (i = 0; i < TimeOutValue; i++)
+ {
+ if (ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell) &
+ DAC960_SYSTEM_DOORBELL_COMMAND_COMPLETE) {
+ //
+ // Update Status field
+ //
+
+ DeviceExtension->MailBox.Status =
+ ScsiPortReadPortUshort(&DeviceExtension->PmailBox->Status);
+
+ break;
+ } else {
+
+ ScsiPortStallExecution(50);
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == TimeOutValue) {
+ DebugPrint((1,
+ "DAC960: Request: %x timed out\n",
+ DeviceExtension->MailBox.OperationCode));
+
+ completionStatus = FALSE;
+ }
+
+ //
+ // Dismiss interrupt and tell host mailbox is free.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell,
+ ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell));
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DAC960_LOCAL_DOORBELL_MAILBOX_FREE);
+
+ return (completionStatus);
+}
+
+BOOLEAN
+Dac960McaSendInitTimeRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN ULONG TimeOutValue
+)
+
+/*++
+
+Routine Description:
+
+ Send Request to DAC960-MCA Controller and poll for command completion
+
+Assumptions:
+ Controller Interrupts are turned off
+ Supports Dac960 Type 5 Commands only
+
+Arguments:
+
+ DeviceExtension - Adapter state information.
+ TimeoutValue - TimeOut value (0xFFFFFFFF - Polled Mode)
+
+Return Value:
+
+ TRUE if commands complete successfully.
+
+--*/
+
+{
+ ULONG i;
+ BOOLEAN completionStatus = TRUE;
+
+ //
+ // Issue Request
+ //
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->OperationCode,
+ DeviceExtension->MailBox.OperationCode);
+
+ ScsiPortWriteRegisterUlong(&DeviceExtension->PmailBox->PhysicalAddress,
+ DeviceExtension->MailBox.PhysicalAddress);
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DMC960_SUBMIT_COMMAND);
+
+ //
+ // Poll for completion.
+ //
+
+ for (i = 0; i < TimeOutValue; i++) {
+
+ if (ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell) &
+ DMC960_INTERRUPT_VALID) {
+
+ //
+ // Update Status field
+ //
+
+ DeviceExtension->MailBox.Status =
+ ScsiPortReadRegisterUshort(&DeviceExtension->PmailBox->Status);
+
+ break;
+
+ } else {
+
+ ScsiPortStallExecution(50);
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == TimeOutValue) {
+ DebugPrint((1,
+ "DAC960: Request: %x timed out\n",
+ DeviceExtension->MailBox.OperationCode));
+
+ completionStatus = FALSE;
+ }
+
+ //
+ // Dismiss interrupt and tell host mailbox is free.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->BaseIoAddress +
+ DMC960_SUBSYSTEM_CONTROL_PORT,
+ (DMC960_DISABLE_INTERRUPT | DMC960_CLEAR_INTERRUPT_ON_READ));
+
+ ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell);
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DMC960_ACKNOWLEDGE_STATUS);
+
+ ScsiPortWritePortUchar(DeviceExtension->BaseIoAddress +
+ DMC960_SUBSYSTEM_CONTROL_PORT,
+ DMC960_DISABLE_INTERRUPT);
+
+ return (completionStatus);
+}
+
+BOOLEAN
+Dac960ScanForNonDiskDevices(
+ IN PDEVICE_EXTENSION DeviceExtension
+)
+
+/*++
+
+Routine Description:
+
+ Issue SCSI_INQUIRY request to all Devices, looking for Non
+ Hard Disk devices and construct the NonDisk device table
+
+Arguments:
+
+ DeviceExtension - Adapter state information.
+
+Return Value:
+
+ TRUE if commands complete successfully.
+
+--*/
+
+{
+ ULONG i;
+ PINQUIRYDATA inquiryData;
+ PDIRECT_CDB directCdb = (PDIRECT_CDB) DeviceExtension->NoncachedExtension;
+ BOOLEAN status;
+ UCHAR channel;
+ UCHAR target;
+
+
+ //
+ // Fill in Direct CDB Table with SCSI_INQUIRY command information
+ //
+
+ directCdb->CommandControl = (DAC960_CONTROL_ENABLE_DISCONNECT |
+ DAC960_CONTROL_TIMEOUT_10_SECS |
+ DAC960_CONTROL_DATA_IN);
+
+ inquiryData = (PINQUIRYDATA) ((PUCHAR) directCdb + sizeof(DIRECT_CDB));
+
+ directCdb->DataBufferAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ ((PUCHAR) inquiryData),
+ &i));
+
+ directCdb->CdbLength = 6;
+ directCdb->RequestSenseLength = SENSE_BUFFER_SIZE;
+
+ ((PCDB) directCdb->Cdb)->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+ ((PCDB) directCdb->Cdb)->CDB6INQUIRY.Reserved1 = 0;
+ ((PCDB) directCdb->Cdb)->CDB6INQUIRY.LogicalUnitNumber = 0;
+ ((PCDB) directCdb->Cdb)->CDB6INQUIRY.PageCode = 0;
+ ((PCDB) directCdb->Cdb)->CDB6INQUIRY.IReserved = 0;
+ ((PCDB) directCdb->Cdb)->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
+ ((PCDB) directCdb->Cdb)->CDB6INQUIRY.Control = 0;
+
+ directCdb->Status = 0;
+ directCdb->Reserved = 0;
+
+ //
+ // Set up Mail Box registers for DIRECT_CDB command information.
+ //
+
+ DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_DIRECT;
+
+ DeviceExtension->MailBox.PhysicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ directCdb,
+ &i));
+
+
+ for (channel = 0; channel < DeviceExtension->NumberOfChannels; channel++)
+ {
+ for (target = 0; target < MAXIMUM_TARGETS_PER_CHANNEL; target++)
+ {
+ //
+ // Initialize this device state to not present/not accessible
+ //
+
+ DeviceExtension->DeviceList[channel][target] =
+ DAC960_DEVICE_NOT_ACCESSIBLE;
+
+#ifdef GAM_SUPPORT
+ //
+ // GAM device will be configured on Channel 0, Target 6
+ //
+
+ if ((channel == 0) && (target == 6)) {
+
+ DeviceExtension->DeviceList[channel][target] = DAC960_DEVICE_ACCESSIBLE;
+
+ continue;
+ }
+#endif
+ //
+ // Fill up DCDB Table
+ //
+
+ directCdb->TargetId = target;
+ directCdb->Channel = channel;
+
+ directCdb->DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+ //
+ // Issue Direct CDB command
+ //
+
+ if (DeviceExtension->AdapterInterfaceType == MicroChannel)
+ status = Dac960McaSendInitTimeRequest(DeviceExtension, 0xFFFFFFFF);
+ else
+ status = Dac960EisaPciSendInitTimeRequest(DeviceExtension, 0xFFFFFFFF);
+
+ if (status) {
+ if (DeviceExtension->MailBox.Status == DAC960_STATUS_GOOD)
+ {
+ if (inquiryData->DeviceType != DIRECT_ACCESS_DEVICE)
+ DeviceExtension->DeviceList[channel][target] =
+ DAC960_DEVICE_ACCESSIBLE;
+ }
+ } else {
+ DebugPrint((0, "DAC960: ScanForNonDisk Devices failed\n"));
+ return (status);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+BOOLEAN
+GetEisaPciConfiguration(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
+)
+
+/*++
+
+Routine Description:
+
+ Issue ENQUIRY and ENQUIRY 2 commands to DAC960 (EISA/PCI).
+
+Arguments:
+
+ DeviceExtension - Adapter state information.
+ ConfigInfo - Port configuration information structure.
+
+Return Value:
+
+ TRUE if commands complete successfully.
+
+--*/
+
+{
+ ULONG i;
+ ULONG physicalAddress;
+ USHORT status;
+
+ //
+ // Maximum number of physical segments is 16.
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS - 1;
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
+
+ //
+ // Indicate that this adapter is a busmaster, supports scatter/gather,
+ // caches data and can do DMA to/from physical addresses above 16MB.
+ //
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->CachesData = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+
+ //
+ // Get noncached extension for enquiry command.
+ //
+
+ DeviceExtension->NoncachedExtension =
+ ScsiPortGetUncachedExtension(DeviceExtension,
+ ConfigInfo,
+ 196);
+
+ //
+ // Get physical address of noncached extension.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ DeviceExtension->NoncachedExtension,
+ &i));
+
+ //
+ // Check to see if adapter is initialized and ready to accept commands.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DAC960_LOCAL_DOORBELL_MAILBOX_FREE);
+
+ //
+ // Wait for controller to clear bit.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ if (!(ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) &
+ DAC960_LOCAL_DOORBELL_MAILBOX_FREE)) {
+ break;
+ }
+
+ ScsiPortStallExecution(5000);
+ }
+
+ //
+ // Claim submission semaphore.
+ //
+
+ if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) {
+
+ //
+ // Clear any bits set in system doorbell and tell controller
+ // that the mailbox is free.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell,
+ ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell));
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DAC960_LOCAL_DOORBELL_MAILBOX_FREE);
+
+ //
+ // Check semaphore again.
+ //
+
+ if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) {
+ return FALSE;
+ }
+ }
+
+ //
+ // Set up Mail Box registers with ENQUIRY 2 command information.
+ //
+
+ DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE2;
+
+ DeviceExtension->MailBox.PhysicalAddress = physicalAddress;
+
+ //
+ // Issue ENQUIRY 2 command
+ //
+
+ if (Dac960EisaPciSendInitTimeRequest(DeviceExtension, 200))
+ {
+ //
+ // Set interrupt mode.
+ //
+
+ if (DeviceExtension->MailBox.Status) {
+
+ //
+ // Enquire 2 failed so assume Level.
+ //
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+
+ } else {
+
+ //
+ // Check enquire 2 data for interrupt mode.
+ //
+
+ if (((PENQUIRE2)DeviceExtension->NoncachedExtension)->InterruptMode) {
+ ConfigInfo->InterruptMode = LevelSensitive;
+ } else {
+ ConfigInfo->InterruptMode = Latched;
+ }
+ }
+ } else {
+ //
+ // ENQUIRY 2 command timed out, so assume Level.
+ //
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+
+ DebugPrint((0, "DAC960: ENQUIRY2 command timed-out\n"));
+ }
+
+ //
+ // Scan For Non Hard Disk devices
+ //
+ //
+
+ Dac960ScanForNonDiskDevices(DeviceExtension);
+
+ //
+ // Set up Mail Box registers with ENQUIRE command information.
+ //
+
+ if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER)
+ DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE_3X;
+ else
+ DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE;
+
+ DeviceExtension->MailBox.PhysicalAddress = physicalAddress;
+
+ //
+ // Issue ENQUIRE command.
+ //
+
+ if (! Dac960EisaPciSendInitTimeRequest(DeviceExtension, 100)) {
+ DebugPrint((0, "DAC960: ENQUIRE command timed-out\n"));
+ }
+
+ //
+ // Ask system to scan target ids 0-15. System drives will appear
+ // at target ids 8-15.
+ //
+
+ ConfigInfo->MaximumNumberOfTargets = 16;
+
+ //
+ // Record maximum number of outstanding requests to the adapter.
+ //
+
+ if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+ DeviceExtension->MaximumAdapterRequests = ((PDAC960_ENQUIRY_3X)
+ DeviceExtension->NoncachedExtension)->NumberOfConcurrentCommands;
+ } else {
+ DeviceExtension->MaximumAdapterRequests = ((PDAC960_ENQUIRY)
+ DeviceExtension->NoncachedExtension)->NumberOfConcurrentCommands;
+ }
+
+
+ //
+ // This shameless hack is necessary because this value is coming up
+ // with zero most of time. If I debug it, then it works find, the COD
+ // looks great. I have no idea what's going on here, but for now I will
+ // just account for this anomoly.
+ //
+
+ if (!DeviceExtension->MaximumAdapterRequests) {
+ DebugPrint((0,
+ "Dac960FindAdapter: MaximumAdapterRequests is 0!\n"));
+ DeviceExtension->MaximumAdapterRequests = 0x40;
+ }
+
+ //
+ // Say max commands is 60. This may be necessary to support asynchronous
+ // rebuild etc.
+ //
+
+ DeviceExtension->MaximumAdapterRequests -= 4;
+
+ //
+ // Indicate that each initiator is at id 7 for each bus.
+ //
+
+ for (i = 0; i < ConfigInfo->NumberOfBuses; i++) {
+ ConfigInfo->InitiatorBusId[i] = 7;
+ }
+
+ return TRUE;
+
+} // end GetEisaPciConfiguration()
+
+BOOLEAN
+GetMcaConfiguration(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
+)
+
+/*++
+
+Routine Description:
+
+ Issue ENQUIRY and ENQUIRY 2 commands to DAC960 (MCA).
+
+Arguments:
+
+ DeviceExtension - Adapter state information.
+ ConfigInfo - Port configuration information structure.
+
+Return Value:
+
+ TRUE if commands complete successfully.
+
+--*/
+
+{
+ ULONG i;
+ ULONG physicalAddress;
+ USHORT status;
+
+ //
+ // Maximum number of physical segments is 16.
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS - 1;
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
+
+ //
+ // Indicate that this adapter is a busmaster, supports scatter/gather,
+ // caches data and can do DMA to/from physical addresses above 16MB.
+ //
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->CachesData = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+
+ //
+ // Get noncached extension for enquiry command.
+ //
+
+ DeviceExtension->NoncachedExtension =
+ ScsiPortGetUncachedExtension(DeviceExtension,
+ ConfigInfo,
+ 128);
+
+ //
+ // Get physical address of noncached extension.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ DeviceExtension->NoncachedExtension,
+ &i));
+ //
+ // Check to see if adapter is initialized and ready to accept commands.
+ //
+
+ ScsiPortWriteRegisterUchar(DeviceExtension->BaseBiosAddress + 0x188d, 2);
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DMC960_ACKNOWLEDGE_STATUS);
+
+ //
+ // Wait for controller to clear bit.
+ //
+
+ for (i = 0; i < 5000; i++) {
+
+ if (!(ScsiPortReadRegisterUchar(DeviceExtension->BaseBiosAddress + 0x188d) & 2)) {
+ break;
+ }
+
+ ScsiPortStallExecution(5000);
+ }
+
+ //
+ // Claim submission semaphore.
+ //
+
+ if (ScsiPortReadRegisterUchar(&DeviceExtension->PmailBox->OperationCode) != 0) {
+
+ //
+ // Clear any bits set in system doorbell.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell, 0);
+
+ //
+ // Check for submission semaphore again.
+ //
+
+ if (ScsiPortReadRegisterUchar(&DeviceExtension->PmailBox->OperationCode) != 0) {
+ DebugPrint((0,"Dac960nt: MCA Adapter initialization failed\n"));
+ return FALSE;
+ }
+ }
+
+
+ //
+ // Set up Mail Box registers with ENQUIRY 2 command information.
+ //
+
+ DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE2;
+
+ DeviceExtension->MailBox.PhysicalAddress = physicalAddress;
+
+ //
+ // Issue ENQUIRY 2 command
+ //
+
+ if (Dac960McaSendInitTimeRequest(DeviceExtension, 200)) {
+
+ //
+ // Set Interrupt Mode
+ //
+
+ if (DeviceExtension->MailBox.Status)
+ {
+ //
+ // Enquire 2 failed so assume Level.
+ //
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+
+ } else {
+
+ //
+ // Check enquire 2 data for interrupt mode.
+ //
+
+ if (((PENQUIRE2)DeviceExtension->NoncachedExtension)->InterruptMode) {
+ ConfigInfo->InterruptMode = LevelSensitive;
+ } else {
+ ConfigInfo->InterruptMode = Latched;
+ }
+ }
+ }
+ else {
+ //
+ // Enquire 2 timed-out, so assume Level.
+ //
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+
+ }
+
+ //
+ // Enquiry 2 is always returning Latched Mode. Needs to be fixed
+ // in Firmware. Till then assume LevelSensitive.
+ //
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+
+ //
+ // Scan For Non Disk devices.
+ //
+
+ Dac960ScanForNonDiskDevices(DeviceExtension);
+
+ //
+ // Set up Mail Box registers with ENQUIRE command information.
+ //
+
+ DeviceExtension->MailBox.OperationCode = DAC960_COMMAND_ENQUIRE;
+
+ DeviceExtension->MailBox.PhysicalAddress = physicalAddress;
+
+ //
+ // Issue ENQUIRE command.
+ //
+
+ if (! Dac960McaSendInitTimeRequest(DeviceExtension, 100)) {
+ DebugPrint((0, "DAC960: Enquire command timed-out\n"));
+ }
+
+ //
+ // Ask system to scan target ids 0-15. System drives will appear
+ // at target ids 8-15.
+ //
+
+ ConfigInfo->MaximumNumberOfTargets = 16;
+
+ //
+ // Record maximum number of outstanding requests to the adapter.
+ //
+
+ DeviceExtension->MaximumAdapterRequests =
+ DeviceExtension->NoncachedExtension->NumberOfConcurrentCommands;
+
+ //
+ // This shameless hack is necessary because this value is coming up
+ // with zero most of time. If I debug it, then it works find, the COD
+ // looks great. I have no idea what's going on here, but for now I will
+ // just account for this anomoly.
+ //
+
+ if (!DeviceExtension->MaximumAdapterRequests) {
+ DebugPrint((0,
+ "Dac960FindAdapter: MaximumAdapterRequests is 0!\n"));
+ DeviceExtension->MaximumAdapterRequests = 0x40;
+ }
+
+ //
+ // Say max commands is 60. This may be necessary to support asynchronous
+ // rebuild etc.
+ //
+
+ DeviceExtension->MaximumAdapterRequests -= 4;
+
+ //
+ // Indicate that each initiator is at id 7 for each bus.
+ //
+
+ for (i = 0; i < ConfigInfo->NumberOfBuses; i++) {
+ ConfigInfo->InitiatorBusId[i] = 7;
+ }
+
+ return TRUE;
+
+} // end GetMcaConfiguration()
+
+ULONG
+Dac960EisaFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+)
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - EISA slot number.
+ BusInformation - Not used.
+ ArgumentString - Not used.
+ ConfigInfo - Data shared between system and driver describing an adapter.
+ Again - Indicates that driver wishes to be called again to continue
+ search for adapters.
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_REGISTERS eisaRegisters;
+ ULONG eisaSlotNumber;
+ ULONG eisaId;
+ PUCHAR baseAddress;
+ UCHAR interruptLevel;
+ UCHAR biosAddress;
+ BOOLEAN found=FALSE;
+
+ //
+ // Scan EISA bus for DAC960 adapters.
+ //
+
+ for (eisaSlotNumber = *(PULONG)Context + 1;
+ eisaSlotNumber < MAXIMUM_EISA_SLOTS;
+ eisaSlotNumber++) {
+
+ //
+ // Update the slot count to indicate this slot has been checked.
+ //
+
+ (*(PULONG)Context)++;
+
+ //
+ // Get the system address for this card. The card uses I/O space.
+ //
+
+ baseAddress = (PUCHAR)
+ ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ TRUE);
+
+ eisaRegisters =
+ (PEISA_REGISTERS)(baseAddress + 0xC80);
+ deviceExtension->BaseIoAddress = (PUCHAR)eisaRegisters;
+
+ //
+ // Look at EISA id.
+ //
+
+ eisaId = ScsiPortReadPortUlong(&eisaRegisters->EisaId);
+
+ if ((eisaId & 0xF0FFFFFF) == DAC_EISA_ID) {
+ deviceExtension->Slot = (UCHAR) eisaSlotNumber;
+ found = TRUE;
+ break;
+ }
+
+ //
+ // If an adapter was not found unmap address.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension, baseAddress);
+
+ } // end for (eisaSlotNumber ...
+
+ //
+ // If no more adapters were found then indicate search is complete.
+ //
+
+ if (!found) {
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // Set the address of mailbox and doorbell registers.
+ //
+
+ deviceExtension->PmailBox = (PMAILBOX)&eisaRegisters->MailBox.OperationCode;
+ deviceExtension->LocalDoorBell = &eisaRegisters->LocalDoorBell;
+ deviceExtension->SystemDoorBell = &eisaRegisters->SystemDoorBell;
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + 0xC80);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_REGISTERS);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ //
+ // Determine number of SCSI channels supported by this adapter by
+ // looking low byte of EISA ID.
+ //
+
+ switch (eisaId >> 24) {
+
+ case 0x70:
+ ConfigInfo->NumberOfBuses = 5;
+ deviceExtension->NumberOfChannels = 5;
+ break;
+
+ case 0x75:
+ case 0x71:
+ case 0x72:
+ deviceExtension->NumberOfChannels = 3;
+ ConfigInfo->NumberOfBuses = 3;
+ break;
+
+ case 0x76:
+ case 0x73:
+ deviceExtension->NumberOfChannels = 2;
+ ConfigInfo->NumberOfBuses = 2;
+ break;
+
+ case 0x77:
+ case 0x74:
+ default:
+ deviceExtension->NumberOfChannels = 1;
+ ConfigInfo->NumberOfBuses = 1;
+ break;
+ }
+
+ //
+ // Read adapter interrupt level.
+ //
+
+ interruptLevel =
+ ScsiPortReadPortUchar(&eisaRegisters->InterruptLevel) & 0x60;
+
+ switch (interruptLevel) {
+
+ case 0x00:
+ ConfigInfo->BusInterruptLevel = 15;
+ break;
+
+ case 0x20:
+ ConfigInfo->BusInterruptLevel = 11;
+ break;
+
+ case 0x40:
+ ConfigInfo->BusInterruptLevel = 12;
+ break;
+
+ case 0x60:
+ ConfigInfo->BusInterruptLevel = 14;
+ break;
+ }
+
+ //
+ // Read BIOS ROM address.
+ //
+
+ biosAddress = ScsiPortReadPortUchar(&eisaRegisters->BiosAddress);
+
+ //
+ // Check if BIOS enabled.
+ //
+
+ if (biosAddress & DAC960_BIOS_ENABLED) {
+
+ ULONG rangeStart;
+
+ switch (biosAddress & 7) {
+
+ case 0:
+ rangeStart = 0xC0000;
+ break;
+ case 1:
+ rangeStart = 0xC4000;
+ break;
+ case 2:
+ rangeStart = 0xC8000;
+ break;
+ case 3:
+ rangeStart = 0xCC000;
+ break;
+ case 4:
+ rangeStart = 0xD0000;
+ break;
+ case 5:
+ rangeStart = 0xD4000;
+ break;
+ case 6:
+ rangeStart = 0xD8000;
+ break;
+ case 7:
+ rangeStart = 0xDC000;
+ break;
+ }
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[1].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(rangeStart);
+ (*ConfigInfo->AccessRanges)[1].RangeLength = 0x4000;
+ (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE;
+
+ //
+ // Set BIOS Base Address in Device Extension.
+ //
+
+ deviceExtension->BaseBiosAddress = (PUCHAR) rangeStart;
+ }
+
+ //
+ // Disable DAC960 Interupts.
+ //
+
+ ScsiPortWritePortUchar(&eisaRegisters->InterruptEnable, 0);
+ ScsiPortWritePortUchar(&eisaRegisters->SystemDoorBellEnable, 0);
+
+ //
+ // Set Adapter Interface Type.
+ //
+
+ deviceExtension->AdapterInterfaceType =
+ ConfigInfo->AdapterInterfaceType;
+
+ //
+ // Set Adapter Type
+ //
+
+ deviceExtension->AdapterType = DAC960_OLD_ADAPTER;
+
+ //
+ // Issue ENQUIRY and ENQUIRY 2 commands to get adapter configuration.
+ //
+
+ if (!GetEisaPciConfiguration(deviceExtension,
+ ConfigInfo)) {
+ return SP_INTERNAL_ADAPTER_ERROR;
+ }
+
+ //
+ // Fill in System Resources used by Adapter, in device extension.
+ //
+
+ deviceExtension->SystemIoBusNumber =
+ ConfigInfo->SystemIoBusNumber;
+
+ deviceExtension->BusInterruptLevel =
+ ConfigInfo->BusInterruptLevel;
+
+ deviceExtension->InterruptMode = ConfigInfo->InterruptMode;
+
+
+ //
+ // Enable interrupts. For the local doorbell, enable interrupts to host
+ // when a command has been submitted and when a completion has been
+ // processed. For the system doorbell, enable only an interrupt when a
+ // command is completed by the host. Note: I am noticing that when I get
+ // a completion interrupt, not only is the bit set that indicates a command
+ // is complete, but the bit that indicates that the submission channel is
+ // free is also set. If I don't clear both bits, the interrupt won't go
+ // away. (MGLASS)
+ //
+
+ ScsiPortWritePortUchar(&eisaRegisters->InterruptEnable, 1);
+ ScsiPortWritePortUchar(&eisaRegisters->SystemDoorBellEnable, 1);
+
+ DebugPrint((0,
+ "DAC960: Active request array address %x\n",
+ deviceExtension->ActiveRequests));
+
+ //
+ // Tell system to keep on searching.
+ //
+
+ *Again = TRUE;
+
+ deviceExtension->NextRequest = TRUE;
+
+ return SP_RETURN_FOUND;
+
+} // end Dac960EisaFindAdapter()
+
+ULONG
+Dac960PciFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+)
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - DAC960 PCI Adapter Type.
+ BusInformation - Bus Specific Information.
+ ArgumentString - Not used.
+ ConfigInfo - Data shared between system and driver describing an adapter.
+ Again - Indicates that driver wishes to be called again to continue
+ search for adapters.
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PCI_COMMON_CONFIG pciConfig;
+ ULONG rc, i;
+ ULONG address;
+ USHORT commandRegister;
+ BOOLEAN disableDac960MemorySpaceAccess = FALSE;
+
+ //
+ // Patch for DAC960 PCU3 - System does not reboot after shutdown.
+ //
+
+ for (i = 0; i < ConfigInfo->NumberOfAccessRanges; i++) {
+ if ((*ConfigInfo->AccessRanges)[i].RangeInMemory &&
+ (*ConfigInfo->AccessRanges)[i].RangeLength != 0) {
+
+ address = ScsiPortConvertPhysicalAddressToUlong(
+ (*ConfigInfo->AccessRanges)[i].RangeStart);
+
+ if (address >= 0xFFFC0000) {
+ disableDac960MemorySpaceAccess = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (disableDac960MemorySpaceAccess) {
+ //
+ // Check for Bus Specific information passed in from system.
+ //
+
+ if (BusInformation != (PVOID) NULL) {
+ //
+ // Get Command Register value from PCI Config Space
+ //
+
+ commandRegister = ((PPCI_COMMON_CONFIG) BusInformation)->Command;
+ }
+ else {
+ //
+ // Get PCI Config Space information for DAC960 Pci Controller
+ //
+
+ rc = ScsiPortGetBusData(deviceExtension,
+ PCIConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ (ULONG) ConfigInfo->SlotNumber,
+ (PVOID) &pciConfig,
+ sizeof(PCI_COMMON_CONFIG));
+
+ if (rc == 0 || rc == 2) {
+ DebugPrint((0, "Error: 0x%x, Getting PCI Config Space information for DAC960 Pci Controller\n"));
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+ else {
+ //
+ // Get Command Register value from PCI config space
+ //
+
+ commandRegister = pciConfig.Command;
+ }
+ }
+
+ //
+ // Check if Memory Space Access Bit is enabled in Command Register
+ //
+
+ if (commandRegister & PCI_ENABLE_MEMORY_SPACE) {
+ //
+ // Disable Memory Space Access for DAC960 Pci Controller
+ //
+
+ commandRegister &= ~PCI_ENABLE_MEMORY_SPACE;
+
+ //
+ // Set Command Register value in DAC960 Pci Config Space
+ //
+
+ rc = ScsiPortSetBusDataByOffset(deviceExtension,
+ PCIConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ (ULONG) ConfigInfo->SlotNumber,
+ (PVOID) &commandRegister,
+ 0x04, // Command Register Offset
+ 2); // 2 Bytes
+
+ if (rc != 2) {
+ DebugPrint((0, "Error: 0x%x, Setting Command Register Value in DAC960 Pci Config Space"));
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+ }
+ }
+
+ //
+ // Check for configuration information passed in from system.
+ //
+
+ if ((*ConfigInfo->AccessRanges)[0].RangeLength == 0) {
+
+ DebugPrint((1,
+ "Dac960nt: No configuration information\n"));
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // Get the system address for this card. The card uses I/O space.
+ //
+
+ deviceExtension->BaseIoAddress =
+ ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ (*ConfigInfo->AccessRanges)[0].RangeStart,
+ sizeof(PCI_REGISTERS),
+ TRUE);
+
+ //
+ // Set up register pointers.
+ //
+
+ deviceExtension->PmailBox = (PMAILBOX)deviceExtension->BaseIoAddress;
+ deviceExtension->LocalDoorBell = deviceExtension->BaseIoAddress + 0x40;
+ deviceExtension->SystemDoorBell = deviceExtension->BaseIoAddress + 0x41;
+
+ //
+ // Set number of channels.
+ //
+
+ deviceExtension->NumberOfChannels = 3;
+ ConfigInfo->NumberOfBuses = 3;
+
+ //
+ // Disable Interrupts from DAC960P board.
+ //
+
+ ScsiPortWritePortUchar(deviceExtension->SystemDoorBell + 2, 0);
+
+ //
+ // Set Adapter Interface Type.
+ //
+
+ deviceExtension->AdapterInterfaceType =
+ ConfigInfo->AdapterInterfaceType;
+
+ //
+ // Set Adapter Type
+ //
+
+ deviceExtension->AdapterType = *(PULONG)Context;
+
+ //
+ // Issue ENQUIRY and ENQUIRY 2 commands to get adapter configuration.
+ //
+
+ if (!GetEisaPciConfiguration(deviceExtension,
+ ConfigInfo)) {
+ return SP_INTERNAL_ADAPTER_ERROR;
+ }
+
+ //
+ // Fill in System Resources used by Adapter, in device extension.
+ //
+
+ deviceExtension->SystemIoBusNumber =
+ ConfigInfo->SystemIoBusNumber;
+
+ deviceExtension->BusInterruptLevel =
+ ConfigInfo->BusInterruptLevel;
+
+ //
+ // DAC960P FW 2.0 returns Interrupt Mode as 'Latched'.
+ // Assume 'Level Sensitive' till it is fixed in Firmware.
+ //
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+
+ deviceExtension->InterruptMode = ConfigInfo->InterruptMode;
+
+
+ deviceExtension->BaseBiosAddress = 0;
+
+ deviceExtension->Slot = 0;
+
+ //
+ // Enable completion interrupts.
+ //
+
+ ScsiPortWritePortUchar(deviceExtension->SystemDoorBell + 2, 1);
+
+ //
+ // Tell system to keep on searching.
+ //
+
+ *Again = TRUE;
+
+ deviceExtension->NextRequest = TRUE;
+
+ return SP_RETURN_FOUND;
+
+} // end Dac960PciFindAdapter()
+
+ULONG
+Dac960McaFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+)
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - MCA slot number.
+ BusInformation - Not used.
+ ArgumentString - Not used.
+ ConfigInfo - Data shared between system and driver describing an adapter.
+ Again - Indicates that driver wishes to be called again to continue
+ search for adapters.
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG baseBiosAddress;
+ ULONG baseIoAddress;
+ ULONG mcaSlotNumber;
+ LONG i;
+ BOOLEAN found=FALSE;
+
+ //
+ // Scan MCA bus for DMC960 adapters.
+ //
+
+
+ for (mcaSlotNumber = *(PULONG)Context;
+ mcaSlotNumber < MAXIMUM_MCA_SLOTS;
+ mcaSlotNumber++) {
+
+ //
+ // Update the slot count to indicate this slot has been checked.
+ //
+
+ (*(PULONG)Context)++;
+
+ //
+ // Get POS data for this slot.
+ //
+
+ i = ScsiPortGetBusData (deviceExtension,
+ Pos,
+ 0,
+ mcaSlotNumber,
+ &deviceExtension->PosData,
+ sizeof( POS_DATA )
+ );
+
+ //
+ // If less than the requested amount of data is returned, then
+ // insure that this adapter is ignored.
+ //
+
+ if ( i < (sizeof( POS_DATA ))) {
+ continue;
+ }
+
+ if (deviceExtension->PosData.AdapterId == MAGPIE_ADAPTER_ID ||
+ deviceExtension->PosData.AdapterId == HUMMINGBIRD_ADAPTER_ID ||
+ deviceExtension->PosData.AdapterId == PASSPLAY_ADAPTER_ID) {
+
+ deviceExtension->Slot = (UCHAR) mcaSlotNumber;
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // Set adapter base I/O address.
+ //
+
+ i = (deviceExtension->PosData.OptionData4 >> 3) & 0x07;
+
+ baseIoAddress = 0x1c00 + ((i * 2) << 12);
+
+ //
+ // Set adapter base Bios address.
+ //
+
+ i = (deviceExtension->PosData.OptionData1 >> 2) & 0x0f;
+
+ baseBiosAddress = 0xc0000 + ((i * 2) << 12);
+
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(baseIoAddress);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(MCA_REGISTERS);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ (*ConfigInfo->AccessRanges)[1].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(baseBiosAddress);
+ (*ConfigInfo->AccessRanges)[1].RangeLength = 0x2000;
+ (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE;
+
+
+ deviceExtension->BaseBiosAddress =
+ ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(baseBiosAddress),
+ 0x2000,
+ FALSE);
+
+ deviceExtension->BaseIoAddress =
+ ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(baseIoAddress),
+ sizeof(MCA_REGISTERS),
+ TRUE);
+
+ //
+ // Set up register pointers.
+ //
+
+ deviceExtension->PmailBox = (PMAILBOX)(deviceExtension->BaseBiosAddress +
+ 0x1890);
+
+ //
+ // DMC960 Attention Port is equivalent to EISA/PCI Local Door Bell register.
+ //
+
+ deviceExtension->LocalDoorBell = deviceExtension->BaseIoAddress +
+ DMC960_ATTENTION_PORT;
+
+ //
+ // DMC960 Command Status Busy Port is equivalent to EISA/PCI System DoorBell
+ // register.
+ //
+
+ deviceExtension->SystemDoorBell = deviceExtension->BaseIoAddress +
+ DMC960_COMMAND_STATUS_BUSY_PORT;
+
+ //
+ // Set configuration information
+ //
+
+ switch(((deviceExtension->PosData.OptionData1 >> 6) & 0x03)) {
+
+ case 0x00:
+ ConfigInfo->BusInterruptLevel = 14;
+ break;
+
+ case 0x01:
+ ConfigInfo->BusInterruptLevel = 12;
+ break;
+
+ case 0x02:
+ ConfigInfo->BusInterruptLevel = 11;
+ break;
+
+ case 0x03:
+ ConfigInfo->BusInterruptLevel = 10;
+ break;
+
+ }
+
+ ConfigInfo->NumberOfBuses = 2;
+
+ //
+ // Disable DMC960 Interrupts.
+ //
+
+ ScsiPortWritePortUchar(deviceExtension->BaseIoAddress +
+ DMC960_SUBSYSTEM_CONTROL_PORT,
+ DMC960_DISABLE_INTERRUPT);
+ //
+ // Set Adapter Interface Type.
+ //
+
+ deviceExtension->AdapterInterfaceType = ConfigInfo->AdapterInterfaceType;
+ deviceExtension->NumberOfChannels = ConfigInfo->NumberOfBuses;
+
+ //
+ // Set Adapter Type
+ //
+
+ deviceExtension->AdapterType = DAC960_OLD_ADAPTER;
+
+ //
+ // Issue ENQUIRY and ENQUIRY2 commands to get adapter configuration.
+ //
+
+ if(!GetMcaConfiguration(deviceExtension,
+ ConfigInfo)) {
+ return SP_INTERNAL_ADAPTER_ERROR;
+ }
+
+ //
+ // Fill in System Resources used by Adapter, in device extension.
+ //
+
+ deviceExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
+
+ deviceExtension->BusInterruptLevel = ConfigInfo->BusInterruptLevel;
+
+ deviceExtension->InterruptMode = ConfigInfo->InterruptMode;
+
+
+ //
+ // Enable DMC960 Interrupts.
+ //
+
+ ScsiPortWritePortUchar(deviceExtension->BaseIoAddress +
+ DMC960_SUBSYSTEM_CONTROL_PORT,
+ DMC960_ENABLE_INTERRUPT);
+
+
+ *Again = TRUE;
+
+ deviceExtension->NextRequest = TRUE;
+
+ return SP_RETURN_FOUND;
+
+} // end Dac960McaFindAdapter()
+
+BOOLEAN
+Dac960Initialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ HwDeviceExtension;
+
+ return(TRUE);
+
+} // end Dac960Initialize()
+
+BOOLEAN
+BuildScatterGather(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ OUT PULONG PhysicalAddress,
+ OUT PULONG DescriptorCount
+)
+
+/*++
+
+Routine Description:
+
+ Build scatter/gather list.
+
+Arguments:
+
+ DeviceExtension - Adapter state
+ SRB - System request
+
+Return Value:
+
+ TRUE if scatter/gather command should be used.
+ FALSE if no scatter/gather is necessary.
+
+--*/
+
+{
+ PSG_DESCRIPTOR sgList;
+ ULONG descriptorNumber;
+ ULONG bytesLeft;
+ PUCHAR dataPointer;
+ ULONG length;
+
+ //
+ // Get data pointer, byte count and index to scatter/gather list.
+ //
+
+ sgList = (PSG_DESCRIPTOR)Srb->SrbExtension;
+ descriptorNumber = 0;
+ bytesLeft = Srb->DataTransferLength;
+ dataPointer = Srb->DataBuffer;
+
+ //
+ // Build the scatter/gather list.
+ //
+
+ while (bytesLeft) {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ sgList[descriptorNumber].Address =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ //
+ // Complete SG descriptor.
+ //
+
+ sgList[descriptorNumber].Length = length;
+
+ //
+ // Update pointers and counters.
+ //
+
+ bytesLeft -= length;
+ dataPointer += length;
+ descriptorNumber++;
+ }
+
+ //
+ // Return descriptior count.
+ //
+
+ *DescriptorCount = descriptorNumber;
+
+ //
+ // Check if number of scatter/gather descriptors is greater than 1.
+ //
+
+ if (descriptorNumber > 1) {
+
+ //
+ // Calculate physical address of the scatter/gather list.
+ //
+
+ *PhysicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ sgList,
+ &length));
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Calculate physical address of the data buffer.
+ //
+
+ *PhysicalAddress = sgList[0].Address;
+ return FALSE;
+ }
+
+} // BuildScatterGather()
+
+BOOLEAN
+BuildScatterGatherExtended(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ OUT PULONG PhysicalAddress,
+ OUT PULONG DescriptorCount
+)
+
+/*++
+
+Routine Description:
+
+ Build scatter/gather list using extended format supported in Fw 3.x.
+
+Arguments:
+
+ DeviceExtension - Adapter state
+ SRB - System request
+
+Return Value:
+
+ TRUE if scatter/gather command should be used.
+ FALSE if no scatter/gather is necessary.
+
+--*/
+
+{
+ PSG_DESCRIPTOR sgList;
+ ULONG descriptorNumber;
+ ULONG bytesLeft;
+ PUCHAR dataPointer;
+ ULONG length;
+ ULONG i;
+ PSG_DESCRIPTOR sgElem;
+
+ //
+ // Get data pointer, byte count and index to scatter/gather list.
+ //
+
+ sgList = (PSG_DESCRIPTOR)Srb->SrbExtension;
+ descriptorNumber = 1;
+ bytesLeft = Srb->DataTransferLength;
+ dataPointer = Srb->DataBuffer;
+
+ //
+ // Build the scatter/gather list.
+ //
+
+ while (bytesLeft) {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ sgList[descriptorNumber].Address =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ //
+ // Complete SG descriptor.
+ //
+
+ sgList[descriptorNumber].Length = length;
+
+ //
+ // Update pointers and counters.
+ //
+
+ bytesLeft -= length;
+ dataPointer += length;
+ descriptorNumber++;
+ }
+
+ //
+ // Return descriptior count.
+ //
+
+ *DescriptorCount = --descriptorNumber;
+
+ //
+ // Check if number of scatter/gather descriptors is greater than 1.
+ //
+
+ if (descriptorNumber > 1) {
+
+ //
+ // Calculate physical address of the scatter/gather list.
+ //
+
+ *PhysicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ sgList,
+ &length));
+
+ //
+ // Store count of data blocks in SG list 0th element.
+ //
+
+ sgList[0].Address = (USHORT)
+ (((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb |
+ (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8));
+
+ sgList[0].Length = 0;
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Calculate physical address of the data buffer.
+ //
+
+ *PhysicalAddress = sgList[1].Address;
+ return FALSE;
+ }
+
+} // BuildScatterGatherExtended()
+
+BOOLEAN
+IsAdapterReady(
+ IN PDEVICE_EXTENSION DeviceExtension
+)
+
+/*++
+
+Routine Description:
+
+ Determine if Adapter is ready to accept new request.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+
+Return Value:
+
+ TRUE if adapter can accept new request.
+ FALSE if host adapter is busy
+
+--*/
+{
+ ULONG i;
+
+ //
+ // Claim submission semaphore.
+ //
+
+ if(DeviceExtension->AdapterInterfaceType == MicroChannel) {
+
+ for (i=0; i<100; i++) {
+
+ if (ScsiPortReadRegisterUchar(&DeviceExtension->PmailBox->OperationCode)) {
+ ScsiPortStallExecution(5);
+ } else {
+ break;
+ }
+ }
+ }
+ else {
+
+ for (i=0; i<100; i++) {
+
+ if (ScsiPortReadPortUchar(DeviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) {
+ ScsiPortStallExecution(5);
+ } else {
+ break;
+ }
+ }
+ }
+
+ //
+ // Check for timeout.
+ //
+
+ if (i == 100) {
+
+ DebugPrint((1,
+ "DAC960: Timeout waiting for submission channel\n"));
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+VOID
+SendRequest(
+ IN PDEVICE_EXTENSION DeviceExtension
+)
+
+/*++
+
+Routine Description:
+
+ submit request to DAC960.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PMAILBOX mailBox = (PMAILBOX) &DeviceExtension->MailBox;
+ PEXTENDED_MAILBOX extendedMailBox;
+
+ if(DeviceExtension->AdapterInterfaceType == MicroChannel) {
+
+ //
+ // Write scatter/gather descriptor count to controller.
+ //
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->ScatterGatherCount,
+ mailBox->ScatterGatherCount);
+ //
+ // Write physical address to controller.
+ //
+
+ ScsiPortWriteRegisterUlong(&DeviceExtension->PmailBox->PhysicalAddress,
+ mailBox->PhysicalAddress);
+
+ //
+ // Write starting block number to controller.
+ //
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->BlockNumber[0],
+ mailBox->BlockNumber[0]);
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->BlockNumber[1],
+ mailBox->BlockNumber[1]);
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->BlockNumber[2],
+ mailBox->BlockNumber[2]);
+
+ //
+ // Write block count to controller (bits 0-13)
+ // and msb block number (bits 14-15).
+ //
+
+ ScsiPortWriteRegisterUshort(&DeviceExtension->PmailBox->BlockCount,
+ mailBox->BlockCount);
+
+ //
+ // Write command to controller.
+ //
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->OperationCode,
+ mailBox->OperationCode);
+
+ //
+ // Write request id to controller.
+ //
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->CommandIdSubmit,
+ mailBox->CommandIdSubmit),
+
+ //
+ // Write drive number to controller.
+ //
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->DriveNumber,
+ mailBox->DriveNumber);
+
+ //
+ // Ring host submission doorbell.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DMC960_SUBMIT_COMMAND);
+ }
+ else {
+
+ //
+ // Write scatter/gather descriptor count to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->ScatterGatherCount,
+ mailBox->ScatterGatherCount);
+
+ //
+ // Write physical address to controller.
+ //
+
+ ScsiPortWritePortUlong(&DeviceExtension->PmailBox->PhysicalAddress,
+ mailBox->PhysicalAddress);
+
+ //
+ // Write starting block number to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->BlockNumber[0],
+ mailBox->BlockNumber[0]);
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->BlockNumber[1],
+ mailBox->BlockNumber[1]);
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->BlockNumber[2],
+ mailBox->BlockNumber[2]);
+
+ //
+ // Write block count to controller (bits 0-13)
+ // and msb block number (bits 14-15).
+ //
+
+ ScsiPortWritePortUshort(&DeviceExtension->PmailBox->BlockCount,
+ mailBox->BlockCount);
+
+ //
+ // Write command to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->OperationCode,
+ mailBox->OperationCode);
+
+ //
+ // Write request id to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->CommandIdSubmit,
+ mailBox->CommandIdSubmit);
+
+ //
+ // Write drive number to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->DriveNumber,
+ mailBox->DriveNumber);
+
+ //
+ // Ring host submission doorbell.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DAC960_LOCAL_DOORBELL_SUBMIT_BUSY);
+ }
+} // end SendRequest()
+
+BOOLEAN
+SubmitRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ Build and submit request to DAC960.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+ SRB - System request.
+
+Return Value:
+
+ TRUE if command was started
+ FALSE if host adapter is busy
+
+--*/
+
+{
+ ULONG descriptorNumber;
+ ULONG physicalAddress;
+ UCHAR command;
+ UCHAR busyCurrentIndex;
+
+ //
+ // Determine if adapter can accept new request.
+ //
+
+ if(!IsAdapterReady(DeviceExtension))
+ return FALSE;
+
+ //
+ // Check that next slot is vacant.
+ //
+
+ if (DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) {
+
+ //
+ // Collision occurred.
+ //
+
+ busyCurrentIndex = DeviceExtension->CurrentIndex++;
+
+ do {
+ if (! DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) {
+ break;
+ }
+ } while (++DeviceExtension->CurrentIndex != busyCurrentIndex) ;
+
+ if (DeviceExtension->CurrentIndex == busyCurrentIndex) {
+
+ //
+ // We should never encounter this condition.
+ //
+
+ DebugPrint((1,
+ "DAC960: SubmitRequest-Collision in active request array\n"));
+ return FALSE;
+ }
+ }
+
+ //
+ // Determine command.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ command = DAC960_COMMAND_READ;
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ command = DAC960_COMMAND_WRITE;
+
+ } else if ((Srb->Function == SRB_FUNCTION_FLUSH) || (Srb->Function == SRB_FUNCTION_SHUTDOWN)) {
+
+ command = DAC960_COMMAND_FLUSH;
+ goto commonSubmit;
+
+ } else {
+
+ //
+ // Log this as illegal request.
+ //
+
+ ScsiPortLogError(DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SRB_STATUS_INVALID_REQUEST,
+ 1 << 8);
+
+ return FALSE;
+ }
+
+ if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+
+ command += DAC960_COMMAND_EXTENDED;
+
+ //
+ // Build scatter/gather list if memory is not physically contiguous.
+ //
+
+ if (BuildScatterGatherExtended(DeviceExtension,
+ Srb,
+ &physicalAddress,
+ &descriptorNumber)) {
+
+ //
+ // OR in scatter/gather bit.
+ //
+
+ command |= DAC960_COMMAND_SG;
+
+ //
+ // Write scatter/gather descriptor count in Mailbox.
+ //
+
+ ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockCount =
+ (USHORT) descriptorNumber;
+ }
+ else {
+ //
+ // Write block count to controller
+ //
+
+ ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockCount =
+ (USHORT) (((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb |
+ (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8));
+ }
+
+ //
+ // Write physical address in Mailbox.
+ //
+
+ ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->PhysicalAddress =
+ physicalAddress;
+
+ //
+ // Write starting block number in Mailbox.
+ //
+
+ ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockNumber[0] =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3;
+
+ ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockNumber[1] =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2;
+
+ ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockNumber[2] =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1;
+
+ ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->BlockNumber[3] =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0;
+
+ //
+ // Write drive number to controller.
+ //
+
+ ((PEXTENDED_MAILBOX) &DeviceExtension->MailBox)->DriveNumber = (UCHAR)
+ ((Srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (Srb->Lun << 3));
+ }
+ else {
+
+ //
+ // Build scatter/gather list if memory is not physically contiguous.
+ //
+
+ if (BuildScatterGather(DeviceExtension,
+ Srb,
+ &physicalAddress,
+ &descriptorNumber)) {
+
+ //
+ // OR in scatter/gather bit.
+ //
+
+ command |= DAC960_COMMAND_SG;
+
+ //
+ // Write scatter/gather descriptor count in Mailbox.
+ //
+
+ DeviceExtension->MailBox.ScatterGatherCount =
+ (UCHAR)descriptorNumber;
+ }
+
+ //
+ // Write physical address in Mailbox.
+ //
+
+ DeviceExtension->MailBox.PhysicalAddress = physicalAddress;
+
+ //
+ // Write starting block number in Mailbox.
+ //
+
+ DeviceExtension->MailBox.BlockNumber[0] =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3;
+
+ DeviceExtension->MailBox.BlockNumber[1] =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2;
+
+ DeviceExtension->MailBox.BlockNumber[2] =
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1;
+
+ //
+ // Write block count to controller (bits 0-13)
+ // and msb block number (bits 14-15).
+ //
+
+ DeviceExtension->MailBox.BlockCount = (USHORT)
+ (((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb |
+ ((((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb & 0x3F) << 8) |
+ ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 14);
+
+ //
+ // Write drive number to controller.
+ //
+
+ DeviceExtension->MailBox.DriveNumber = (UCHAR)
+ ((Srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (Srb->Lun << 3));
+ }
+
+commonSubmit:
+
+ //
+ // Write command to controller.
+ //
+
+ DeviceExtension->MailBox.OperationCode = command;
+
+ //
+ // Write request id to controller.
+ //
+
+ DeviceExtension->MailBox.CommandIdSubmit =
+ DeviceExtension->CurrentIndex;
+
+ //
+ // Start writing mailbox to controller.
+ //
+
+ SendRequest(DeviceExtension);
+
+ return TRUE;
+
+} // SubmitRequest()
+
+VOID
+SendCdbDirect(
+ IN PDEVICE_EXTENSION DeviceExtension
+)
+
+/*++
+
+Routine Description:
+
+ Send CDB directly to device - DAC960.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMAILBOX mailBox = &DeviceExtension->MailBox;
+
+ if(DeviceExtension->AdapterInterfaceType == MicroChannel) {
+
+ //
+ // Write Scatter/Gather Count to controller.
+ // For Fw Ver < 3.x, scatter/gather count goes to register C
+ // For Fw Ver >= 3.x, scattre/gather count goes to register 2
+ //
+
+ if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+ ScsiPortWriteRegisterUshort(&DeviceExtension->PmailBox->BlockCount,
+ mailBox->BlockCount);
+ }
+ else {
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->ScatterGatherCount,
+ mailBox->ScatterGatherCount);
+ }
+
+ //
+ // Write physical address to controller.
+ //
+
+ ScsiPortWriteRegisterUlong(&DeviceExtension->PmailBox->PhysicalAddress,
+ mailBox->PhysicalAddress);
+
+ //
+ // Write command to controller.
+ //
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->OperationCode,
+ mailBox->OperationCode);
+
+ //
+ // Write request id to controller.
+ //
+
+ ScsiPortWriteRegisterUchar(&DeviceExtension->PmailBox->CommandIdSubmit,
+ mailBox->CommandIdSubmit);
+
+ //
+ // Ring host submission doorbell.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DMC960_SUBMIT_COMMAND);
+ }
+ else {
+
+ //
+ // Write Scatter/Gather Count to controller.
+ // For Fw Ver < 3.x, scatter/gather count goes to register C
+ // For Fw Ver >= 3.x, scattre/gather count goes to register 2
+ //
+
+ if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+ ScsiPortWritePortUshort(&DeviceExtension->PmailBox->BlockCount,
+ mailBox->BlockCount);
+ }
+ else {
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->ScatterGatherCount,
+ mailBox->ScatterGatherCount);
+ }
+
+ //
+ // Write physical address to controller.
+ //
+
+ ScsiPortWritePortUlong(&DeviceExtension->PmailBox->PhysicalAddress,
+ mailBox->PhysicalAddress);
+
+ //
+ // Write command to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->OperationCode,
+ mailBox->OperationCode);
+
+ //
+ // Write request id to controller.
+ //
+
+ ScsiPortWritePortUchar(&DeviceExtension->PmailBox->CommandIdSubmit,
+ mailBox->CommandIdSubmit);
+
+ //
+ // Ring host submission doorbell.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DAC960_LOCAL_DOORBELL_SUBMIT_BUSY);
+ }
+
+} // SendCdbDirect()
+
+
+BOOLEAN
+SubmitCdbDirect(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ Build direct CDB and send directly to device - DAC960.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+ SRB - System request.
+
+Return Value:
+
+ TRUE if command was started
+ FALSE if host adapter is busy
+
+--*/
+{
+ ULONG physicalAddress;
+ PDIRECT_CDB directCdb;
+ UCHAR command;
+ ULONG descriptorNumber;
+ ULONG i;
+ UCHAR busyCurrentIndex;
+
+ //
+ // Determine if adapter is ready to accept new request.
+ //
+
+ if(!IsAdapterReady(DeviceExtension)) {
+ return FALSE;
+ }
+
+ //
+ // Check that next slot is vacant.
+ //
+
+ if (DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) {
+
+ //
+ // Collision occurred.
+ //
+
+ busyCurrentIndex = DeviceExtension->CurrentIndex++;
+
+ do {
+ if (! DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) {
+ break;
+ }
+ } while (++DeviceExtension->CurrentIndex != busyCurrentIndex) ;
+
+ if (DeviceExtension->CurrentIndex == busyCurrentIndex) {
+
+ //
+ // We should never encounter this condition.
+ //
+
+ DebugPrint((1,
+ "DAC960: SubmitCdbDirect-Collision in active request array\n"));
+ return FALSE;
+ }
+ }
+
+ //
+ // Set command code.
+ //
+
+ command = DAC960_COMMAND_DIRECT;
+
+ //
+ // Build scatter/gather list if memory is not physically contiguous.
+ //
+
+ if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+
+ if (BuildScatterGatherExtended(DeviceExtension,
+ Srb,
+ &physicalAddress,
+ &descriptorNumber)) {
+ //
+ // OR in scatter/gather bit.
+ //
+
+ command |= DAC960_COMMAND_SG;
+
+ //
+ // Write scatter/gather descriptor count in mailbox.
+ // For Fw Ver >= 3.x, scatter/gather count goes to reg 2
+ //
+
+ DeviceExtension->MailBox.BlockCount =
+ (USHORT)descriptorNumber;
+ }
+ }
+ else {
+ if (BuildScatterGather(DeviceExtension,
+ Srb,
+ &physicalAddress,
+ &descriptorNumber)) {
+
+ //
+ // OR in scatter/gather bit.
+ //
+
+ command |= DAC960_COMMAND_SG;
+
+ //
+ // Write scatter/gather descriptor count in mailbox.
+ //
+
+ DeviceExtension->MailBox.ScatterGatherCount =
+ (UCHAR)descriptorNumber;
+ }
+ }
+
+ //
+ // Get address of data buffer offset after the scatter/gather list.
+ //
+
+ directCdb =
+ (PDIRECT_CDB)((PUCHAR)Srb->SrbExtension +
+ MAXIMUM_SGL_DESCRIPTORS * sizeof(SG_DESCRIPTOR));
+
+ //
+ // Set device SCSI address.
+ //
+
+ directCdb->TargetId = Srb->TargetId;
+ directCdb->Channel = Srb->PathId;
+
+ //
+ // Set Data transfer length.
+ //
+
+ directCdb->DataBufferAddress = physicalAddress;
+ directCdb->DataTransferLength = (USHORT)Srb->DataTransferLength;
+
+ //
+ // Initialize control field indicating disconnect allowed.
+ //
+
+ directCdb->CommandControl = DAC960_CONTROL_ENABLE_DISCONNECT;
+
+ //
+ // Set data direction bit and allow disconnects.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ directCdb->CommandControl |=
+ DAC960_CONTROL_DATA_IN;
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+ directCdb->CommandControl |=
+ DAC960_CONTROL_DATA_OUT;
+ }
+
+ //
+ // Copy CDB from SRB.
+ //
+
+ for (i = 0; i < 12; i++) {
+ directCdb->Cdb[i] = ((PUCHAR)Srb->Cdb)[i];
+ }
+
+ //
+ // Set lengths of CDB and request sense buffer.
+ //
+
+ directCdb->CdbLength = Srb->CdbLength;
+ directCdb->RequestSenseLength = Srb->SenseInfoBufferLength;
+
+ //
+ // Get physical address of direct CDB packet.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ directCdb,
+ &i));
+
+ //
+ // Write physical address in mailbox.
+ //
+
+ DeviceExtension->MailBox.PhysicalAddress = physicalAddress;
+
+ //
+ // Write command in mailbox.
+ //
+
+ DeviceExtension->MailBox.OperationCode = command;
+
+ //
+ // Write request id in mailbox.
+ //
+
+ DeviceExtension->MailBox.CommandIdSubmit =
+ DeviceExtension->CurrentIndex;
+
+ //
+ // Start writing Mailbox to controller.
+ //
+
+ SendCdbDirect(DeviceExtension);
+
+ return TRUE;
+
+} // SubmitCdbDirect()
+
+BOOLEAN
+Dac960ResetChannel(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Non Disk device associated with Srb.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ PathId - SCSI channel number.
+
+Return Value:
+
+ TRUE if resets issued to all channels.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ if(!IsAdapterReady(deviceExtension)) {
+
+ DebugPrint((1,
+ "DAC960: Timeout waiting for submission channel %x on reset\n"));
+
+ if(deviceExtension->AdapterInterfaceType == MicroChannel) {
+ //
+ // This is bad news. The DAC960 doesn't have a direct hard reset.
+ // Clear any bits set in system doorbell.
+ //
+
+ ScsiPortWritePortUchar(deviceExtension->SystemDoorBell, 0);
+
+ //
+ // Now check again if submission channel is free.
+ //
+
+ if (ScsiPortReadRegisterUchar(&deviceExtension->PmailBox->OperationCode) != 0) {
+
+ //
+ // Give up.
+ //
+
+ return FALSE;
+ }
+ }
+ else {
+ //
+ // This is bad news. The DAC960 doesn't have a direct hard reset.
+ // Clear any bits set in system doorbell.
+ //
+
+ ScsiPortWritePortUchar(deviceExtension->SystemDoorBell,
+ ScsiPortReadPortUchar(deviceExtension->SystemDoorBell));
+
+ //
+ // Now check again if submission channel is free.
+ //
+
+ if (ScsiPortReadPortUchar(deviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) {
+
+ //
+ // Give up.
+ //
+
+ return FALSE;
+ }
+ }
+ }
+
+ //
+ // Write command in mailbox.
+ //
+
+ deviceExtension->MailBox.OperationCode =
+ DAC960_COMMAND_RESET;
+
+ //
+ // Write channel number in mailbox.
+ //
+
+ deviceExtension->MailBox.BlockCount =
+ (UCHAR)PathId;
+
+
+ //
+ // Indicate Soft reset required.
+ //
+
+ deviceExtension->MailBox.BlockNumber[0] = 0;
+
+
+ deviceExtension->MailBox.CommandIdSubmit =
+ deviceExtension->CurrentIndex;
+
+ //
+ // Start writing mail box to controller.
+ //
+
+ SendRequest(deviceExtension);
+
+ return TRUE;
+}
+
+BOOLEAN
+Dac960ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Dac960 SCSI adapter and SCSI bus.
+ NOTE: Command ID is ignored as this command will be completed
+ before reset interrupt occurs and all active slots are zeroed.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ PathId - not used.
+
+Return Value:
+
+ TRUE if resets issued to all channels.
+
+--*/
+
+{
+
+ //
+ // There is nothing that can be done by Hard/Soft Resetting SCSI channels.
+ // Dac960 FW does not support a mechanism to abort requests. So If we go
+ // ahead and indicate to ScsiPort that all requests are complete then
+ // ScsiPort releases all data buffers and Dac960 DMAs data to data buffers
+ // which have just been released and eventually system panics.
+
+ // I have observed many instances, where Dac960 takes more than 10 seconds
+ // to complete requests, specially during insertion/removal of Hot Spare/
+ // New/Dead drives. Everything is fine with the adapter, just that it takes
+ // more than 10 seconds to scan all SCSI channels. Issusing Hard Reset to
+ // each SCSI channel forces the adapter to re-scan the bus, which would
+ // worsen the situation.
+ //
+
+ // I have chosen not to complete all pending requests in the reset
+ // routine, instead decided to complete the requests as they get completed
+ // by adapter. -(mouli)
+ //
+
+#ifdef ENABLE_DAC960_RESETS
+
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG channelNumber;
+ ULONG i;
+
+ //
+ // Reset each channel on the adapter. This is because a system drive is
+ // potentially a composition of several disks arranged across all of the
+ // channels.
+ //
+
+ for (channelNumber = 0;
+ channelNumber < deviceExtension->NumberOfChannels;
+ channelNumber++) {
+
+ if(!IsAdapterReady(deviceExtension)) {
+
+ DebugPrint((1,
+ "DAC960: Timeout waiting for submission channel %x on reset\n"));
+
+ if(deviceExtension->AdapterInterfaceType == MicroChannel) {
+ //
+ // This is bad news. The DAC960 doesn't have a direct hard reset.
+ // Clear any bits set in system doorbell.
+ //
+
+ ScsiPortWritePortUchar(deviceExtension->SystemDoorBell, 0);
+
+ //
+ // Now check again if submission channel is free.
+ //
+
+ if (ScsiPortReadRegisterUchar(&deviceExtension->PmailBox->OperationCode) != 0) {
+
+ //
+ // Give up.
+ //
+
+ break;
+ }
+ }
+ else {
+ //
+ // This is bad news. The DAC960 doesn't have a direct hard reset.
+ // Clear any bits set in system doorbell.
+ //
+
+ ScsiPortWritePortUchar(deviceExtension->SystemDoorBell,
+ ScsiPortReadPortUchar(deviceExtension->SystemDoorBell));
+
+ //
+ // Now check again if submission channel is free.
+ //
+
+ if (ScsiPortReadPortUchar(deviceExtension->LocalDoorBell) & DAC960_LOCAL_DOORBELL_SUBMIT_BUSY) {
+
+ //
+ // Give up.
+ //
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Write command in mailbox.
+ //
+
+ deviceExtension->MailBox.OperationCode =
+ DAC960_COMMAND_RESET;
+
+ //
+ // Write channel number in mailbox.
+ //
+
+ deviceExtension->MailBox.BlockCount =
+ (UCHAR)channelNumber;
+
+ //
+ // Indicate hard reset required.
+ //
+
+ deviceExtension->MailBox.BlockNumber[0] = 1;
+
+ //
+ // Start writing mail box to controller.
+ //
+
+ SendRequest(deviceExtension);
+ }
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ //
+ // Reset submission queue.
+ //
+
+ deviceExtension->SubmissionQueueHead = NULL;
+ deviceExtension->SubmissionQueueTail = NULL;
+
+ //
+ // Clear active request array.
+ //
+
+ for (i = 0; i < 256; i++) {
+ deviceExtension->ActiveRequests[i] = NULL;
+ }
+
+ //
+ // Indicate no outstanding adapter requests and reset
+ // active request array index.
+ //
+
+ deviceExtension->CurrentAdapterRequests = 0;
+
+#endif
+
+ return TRUE;
+
+} // end Dac960ResetBus()
+
+BOOLEAN
+Dac960StartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to start a request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG i;
+ UCHAR status;
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ if (Srb->TargetId & DAC960_SYSTEM_DRIVE) {
+
+ //
+ // Determine command from CDB operation code.
+ //
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_READ:
+ case SCSIOP_WRITE:
+
+ //
+ // Check if number of outstanding adapter requests
+ // equals or exceeds maximum. If not, submit SRB.
+ //
+
+ if (deviceExtension->CurrentAdapterRequests <
+ deviceExtension->MaximumAdapterRequests) {
+
+ //
+ // Send request to controller.
+ //
+
+ if (SubmitRequest(deviceExtension, Srb)) {
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ } else {
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ break;
+
+ case SCSIOP_INQUIRY:
+
+ //
+ // DAC960 only supports LUN 0.
+ //
+
+ i = (Srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (Srb->Lun << 3);
+
+ if (deviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+ if (i >= ((PDAC960_ENQUIRY_3X)deviceExtension->NoncachedExtension)->NumberOfDrives ||
+ Srb->PathId != 0) {
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+ }
+ else {
+ if (i >= ((PDAC960_ENQUIRY)deviceExtension->NoncachedExtension)->NumberOfDrives ||
+ Srb->PathId != 0) {
+
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+ }
+
+ //
+ // Fill in inquiry buffer.
+ //
+
+ ((PUCHAR)Srb->DataBuffer)[0] = 0;
+ ((PUCHAR)Srb->DataBuffer)[1] = 0;
+ ((PUCHAR)Srb->DataBuffer)[2] = 1;
+ ((PUCHAR)Srb->DataBuffer)[3] = 0;
+ ((PUCHAR)Srb->DataBuffer)[4] = 0x20;
+ ((PUCHAR)Srb->DataBuffer)[5] = 0;
+ ((PUCHAR)Srb->DataBuffer)[6] = 0;
+ ((PUCHAR)Srb->DataBuffer)[7] = 0;
+ ((PUCHAR)Srb->DataBuffer)[8] = 'M';
+ ((PUCHAR)Srb->DataBuffer)[9] = 'Y';
+ ((PUCHAR)Srb->DataBuffer)[10] = 'L';
+ ((PUCHAR)Srb->DataBuffer)[11] = 'E';
+ ((PUCHAR)Srb->DataBuffer)[12] = 'X';
+ ((PUCHAR)Srb->DataBuffer)[13] = ' ';
+ ((PUCHAR)Srb->DataBuffer)[14] = 'D';
+ ((PUCHAR)Srb->DataBuffer)[15] = 'A';
+ ((PUCHAR)Srb->DataBuffer)[16] = 'C';
+ ((PUCHAR)Srb->DataBuffer)[17] = '9';
+ ((PUCHAR)Srb->DataBuffer)[18] = '6';
+ ((PUCHAR)Srb->DataBuffer)[19] = '0';
+
+ for (i = 20; i < Srb->DataTransferLength; i++) {
+ ((PUCHAR)Srb->DataBuffer)[i] = ' ';
+ }
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case SCSIOP_READ_CAPACITY:
+
+ //
+ // Fill in read capacity data.
+ //
+
+ i = (Srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (Srb->Lun << 3);
+
+ if (deviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+
+ REVERSE_BYTES(&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress,
+ &(((PDAC960_ENQUIRY_3X)deviceExtension->NoncachedExtension)->SectorSize[i]));
+ }
+ else {
+ REVERSE_BYTES(&((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress,
+ &(((PDAC960_ENQUIRY)deviceExtension->NoncachedExtension)->SectorSize[i]));
+ }
+
+ ((PUCHAR)Srb->DataBuffer)[4] = 0;
+ ((PUCHAR)Srb->DataBuffer)[5] = 0;
+ ((PUCHAR)Srb->DataBuffer)[6] = 2;
+ ((PUCHAR)Srb->DataBuffer)[7] = 0;
+
+ //
+ // Fall through to common code.
+ //
+
+ case SCSIOP_VERIFY:
+
+ //
+ // Complete this request.
+ //
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ //
+ // Fail this request.
+ //
+
+ DebugPrint((1,
+ "Dac960StartIo: SCSI CDB opcode %x not handled\n",
+ Srb->Cdb[0]));
+
+ status = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ } // end switch (Srb->Cdb[0])
+
+ break;
+
+ } else {
+
+ //
+ // These are passthrough requests. Only accept request to LUN 0.
+ // This is because the DAC960 direct CDB interface does not include
+ // a field for LUN.
+ //
+
+ if ((Srb->Lun != 0) ||
+ (deviceExtension->DeviceList[Srb->PathId][Srb->TargetId] != DAC960_DEVICE_ACCESSIBLE)) {
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+#ifdef GAM_SUPPORT
+
+ if ((Srb->PathId == 0) && (Srb->TargetId == 6)) {
+
+ switch (Srb->Cdb[0]) {
+
+ case SCSIOP_INQUIRY:
+
+ //
+ // Fill in inquiry buffer for the GAM device.
+ //
+
+ ((PUCHAR)Srb->DataBuffer)[0] = 0x03; // Processor device
+ ((PUCHAR)Srb->DataBuffer)[1] = 0;
+ ((PUCHAR)Srb->DataBuffer)[2] = 1;
+ ((PUCHAR)Srb->DataBuffer)[3] = 0;
+ ((PUCHAR)Srb->DataBuffer)[4] = 0x20;
+ ((PUCHAR)Srb->DataBuffer)[5] = 0;
+ ((PUCHAR)Srb->DataBuffer)[6] = 0;
+ ((PUCHAR)Srb->DataBuffer)[7] = 0;
+ ((PUCHAR)Srb->DataBuffer)[8] = 'M';
+ ((PUCHAR)Srb->DataBuffer)[9] = 'Y';
+ ((PUCHAR)Srb->DataBuffer)[10] = 'L';
+ ((PUCHAR)Srb->DataBuffer)[11] = 'E';
+ ((PUCHAR)Srb->DataBuffer)[12] = 'X';
+ ((PUCHAR)Srb->DataBuffer)[13] = ' ';
+ ((PUCHAR)Srb->DataBuffer)[14] = ' ';
+ ((PUCHAR)Srb->DataBuffer)[15] = ' ';
+ ((PUCHAR)Srb->DataBuffer)[16] = 'G';
+ ((PUCHAR)Srb->DataBuffer)[17] = 'A';
+ ((PUCHAR)Srb->DataBuffer)[18] = 'M';
+ ((PUCHAR)Srb->DataBuffer)[19] = ' ';
+ ((PUCHAR)Srb->DataBuffer)[20] = 'D';
+ ((PUCHAR)Srb->DataBuffer)[21] = 'E';
+ ((PUCHAR)Srb->DataBuffer)[22] = 'V';
+ ((PUCHAR)Srb->DataBuffer)[23] = 'I';
+ ((PUCHAR)Srb->DataBuffer)[24] = 'C';
+ ((PUCHAR)Srb->DataBuffer)[25] = 'E';
+
+ for (i = 26; i < Srb->DataTransferLength; i++) {
+ ((PUCHAR)Srb->DataBuffer)[i] = ' ';
+ }
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ default:
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+ }
+
+ break;
+ }
+#endif
+
+ //
+ // Check if number of outstanding adapter requests
+ // equals or exceeds maximum. If not, submit SRB.
+ //
+
+ if (deviceExtension->CurrentAdapterRequests <
+ deviceExtension->MaximumAdapterRequests) {
+
+ //
+ // Send request to controller.
+ //
+
+ if (SubmitCdbDirect(deviceExtension, Srb)) {
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ } else {
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ break;
+ }
+
+ case SRB_FUNCTION_FLUSH:
+ case SRB_FUNCTION_SHUTDOWN:
+
+ //
+ // Issue flush command to controller.
+ //
+
+ if (!SubmitRequest(deviceExtension, Srb)) {
+
+ status = SRB_STATUS_BUSY;
+
+ } else {
+
+ status = SRB_STATUS_PENDING;
+ }
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ //
+ // If the request is for Non-Disk device, do soft reset.
+ //
+
+ if ( !(Srb->TargetId & DAC960_SYSTEM_DRIVE)) {
+
+ //
+ // Issue request to soft reset Non-Disk device.
+ //
+
+ if (Dac960ResetChannel(deviceExtension,
+ Srb->NextSrb->PathId)) {
+
+ //
+ // Set the flag to indicate that we are handling abort
+ // Request, so do not ask for new requests.
+ //
+
+ deviceExtension->NextRequest = FALSE;
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+
+ status = SRB_STATUS_ABORT_FAILED;
+ }
+ }
+ else {
+
+ //
+ // There is nothing the miniport can do, if logical drive
+ // requests are timing out. Resetting the channel does not help.
+ // It only makes the situation worse.
+ //
+
+ //
+ // Indicate that the abort failed.
+ //
+
+ status = SRB_STATUS_ABORT_FAILED;
+ }
+
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ //
+ // There is nothing the miniport can do by issuing Hard Resets on
+ // Dac960 SCSI channels.
+ //
+
+ //
+ // Set the flag to indicate that we are handling Reset request,
+ // so do not ask for new requests.
+ //
+
+ deviceExtension->NextRequest = FALSE;
+
+ status = SRB_STATUS_SUCCESS;
+
+ break;
+
+ case SRB_FUNCTION_IO_CONTROL:
+
+ DebugPrint((0, "DAC960: Ioctl\n"));
+
+ //
+ // Check if number of outstanding adapter requests
+ // equals or exceeds maximum. If not, submit SRB.
+ //
+
+ if (deviceExtension->CurrentAdapterRequests <
+ deviceExtension->MaximumAdapterRequests) {
+
+ PIOCTL_REQ_HEADER ioctlReqHeader =
+ (PIOCTL_REQ_HEADER)Srb->DataBuffer;
+
+ //
+ // Send request to controller.
+ //
+
+ switch (ioctlReqHeader->GenMailBox.Reg0) {
+ case MIOC_ADP_INFO:
+
+ SetupAdapterInfo(deviceExtension, Srb);
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case MIOC_DRIVER_VERSION:
+
+ SetupDriverVersionInfo(deviceExtension, Srb);
+
+ status = SRB_STATUS_SUCCESS;
+ break;
+
+ case DAC960_COMMAND_DIRECT:
+
+ if (SendIoctlCdbDirect(deviceExtension, Srb)) {
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+ ioctlReqHeader->DriverErrorCode =
+ DAC_IOCTL_RESOURCE_ALLOC_FAILURE;
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+
+ default:
+
+ if (SendIoctlDcmdRequest(deviceExtension, Srb)) {
+
+ status = SRB_STATUS_PENDING;
+
+ } else {
+ ioctlReqHeader->DriverErrorCode =
+ DAC_IOCTL_RESOURCE_ALLOC_FAILURE;
+
+ status = SRB_STATUS_SUCCESS;
+ }
+
+ break;
+ }
+
+ } else {
+
+ status = SRB_STATUS_BUSY;
+ }
+
+ break;
+
+ default:
+
+ //
+ // Fail this request.
+ //
+
+ DebugPrint((1,
+ "Dac960StartIo: SRB fucntion %x not handled\n",
+ Srb->Function));
+
+ status = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ } // end switch
+
+ //
+ // Check if this request is complete.
+ //
+
+ if (status == SRB_STATUS_PENDING) {
+
+ //
+ // Record SRB in active request array.
+ //
+
+ deviceExtension->ActiveRequests[deviceExtension->CurrentIndex] = Srb;
+
+ //
+ // Bump the count of outstanding adapter requests.
+ //
+
+ deviceExtension->CurrentAdapterRequests++;
+
+ //
+ // Advance active request index array.
+ //
+
+ deviceExtension->CurrentIndex++;
+
+ } else if (status == SRB_STATUS_BUSY) {
+
+ //
+ // Check that there are outstanding requests to thump
+ // the queue.
+ //
+
+ if (deviceExtension->CurrentAdapterRequests) {
+
+ //
+ // Queue SRB for resubmission.
+ //
+
+ if (!deviceExtension->SubmissionQueueHead) {
+ deviceExtension->SubmissionQueueHead = Srb;
+ deviceExtension->SubmissionQueueTail = Srb;
+ } else {
+ deviceExtension->SubmissionQueueTail->NextSrb = Srb;
+ deviceExtension->SubmissionQueueTail = Srb;
+ }
+
+ status = SRB_STATUS_PENDING;
+ }
+
+ } else {
+
+ //
+ // Notify system of request completion.
+ //
+
+ Srb->SrbStatus = status;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ }
+
+ //
+ // Check if this is a request to a system drive. Indicating
+ // ready for next logical unit request causes the system to
+ // send overlapped requests to this device (tag queuing).
+ //
+ // The DAC960 only supports a single outstanding direct CDB
+ // request per device, so indicate ready for next adapter request.
+ //
+
+ if (deviceExtension->NextRequest) {
+
+ if (Srb->TargetId & DAC960_SYSTEM_DRIVE) {
+
+ //
+ // Indicate ready for next logical unit request.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ } else {
+
+ //
+ // Indicate ready for next adapter request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ }
+ }
+
+ return TRUE;
+
+} // end Dac960StartIo()
+
+BOOLEAN
+Dac960CheckInterrupt(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ OUT PUSHORT Status,
+ OUT PUCHAR Index
+)
+
+/*++
+
+Routine Description:
+
+ This routine reads interrupt register to determine if the adapter is
+ indeed the source of the interrupt, and if so clears interrupt and
+ returns command completion status and command index.
+
+Arguments:
+
+ DeviceExtension - HBA miniport driver's adapter data storage
+ Status - DAC960 Command completion status.
+ Index - DAC960 Command index.
+
+Return Value:
+
+ TRUE if the adapter is interrupting.
+ FALSE if the adapter is not the source of the interrupt.
+
+--*/
+
+{
+
+ if(DeviceExtension->AdapterInterfaceType == MicroChannel) {
+
+ if (ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell) &
+ DMC960_INTERRUPT_VALID) {
+ //
+ // The adapter is indeed the source of the interrupt.
+ // Set 'Clear Interrupt Valid Bit on read' in subsystem
+ // control port.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->BaseIoAddress +
+ DMC960_SUBSYSTEM_CONTROL_PORT,
+ (DMC960_ENABLE_INTERRUPT | DMC960_CLEAR_INTERRUPT_ON_READ));
+
+ //
+ // Read index, status and error of completing command.
+ //
+
+ *Index = ScsiPortReadRegisterUchar(&DeviceExtension->PmailBox->CommandIdComplete);
+ *Status = ScsiPortReadRegisterUshort(&DeviceExtension->PmailBox->Status);
+
+ //
+ // Dismiss interrupt and tell host mailbox is free.
+ //
+
+ ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell);
+
+ //
+ // status accepted acknowledgement.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DMC960_ACKNOWLEDGE_STATUS);
+
+ //
+ // Set 'Not to Clear Interrupt Valid Bit on read' bits in subsystem
+ // control port.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->BaseIoAddress +
+ DMC960_SUBSYSTEM_CONTROL_PORT,
+ DMC960_ENABLE_INTERRUPT);
+ }
+ else {
+ return FALSE;
+ }
+
+ }
+ else {
+
+ //
+ // Check for command complete.
+ //
+
+ if (!(ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell) &
+ DAC960_SYSTEM_DOORBELL_COMMAND_COMPLETE)) {
+ return FALSE;
+ }
+
+ //
+ // Read index, status and error of completing command.
+ //
+
+ *Index = ScsiPortReadPortUchar(&DeviceExtension->PmailBox->CommandIdComplete);
+ *Status = ScsiPortReadPortUshort(&DeviceExtension->PmailBox->Status);
+
+ //
+ // Dismiss interrupt and tell host mailbox is free.
+ //
+
+ ScsiPortWritePortUchar(DeviceExtension->SystemDoorBell,
+ ScsiPortReadPortUchar(DeviceExtension->SystemDoorBell));
+
+ ScsiPortWritePortUchar(DeviceExtension->LocalDoorBell,
+ DAC960_LOCAL_DOORBELL_MAILBOX_FREE);
+
+ //
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+Dac960Interrupt(
+ IN PVOID HwDeviceExtension
+)
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the DAC960 SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if we handled the interrupt
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ PSCSI_REQUEST_BLOCK restartList;
+ USHORT status;
+ UCHAR index;
+
+ //
+ // Determine if the adapter is indeed the source of interrupt.
+ //
+
+ if(! Dac960CheckInterrupt(deviceExtension,
+ &status,
+ &index)) {
+ return FALSE;
+ }
+
+ //
+ // Get SRB.
+ //
+
+ srb = deviceExtension->ActiveRequests[index];
+
+ if (!srb) {
+ DebugPrint((1,
+ "Dac960Interrupt: No active SRB for index %x\n",
+ index));
+ return TRUE;
+ }
+
+ if (status != 0) {
+
+ //
+ // Map DAC960 error to SRB status.
+ //
+
+ switch (status) {
+
+ case DAC960_STATUS_CHECK_CONDITION:
+
+ if (srb->TargetId & DAC960_SYSTEM_DRIVE) {
+
+ //
+ // This request was to a system drive.
+ //
+
+ srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+
+ } else {
+
+ PDIRECT_CDB directCdb;
+ ULONG requestSenseLength;
+ ULONG i;
+
+ //
+ // Get address of direct CDB packet.
+ //
+
+ directCdb =
+ (PDIRECT_CDB)((PUCHAR)srb->SrbExtension +
+ MAXIMUM_SGL_DESCRIPTORS * sizeof(SG_DESCRIPTOR));
+
+ //
+ // This request was a pass-through.
+ // Copy request sense buffer to SRB.
+ //
+
+ requestSenseLength =
+ srb->SenseInfoBufferLength <
+ directCdb->RequestSenseLength ?
+ srb->SenseInfoBufferLength:
+ directCdb->RequestSenseLength;
+
+ for (i = 0;
+ i < requestSenseLength;
+ i++) {
+
+ ((PUCHAR)srb->SenseInfoBuffer)[i] =
+ directCdb->RequestSenseData[i];
+ }
+
+ //
+ // Set statuses to indicate check condition and valid
+ // request sense information.
+ //
+
+ srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
+ srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ }
+
+ break;
+
+ case DAC960_STATUS_BUSY:
+ srb->SrbStatus = SRB_STATUS_BUSY;
+ break;
+
+ case DAC960_STATUS_SELECT_TIMEOUT:
+ case DAC960_STATUS_DEVICE_TIMEOUT:
+ srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case DAC960_STATUS_NOT_IMPLEMENTED:
+ case DAC960_STATUS_BOUNDS_ERROR:
+ srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case DAC960_STATUS_ERROR:
+ if (srb->TargetId & DAC960_SYSTEM_DRIVE)
+ {
+ if(srb->SenseInfoBufferLength)
+ {
+ ULONG i;
+
+ for (i = 0; i < srb->SenseInfoBufferLength; i++)
+ ((PUCHAR)srb->SenseInfoBuffer)[i] = 0;
+
+ ((PSENSE_DATA) srb->SenseInfoBuffer)->ErrorCode = 0x70;
+ ((PSENSE_DATA) srb->SenseInfoBuffer)->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
+
+ if (srb->SrbFlags & SRB_FLAGS_DATA_IN)
+ ((PSENSE_DATA) srb->SenseInfoBuffer)->AdditionalSenseCode = 0x11;
+
+ srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
+
+ DebugPrint((0,
+ "DAC960: System Drive %d, cmd sts = 1, sense info returned\n",
+ ((srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (srb->Lun << 3))));
+
+ }
+ else
+ {
+ DebugPrint((0,
+ "DAC960: System Drive %d, cmd sts = 1, sense info length 0\n",
+ ((srb->TargetId & ~DAC960_SYSTEM_DRIVE) + (srb->Lun << 3))));
+
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ }
+ }
+ else {
+ DebugPrint((0,
+ "DAC960: SCSI Target Id %x, cmd sts = 1\n",
+ srb->TargetId));
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ }
+
+ break;
+
+ default:
+
+ DebugPrint((1,
+ "DAC960: Unrecognized status %x\n",
+ status));
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+
+ break;
+ }
+
+ //
+ // Check for IOCTL request.
+ //
+
+ if (srb->Function == SRB_FUNCTION_IO_CONTROL) {
+
+ //
+ // Update status in IOCTL header.
+ //
+
+ ((PIOCTL_REQ_HEADER)srb->DataBuffer)->CompletionCode = status;
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ } else {
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ //
+ // Determine if we were to abort this request and a SCSI Bus Reset
+ // occured while this request was being executed. If so, set Srb
+ // status field to reflect the scenerio.
+ //
+
+ if (deviceExtension->NextRequest == FALSE) {
+ srb->SrbStatus = SRB_STATUS_BUS_RESET;
+ }
+
+ //
+ // Complete request.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ //
+ // Indicate this index is free.
+ //
+
+ deviceExtension->ActiveRequests[index] = NULL;
+
+ //
+ // Decrement count of outstanding adapter requests.
+ //
+
+ deviceExtension->CurrentAdapterRequests--;
+
+ //
+ // Check to see if we are done handling SCSI Reset. If so set the
+ // flag to indicate that the new requests can be processed.
+ //
+
+ if (! deviceExtension->CurrentAdapterRequests)
+ deviceExtension->NextRequest = TRUE;
+
+ //
+ // Check to see if a new request can be sent to controller.
+ //
+
+ if (deviceExtension->NextRequest) {
+
+ //
+ // Start requests that timed out waiting for controller to become ready.
+ //
+
+ restartList = deviceExtension->SubmissionQueueHead;
+ deviceExtension->SubmissionQueueHead = NULL;
+
+ while (restartList) {
+
+ //
+ // Get next pending request.
+ //
+
+ srb = restartList;
+
+ //
+ // Check if this request exceeds maximum for this adapter.
+ //
+
+ if (deviceExtension->CurrentAdapterRequests >=
+ deviceExtension->MaximumAdapterRequests) {
+
+ continue;
+ }
+
+ //
+ // Remove request from pending queue.
+ //
+
+ restartList = srb->NextSrb;
+ srb->NextSrb = NULL;
+
+ //
+ // Start request over again.
+ //
+
+ Dac960StartIo(deviceExtension,
+ srb);
+ }
+ }
+
+ return TRUE;
+
+} // end Dac960Interrupt()
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+)
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+ It scans the EISA slots looking for DAC960 host adapters.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ ULONG SlotNumber;
+ ULONG Status1, Status2;
+ UCHAR vendorId[4] = {'1', '0', '6', '9'};
+ UCHAR deviceId[4] = {'0', '0', '0', '1'};
+
+ DebugPrint((1,"\nDAC960 SCSI Miniport Driver\n"));
+
+ // Zero out structure.
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++)
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+
+ // Set size of hwInitializationData.
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ // Set entry points.
+
+ hwInitializationData.HwInitialize = Dac960Initialize;
+ hwInitializationData.HwStartIo = Dac960StartIo;
+ hwInitializationData.HwInterrupt = Dac960Interrupt;
+ hwInitializationData.HwResetBus = Dac960ResetBus;
+
+ //
+ // Show two access ranges - adapter registers and BIOS.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 2;
+
+ //
+ // Indicate will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Indicate auto request sense is supported.
+ //
+
+ hwInitializationData.AutoRequestSense = TRUE;
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
+ hwInitializationData.SrbExtensionSize =
+ sizeof(SG_DESCRIPTOR) * MAXIMUM_SGL_DESCRIPTORS + sizeof(DIRECT_CDB);
+
+#ifndef DAC960_EISA_SUPPORT_ONLY
+
+ //
+ // Set PCI ids.
+ //
+
+ hwInitializationData.DeviceId = &deviceId;
+ hwInitializationData.DeviceIdLength = 4;
+ hwInitializationData.VendorId = &vendorId;
+ hwInitializationData.VendorIdLength = 4;
+
+ //
+ // Attempt PCI initialization for old DAC960 PCI (Device Id - 0001)
+ // Controllers.
+ //
+
+ hwInitializationData.AdapterInterfaceType = PCIBus;
+ hwInitializationData.HwFindAdapter = Dac960PciFindAdapter;
+ SlotNumber = DAC960_OLD_ADAPTER;
+
+ Status1 = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &SlotNumber);
+ //
+ // Attempt PCI initialization for new DAC960 PCI (Device Id - 0002)
+ // Controllers.
+ //
+
+ deviceId[3] = '2';
+ SlotNumber = DAC960_NEW_ADAPTER;
+
+ Status2 = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &SlotNumber);
+
+ Status1 = Status2 < Status1 ? Status2 : Status1;
+
+#endif // DAC960_EISA_SUPPORT_ONLY
+
+ //
+ // Attempt EISA initialization.
+ //
+
+
+ SlotNumber = 0;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.HwFindAdapter = Dac960EisaFindAdapter;
+
+ Status2 = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &SlotNumber);
+
+#ifndef DAC960_EISA_SUPPORT_ONLY
+
+ Status1 = Status2 < Status1 ? Status2 : Status1;
+
+ //
+ // Attempt MCA initialization.
+ //
+
+
+ SlotNumber = 0;
+ hwInitializationData.AdapterInterfaceType = MicroChannel;
+ hwInitializationData.HwFindAdapter = Dac960McaFindAdapter;
+
+ Status2 = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &SlotNumber);
+
+ //
+ // Return the smaller status.
+ //
+
+ return (Status2 < Status1 ? Status2 : Status1);
+
+#else
+
+ return (Status2);
+
+#endif // DAC960_EISA_SUPPORT_ONLY
+
+} // end DriverEntry()
diff --git a/private/ntos/miniport/mylex/dac960/dac960nt.h b/private/ntos/miniport/mylex/dac960/dac960nt.h
new file mode 100644
index 000000000..32a078785
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/dac960nt.h
@@ -0,0 +1,428 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ Dac960Nt.h
+
+Abstract:
+
+ This is header file for the driver for the Mylex 960 family.
+
+Author:
+
+ Mike Glass (mglass)
+
+Environment:
+
+ kernel mode only
+
+Revision History:
+
+--*/
+
+#include "scsi.h"
+
+//
+// SG list size is 17, one additional entry to support Fw 3.x format
+//
+
+#define MAXIMUM_SGL_DESCRIPTORS 0x12
+
+#define MAXIMUM_TRANSFER_LENGTH 0xF000
+#define MAXIMUM_EISA_SLOTS 0x10
+#define MAXIMUM_CHANNELS 0x05
+#define MAXIMUM_TARGETS_PER_CHANNEL 0x07
+
+#define DAC_EISA_ID 0x70009835
+
+#define DAC960_SYSTEM_DRIVE 0x08
+#define DAC960_DEVICE_NOT_ACCESSIBLE 0x00
+#define DAC960_DEVICE_ACCESSIBLE 0x01
+
+//
+// DAC960 mailbox register definition
+//
+
+typedef struct _MAILBOX {
+ UCHAR OperationCode; // zC90
+ UCHAR CommandIdSubmit; // zC91
+ USHORT BlockCount; // zC92
+ UCHAR BlockNumber[3]; // zC94
+ UCHAR DriveNumber; // zC97
+ ULONG PhysicalAddress; // zC98
+ UCHAR ScatterGatherCount; // zC9C
+ UCHAR CommandIdComplete; // zC9D
+ USHORT Status; // zC9E
+} MAILBOX, *PMAILBOX;
+
+//
+// DAC960 mailbox register definition for DAC960 Extended Commands
+//
+
+typedef struct _EXTENDED_MAILBOX {
+ UCHAR OperationCode; // zC90
+ UCHAR CommandIdSubmit; // zC91
+ USHORT BlockCount; // zC92
+ UCHAR BlockNumber[4]; // zC94
+ ULONG PhysicalAddress; // zC98
+ UCHAR DriveNumber; // zC9C
+ UCHAR CommandIdComplete; // zC9D
+ USHORT Status; // zC9E
+} EXTENDED_MAILBOX, *PEXTENDED_MAILBOX;
+
+//
+// DAC960 EISA register definition
+//
+
+typedef struct _EISA_REGISTERS {
+ ULONG EisaId; // zC80
+ UCHAR NotUsed1[4]; // zC84
+ UCHAR GlobalConfiguration; // zC88
+ UCHAR InterruptEnable; // zC89
+ UCHAR NotUsed2[2]; // zC9A
+ UCHAR LocalDoorBellEnable; // zC8C
+ UCHAR LocalDoorBell; // zC8D
+ UCHAR SystemDoorBellEnable; // zC8E
+ UCHAR SystemDoorBell; // zC8F
+ MAILBOX MailBox; // zC90
+ UCHAR Unused4[33]; // zCA0
+ UCHAR BiosAddress; // zCC1
+ UCHAR Unused5; // zCC2
+ UCHAR InterruptLevel; // zCC3
+} EISA_REGISTERS, *PEISA_REGISTERS;
+
+//
+// DAC960 PCI register definition
+//
+
+typedef struct _PCI_REGISTERS {
+ MAILBOX MailBox; // 0x00
+ UCHAR NotUsed1[48]; // 0x10
+ UCHAR LocalDoorBell; // 0x40
+ UCHAR SystemDoorBell; // 0x41
+ UCHAR NotUsed2[1]; // 0x42
+ UCHAR InterruptEnable; // 0x43
+} PCI_REGISTERS, *PPCI_REGISTERS;
+
+
+//
+// Local doorbell definition
+//
+
+#define DAC960_LOCAL_DOORBELL_SUBMIT_BUSY 0x01
+#define DAC960_LOCAL_DOORBELL_MAILBOX_FREE 0x02
+
+//
+// System doorbell definition
+//
+
+#define DAC960_SYSTEM_DOORBELL_COMMAND_COMPLETE 0x01
+#define DAC960_SYSTEM_DOORBELL_SUBMISSION_COMPLETE 0x02
+
+//
+// Command complete status
+//
+
+#define DAC960_STATUS_GOOD 0x0000
+#define DAC960_STATUS_ERROR 0x0001
+#define DAC960_STATUS_NO_DRIVE 0x0002 // system drives
+#define DAC960_STATUS_CHECK_CONDITION 0x0002 // pass-through
+#define DAC960_STATUS_BUSY 0x0008
+#define DAC960_STATUS_SELECT_TIMEOUT 0x000F
+#define DAC960_STATUS_DEVICE_TIMEOUT 0x000E
+#define DAC960_STATUS_NOT_IMPLEMENTED 0x0104
+#define DAC960_STATUS_BOUNDS_ERROR 0x0105
+
+//
+// Command codes
+//
+
+#define DAC960_COMMAND_READ 0x02 // DAC960 Fw Ver < 3.x
+#define DAC960_COMMAND_READ_EXT 0x33 // DAC960 Fw Ver >= 3.x
+#define DAC960_COMMAND_WRITE 0x03 // DAC960 Fw Ver < 3.x
+#define DAC960_COMMAND_WRITE_EXT 0x34 // DAC960 Fw Ver >= 3.x
+#define DAC960_COMMAND_DIRECT 0x04
+#define DAC960_COMMAND_ENQUIRE 0x05 // DAC960 Fw Ver < 3.x
+#define DAC960_COMMAND_ENQUIRE_3X 0x53 // DAC960 Fw Ver >= 3.x
+#define DAC960_COMMAND_FLUSH 0x0A
+#define DAC960_COMMAND_RESET 0x1A
+#define DAC960_COMMAND_ENQUIRE2 0x1C
+#define DAC960_COMMAND_SG 0x80
+#define DAC960_COMMAND_EXTENDED 0x31 // DAC960 Fw Ver >= 3.x
+
+//
+// Define BIOS enabled bit
+//
+
+#define DAC960_BIOS_ENABLED 0x40
+
+//
+// Scatter Gather List
+//
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Address;
+ ULONG Length;
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+typedef struct _SGL {
+ SG_DESCRIPTOR Descriptor[1];
+} SGL, *PSGL;
+
+//
+// Enquiry data, DAC960 Fw < 3.x
+//
+
+typedef struct _DAC960_ENQUIRY {
+ UCHAR NumberOfDrives; // 00
+ UCHAR Unused1[3]; // 01
+ ULONG SectorSize[8]; // 04
+ USHORT NumberOfFlashes; // 36
+ UCHAR StatusFlags; // 38
+ UCHAR FreeStateChangeCount; // 39
+ UCHAR MinorFirmwareRevision; // 40
+ UCHAR MajorFirmwareRevision; // 41
+ UCHAR RebuildFlag; // 42
+ UCHAR NumberOfConcurrentCommands; // 43
+ UCHAR NumberOfOfflineDrives; // 44
+ UCHAR Unused2[3]; // 45
+ UCHAR NumberOfCriticalDrives; // 48
+ UCHAR Unused3[3]; // 49
+ UCHAR NumberOfDeadDisks; // 52
+ UCHAR Unused4; // 53
+ UCHAR NumberOfRebuildingDisks; // 54
+ UCHAR MiscellaneousFlags; // 55
+} DAC960_ENQUIRY, *PDAC960_ENQUIRY;
+
+//
+// Enquiry data, DAC960 Fw >= 3.x
+//
+
+typedef struct _DAC960_ENQUIRY_3X {
+ UCHAR NumberOfDrives; // 00
+ UCHAR Unused1[3]; // 01
+ ULONG SectorSize[32]; // 04
+ USHORT NumberOfFlashes; // 100
+ UCHAR StatusFlags; // 102
+ UCHAR FreeStateChangeCount; // 103
+ UCHAR MinorFirmwareRevision; // 104
+ UCHAR MajorFirmwareRevision; // 105
+ UCHAR RebuildFlag; // 106
+ UCHAR NumberOfConcurrentCommands; // 107
+ UCHAR NumberOfOfflineDrives; // 108
+ UCHAR Unused2[3]; // 109
+ UCHAR NumberOfCriticalDrives; // 112
+ UCHAR Unused3[3]; // 113
+ UCHAR NumberOfDeadDisks; // 116
+ UCHAR Unused4; // 117
+ UCHAR NumberOfRebuildingDisks; // 118
+ UCHAR MiscellaneousFlags; // 119
+} DAC960_ENQUIRY_3X, *PDAC960_ENQUIRY_3X;
+
+
+//
+// Pass-through command
+//
+
+typedef struct _DIRECT_CDB {
+ UCHAR TargetId:4; // 00 (bits 0-3)
+ UCHAR Channel:4; // 00 (bits 4-7)
+ UCHAR CommandControl; // 01
+ USHORT DataTransferLength; // 02
+ ULONG DataBufferAddress; // 04
+ UCHAR CdbLength; // 08
+ UCHAR RequestSenseLength; // 09
+ UCHAR Cdb[12]; // 10
+ UCHAR RequestSenseData[64]; // 22
+ UCHAR Status; // 86
+ UCHAR Reserved; // 87
+} DIRECT_CDB, *PDIRECT_CDB;
+
+//
+// Direct CDB command control bit definitions
+//
+
+#define DAC960_CONTROL_ENABLE_DISCONNECT 0x80
+#define DAC960_CONTROL_DISABLE_REQUEST_SENSE 0x40
+#define DAC960_CONTROL_DATA_IN 0x01
+#define DAC960_CONTROL_DATA_OUT 0x02
+#define DAC960_CONTROL_TIMEOUT_10_SECS 0x10
+#define DAC960_CONTROL_TIMEOUT_60_SECS 0x20
+#define DAC960_CONTROL_TIMEOUT_20_MINUTES 0x30
+
+
+//
+// Enquire 2 structure
+//
+
+typedef struct _ENQUIRE2 {
+ ULONG Reserved1;
+ ULONG EisaId;
+ ULONG InterruptMode:1;
+ ULONG Unused1:31;
+ UCHAR ConfiguredChannels;
+ UCHAR ActualChannels;
+ UCHAR MaximumTargets;
+ UCHAR MaximumTags;
+ UCHAR MaximumSystemDrives;
+ UCHAR MaximumDrivesPerStripe;
+ UCHAR MaximumSpansPerSystemDrive;
+ UCHAR Reserved2[5];
+ ULONG DramSize;
+ UCHAR DramForCache[5];
+ UCHAR SizeOfFlash[3];
+ ULONG SizeOfNvram;
+ ULONG Reserved3[5];
+ USHORT PhysicalSectorSize;
+ USHORT LogicalSectorSize;
+ USHORT MaximumSectorsPerCommand;
+ USHORT BlockingFactor;
+ USHORT CacheLineSize;
+} ENQUIRE2, *PENQUIRE2;
+
+//
+// Device extension
+//
+
+typedef struct _DEVICE_EXTENSION {
+
+ //
+ // DAC960 register base address
+ //
+
+ PUCHAR BaseIoAddress;
+
+ //
+ // Command submission mailbox address
+ //
+
+ PMAILBOX PmailBox;
+
+ //
+ // Mailbox structure space
+ //
+
+ MAILBOX MailBox;
+
+ //
+ // System doorbell address
+ //
+
+ PUCHAR SystemDoorBell;
+
+ //
+ // Local doorbell address
+ //
+
+ PUCHAR LocalDoorBell;
+
+ //
+ // Noncached extension
+ //
+
+ PDAC960_ENQUIRY NoncachedExtension;
+
+ //
+ // Pending request queue
+ //
+
+ PSCSI_REQUEST_BLOCK SubmissionQueueHead;
+ PSCSI_REQUEST_BLOCK SubmissionQueueTail;
+
+ //
+ // Maximum number of outstanding requests per adapter
+ //
+
+ UCHAR MaximumAdapterRequests;
+
+ //
+ // Current number of outstanding requests per adapter
+ //
+
+ UCHAR CurrentAdapterRequests;
+
+ //
+ // Last active request index used
+ //
+
+ UCHAR CurrentIndex;
+
+ //
+ // HBA Slot number.
+ //
+
+ UCHAR Slot;
+
+ //
+ // Number of SCSI channels. (Used for resetting adapter.)
+ //
+
+ ULONG NumberOfChannels;
+
+ //
+ // System I/O Bus Number.
+ //
+
+ ULONG SystemIoBusNumber;
+
+ //
+ // Host Bus Adapter Interface Type.
+ //
+
+ INTERFACE_TYPE AdapterInterfaceType;
+
+ //
+ // Host Bus Adapter Interrupt Level.
+ //
+
+ ULONG BusInterruptLevel;
+
+ //
+ // Adapter Interrupt Mode: Level/Latched.
+ //
+
+ KINTERRUPT_MODE InterruptMode;
+
+ //
+ // BIOS Base Address.
+ //
+
+ PUCHAR BaseBiosAddress;
+
+ //
+ // Adapter Type (DAC960 PCI device id 0x0002 - new adapter, else old)
+ //
+
+ ULONG AdapterType;
+
+ //
+ // Active request pointers
+ //
+
+ PSCSI_REQUEST_BLOCK ActiveRequests[256];
+
+ //
+ // DMC960 POS Registers.
+ //
+
+ POS_DATA PosData;
+
+ //
+ // Flag to indicate, if we should send a new command to controller
+ // and ask for new request. To handle Abort/SCSI Bus Reset Scenerio.
+ //
+
+ BOOLEAN NextRequest;
+
+ //
+ // Contains List Of Physical Devices that are accessible
+ //
+
+ UCHAR DeviceList[MAXIMUM_CHANNELS][MAXIMUM_TARGETS_PER_CHANNEL];
+
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+
diff --git a/private/ntos/miniport/mylex/dac960/dac960nt.rc b/private/ntos/miniport/mylex/dac960/dac960nt.rc
new file mode 100644
index 000000000..14b1baf2a
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/dac960nt.rc
@@ -0,0 +1,38 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "DAC960 SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "DAC960NT.sys"
+#define VER_ORIGINALFILENAME_STR "DAC960NT.sys"
+
+#ifdef VER_COMPANYNAME_STR
+#undef VER_COMPANYNAME_STR
+#endif
+
+#define VER_COMPANYNAME_STR "Mylex Corporation"
+#define VER_LEGALCOPYRIGHT_YEARS "1994-1995"
+#define VER_LEGALCOPYRIGHT_STR "Copyright \251 Mylex Corp. " VER_LEGALCOPYRIGHT_YEARS
+
+#ifdef VER_PRODUCTNAME_STR
+#undef VER_PRODUCTNAME_STR
+#endif
+
+#define VER_PRODUCTNAME_STR "Mylex DAC960 SCSI RAID Controller"
+
+#ifdef VER_PRODUCTVERSION_STR
+#undef VER_PRODUCTVERSION_STR
+#endif
+
+#define VER_PRODUCTVERSION_STR "4.02"
+
+#ifdef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION
+#endif
+
+#define VER_PRODUCTVERSION 4,02,00
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/mylex/dac960/dacioctl.c b/private/ntos/miniport/mylex/dac960/dacioctl.c
new file mode 100644
index 000000000..dcccc92d4
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/dacioctl.c
@@ -0,0 +1,525 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ Dacioctl.c
+
+Abstract:
+
+ This module provides support for DAC960 configuration IOCTls.
+
+Author:
+
+ Mouli (mouli@mylex.com)
+
+Environment:
+
+ kernel mode only
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "Dmc960Nt.h"
+#include "Dac960Nt.h"
+#include "d960api.h"
+
+BOOLEAN
+SubmitRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+BOOLEAN
+SubmitCdbDirect(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+BOOLEAN
+IsAdapterReady(
+ IN PDEVICE_EXTENSION DeviceExtension
+);
+
+VOID
+SendRequest(
+ IN PDEVICE_EXTENSION DeviceExtension
+);
+
+VOID
+SendCdbDirect(
+ IN PDEVICE_EXTENSION DeviceExtension
+);
+
+BOOLEAN
+SendIoctlDcmdRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ Build and submit IOCTL Request-DAC960(Non-DCDB) command to DAC960.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+ SRB - System request.
+
+Return Value:
+
+ TRUE if command was started
+ FALSE if host adapter is busy
+
+--*/
+
+{
+ ULONG physicalAddress;
+ PIOCTL_REQ_HEADER IoctlReqHeader;
+ ULONG i;
+ UCHAR busyCurrentIndex;
+
+ //
+ // Determine if adapter can accept new request.
+ //
+
+ if(!IsAdapterReady(DeviceExtension)) {
+ return FALSE;
+ }
+
+ //
+ // Check that next slot is vacant.
+ //
+
+ if (DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) {
+
+ //
+ // Collision occurred.
+ //
+
+ busyCurrentIndex = DeviceExtension->CurrentIndex++;
+
+ do {
+ if (! DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) {
+ break;
+ }
+ } while (++DeviceExtension->CurrentIndex != busyCurrentIndex) ;
+
+ if (DeviceExtension->CurrentIndex == busyCurrentIndex) {
+
+ //
+ // We should never encounter this condition.
+ //
+
+ DebugPrint((0,
+ "DAC960: SendIoctlDcmdRequest-Collision in active request array\n"));
+
+ return FALSE;
+ }
+ }
+
+ IoctlReqHeader = (PIOCTL_REQ_HEADER) Srb->DataBuffer;
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ ((PUCHAR)Srb->DataBuffer +
+ sizeof(IOCTL_REQ_HEADER)),
+ &i));
+
+ //
+ // The buffer passed in may not be physically contiguous.
+ //
+
+ if (i < Srb->DataTransferLength - sizeof(IOCTL_REQ_HEADER)) {
+ DebugPrint((1,
+ "Dac960: DCMD IOCTL buffer is not contiguous\n"));
+ return FALSE;
+ }
+
+ //
+ // Write physical address in mailbox.
+ //
+
+ DeviceExtension->MailBox.PhysicalAddress = physicalAddress;
+
+ //
+ // Write command in mailbox.
+ //
+
+ DeviceExtension->MailBox.OperationCode =
+ IoctlReqHeader->GenMailBox.Reg0;
+
+ //
+ // Write request in mailbox.
+ //
+
+ DeviceExtension->MailBox.CommandIdSubmit =
+ DeviceExtension->CurrentIndex;
+
+ //
+ // Write Mail Box Registers 2 and 3.
+ //
+
+ DeviceExtension->MailBox.BlockCount = (USHORT)
+ (IoctlReqHeader->GenMailBox.Reg2 |
+ (IoctlReqHeader->GenMailBox.Reg3 << 8));
+
+ //
+ // Write Mail Box Registers 4, 5 and 6.
+ //
+
+ DeviceExtension->MailBox.BlockNumber[0] =
+ IoctlReqHeader->GenMailBox.Reg4;
+
+ DeviceExtension->MailBox.BlockNumber[1] =
+ IoctlReqHeader->GenMailBox.Reg5;
+
+ DeviceExtension->MailBox.BlockNumber[2] =
+ IoctlReqHeader->GenMailBox.Reg6;
+
+ //
+ // Write Mail Box Register 7.
+ //
+
+ DeviceExtension->MailBox.DriveNumber =
+ IoctlReqHeader->GenMailBox.Reg7;
+
+ //
+ // Write Mail Box Register C.
+ //
+
+ DeviceExtension->MailBox.ScatterGatherCount =
+ IoctlReqHeader->GenMailBox.RegC;
+
+ //
+ // Start writing mailbox to controller.
+ //
+
+ SendRequest(DeviceExtension);
+
+ return(TRUE);
+
+} // SendIoctlDcmdRequest()
+
+
+BOOLEAN
+SendIoctlCdbDirect(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ Send IOCTL Request-CDB directly to device.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+ SRB - System request.
+
+Return Value:
+
+ TRUE if command was started
+ FALSE if host adapter is busy
+
+--*/
+
+{
+ ULONG physicalAddress;
+ PDIRECT_CDB directCdb;
+ PIOCTL_REQ_HEADER IoctlReqHeader;
+ ULONG i;
+ UCHAR busyCurrentIndex;
+
+ //
+ // Determine if adapter can accept new request.
+ //
+
+ if(!IsAdapterReady(DeviceExtension)) {
+ return FALSE;
+ }
+
+ //
+ // Check that next slot is vacant.
+ //
+
+ if (DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) {
+
+ //
+ // Collision occurred.
+ //
+
+ busyCurrentIndex = DeviceExtension->CurrentIndex++;
+
+ do {
+ if (! DeviceExtension->ActiveRequests[DeviceExtension->CurrentIndex]) {
+ break;
+ }
+ } while (++DeviceExtension->CurrentIndex != busyCurrentIndex) ;
+
+ if (DeviceExtension->CurrentIndex == busyCurrentIndex) {
+
+ //
+ // We should never encounter this condition.
+ //
+
+ DebugPrint((0,
+ "DAC960: SendIoctlCdbDirect-Collision in active request array\n"));
+
+ return FALSE;
+ }
+ }
+
+ IoctlReqHeader = (PIOCTL_REQ_HEADER) Srb->DataBuffer;
+
+ directCdb =
+ (PDIRECT_CDB)((PUCHAR)Srb->DataBuffer + sizeof(IOCTL_REQ_HEADER));
+
+ //
+ // Get address of data buffer offset.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ ((PUCHAR)Srb->DataBuffer +
+ sizeof(IOCTL_REQ_HEADER) +
+ sizeof(DIRECT_CDB)),
+ &i));
+
+ //
+ // The buffer passed in may not be physically contiguous.
+ //
+
+ if (i < Srb->DataTransferLength -
+ (sizeof(IOCTL_REQ_HEADER) + sizeof(DIRECT_CDB))) {
+ DebugPrint((1,
+ "Dac960: DCDB IOCTL buffer is not contiguous\n"));
+ return FALSE;
+ }
+
+ directCdb->DataBufferAddress = physicalAddress;
+
+ if (directCdb->DataTransferLength == 0) {
+
+ //
+ // mask off data xfer in/out bits
+ //
+
+ directCdb->CommandControl &= ~(DAC960_CONTROL_DATA_IN |
+ DAC960_CONTROL_DATA_OUT);
+ }
+
+ //
+ // Disable Early-status on command bit
+ //
+
+ directCdb->CommandControl &= 0xfb;
+
+ //
+ // Get physical address of direct CDB packet.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ directCdb,
+ &i));
+
+ //
+ // Write physical address in mailbox.
+ //
+
+ DeviceExtension->MailBox.PhysicalAddress = physicalAddress;
+
+ //
+ // Write command in mailbox.
+ //
+
+ DeviceExtension->MailBox.OperationCode =
+ IoctlReqHeader->GenMailBox.Reg0;
+
+ //
+ // Write request id in mailbox.
+ //
+
+ DeviceExtension->MailBox.CommandIdSubmit =
+ DeviceExtension->CurrentIndex;
+
+ //
+ // Start writing mailbox to controller.
+ //
+
+ SendCdbDirect(DeviceExtension);
+
+ return(TRUE);
+
+} // SendIoctlCdbDirect()
+
+VOID
+SetupAdapterInfo(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ Copy Adapter Information to Application Buffer.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+ SRB - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER_INFO AdpInfo;
+
+ AdpInfo = (PADAPTER_INFO)((PUCHAR) Srb->DataBuffer +
+ sizeof(IOCTL_REQ_HEADER));
+
+ //
+ // Fill in Adapter Features Information.
+ //
+
+ if (DeviceExtension->AdapterInterfaceType == MicroChannel) {
+
+ AdpInfo->AdpFeatures.Model = (UCHAR) DeviceExtension->PosData.AdapterId;
+ AdpInfo->AdpFeatures.SubModel = DeviceExtension->PosData.OptionData3;
+ }
+ else {
+
+ AdpInfo->AdpFeatures.Model = 0;
+ AdpInfo->AdpFeatures.SubModel = 0;
+ }
+
+ if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+
+ AdpInfo->AdpFeatures.MaxSysDrv = 32;
+ AdpInfo->AdpFeatures.MaxTgt = 16;
+ }
+ else {
+ AdpInfo->AdpFeatures.MaxSysDrv = 8;
+
+ if (AdpInfo->AdpFeatures.MaxChn == 5) {
+ AdpInfo->AdpFeatures.MaxTgt = 4;
+ }
+ else {
+ AdpInfo->AdpFeatures.MaxTgt = 7;
+ }
+ }
+
+ AdpInfo->AdpFeatures.MaxChn = (UCHAR) DeviceExtension->NumberOfChannels;
+
+ AdpInfo->AdpFeatures.AdapterType = (UCHAR) DeviceExtension->AdapterType;
+ AdpInfo->AdpFeatures.PktFormat = 0;
+
+
+ AdpInfo->AdpFeatures.Reserved1 = 0;
+ AdpInfo->AdpFeatures.Reserved2 = 0;
+ AdpInfo->AdpFeatures.CacheSize = 0;
+ AdpInfo->AdpFeatures.OemCode = 0;
+ AdpInfo->AdpFeatures.Reserved3 = 0;
+
+ //
+ // Fill in the System Resources information.
+ //
+
+ AdpInfo->SysResources.BusInterface =
+ (UCHAR) DeviceExtension->AdapterInterfaceType;
+
+ AdpInfo->SysResources.BusNumber =
+ (UCHAR) DeviceExtension->SystemIoBusNumber;
+
+
+ AdpInfo->SysResources.IrqVector =
+ (UCHAR) DeviceExtension->BusInterruptLevel;
+
+ AdpInfo->SysResources.IrqType =
+ (UCHAR) DeviceExtension->InterruptMode;
+
+
+ AdpInfo->SysResources.Slot = DeviceExtension->Slot;
+ AdpInfo->SysResources.Reserved2 = 0;
+
+ AdpInfo->SysResources.IoAddress = (ULONG) DeviceExtension->BaseIoAddress;
+
+ AdpInfo->SysResources.MemAddress = 0;
+
+ AdpInfo->SysResources.BiosAddress = (ULONG) DeviceExtension->BaseBiosAddress;
+ AdpInfo->SysResources.Reserved3 = 0;
+
+ //
+ // Fill in the Firmware & BIOS version information.
+ //
+
+ if (DeviceExtension->AdapterType == DAC960_NEW_ADAPTER) {
+
+ AdpInfo->VerControl.MinorFirmwareRevision =
+ ((PDAC960_ENQUIRY_3X)DeviceExtension->NoncachedExtension)->MinorFirmwareRevision;
+ }
+ else {
+
+ AdpInfo->VerControl.MajorFirmwareRevision =
+ ((PDAC960_ENQUIRY)DeviceExtension->NoncachedExtension)->MajorFirmwareRevision;
+ }
+
+ AdpInfo->VerControl.MinorBIOSRevision = 0;
+ AdpInfo->VerControl.MajorBIOSRevision = 0;
+ AdpInfo->VerControl.Reserved = 0;
+}
+
+VOID
+SetupDriverVersionInfo(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ Copy Driver Version Information to Application Buffer.
+
+Arguments:
+
+ DeviceExtension - Adapter state.
+ SRB - System request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDRIVER_VERSION driverVersion;
+
+ driverVersion = (PDRIVER_VERSION)((PUCHAR) Srb->DataBuffer +
+ sizeof(IOCTL_REQ_HEADER));
+
+ driverVersion->DriverMajorVersion = (UCHAR) (DRIVER_REVISION >> 8);
+ driverVersion->DriverMinorVersion = (UCHAR) DRIVER_REVISION;
+ driverVersion->Month = (UCHAR) (DRIVER_BUILD_DATE >> 16);
+ driverVersion->Date = (UCHAR) (DRIVER_BUILD_DATE >> 8);
+ driverVersion->Year = (UCHAR) DRIVER_BUILD_DATE;
+
+}
diff --git a/private/ntos/miniport/mylex/dac960/dmc960nt.h b/private/ntos/miniport/mylex/dac960/dmc960nt.h
new file mode 100644
index 000000000..c00f41065
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/dmc960nt.h
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 1994 Mylex Corporation
+
+Module Name:
+
+ dmc960nt.h
+
+Abstract:
+
+ The module defines the structures, defines for DMC960 Adapter.
+
+Author:
+
+ Mouli (mouli@mylex.com)
+
+Environment:
+
+ Kernel mode Only
+
+Revision History:
+
+--*/
+
+
+#define MAXIMUM_MCA_SLOTS 0x08
+
+//
+// DMC960 Adapter IDs
+//
+
+#define MAGPIE_ADAPTER_ID 0x8f6c // Mylex Version
+#define HUMMINGBIRD_ADAPTER_ID 0x8f82 // Pass Play Option
+#define PASSPLAY_ADAPTER_ID 0x8fbb // Pass Play
+
+//
+// DMC960 Control Registers definitions.
+//
+
+#define DMC960_ATTENTION_PORT 0x04
+#define DMC960_SUBSYSTEM_CONTROL_PORT 0x05
+#define DMC960_COMMAND_STATUS_BUSY_PORT 0x07
+
+//
+// DMC960 Interrupt Valid bit (Bit 1 in Command Status Busy Port).
+//
+#define DMC960_INTERRUPT_VALID 0x02
+
+//
+// DMC960 Interrupt Control bit definitions (Set in Subsytem Control Port).
+//
+
+#define DMC960_DISABLE_INTERRUPT 0x02
+#define DMC960_ENABLE_INTERRUPT 0x03
+#define DMC960_CLEAR_INTERRUPT_ON_READ 0x40
+
+//
+// DMC960 Command/status Handshaking register values.
+//
+
+#define DMC960_SUBMIT_COMMAND 0xd0
+#define DMC960_ACKNOWLEDGE_STATUS 0xd1
+
+//
+// Define Option Select Register Structures.
+//
+
+typedef struct _POS_DATA {
+ USHORT AdapterId;
+ UCHAR OptionData1;
+ UCHAR OptionData2;
+ UCHAR OptionData3;
+ UCHAR OptionData4;
+} POS_DATA, *PPOS_DATA;
+
+//
+// DAC960 MCA register definition
+//
+
+typedef struct _MCA_REGISTERS {
+ UCHAR NotUsed1[4]; // IoBase + 0x00
+ UCHAR AttentionPort; // IoBase + 0x04
+ UCHAR SubsystemControlPort; // IoBase + 0x05
+ UCHAR NotUsed2; // IoBase + 0x06
+ UCHAR CommandStatusBusyPort; // IoBase + 0x07
+} MCA_REGISTERS, *PMCA_REGISTERS;
+
diff --git a/private/ntos/miniport/mylex/dac960/makefile b/private/ntos/miniport/mylex/dac960/makefile
new file mode 100644
index 000000000..0d61f853d
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/mylex/dac960/raidapi.h b/private/ntos/miniport/mylex/dac960/raidapi.h
new file mode 100644
index 000000000..86261105b
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/raidapi.h
@@ -0,0 +1,277 @@
+/*****************************************************************************
+* *
+* COPYRIGHT (C) Mylex Corporation 1992-1994 *
+* *
+* This software is furnished under a license and may be used and copied *
+* only in accordance with the terms and conditions of such license *
+* and with inclusion of the above copyright notice. This software or nay *
+* other copies thereof may not be provided or otherwise made available to *
+* any other person. No title to and ownership of the software is hereby *
+* transferred. *
+* *
+* The information in this software is subject to change without notices *
+* and should not be construed as a commitment by Mylex Corporation *
+*****************************************************************************/
+
+/****************************************************************************
+* *
+* Name: RAIDAPI.H *
+* *
+* Description: Structure Definitions Used by Driver and Utils *
+* *
+* Envrionment: *
+* *
+* Operating System: Netware 3.x and 4.x,OS/2 2.x,Win NT 3.5,Unixware 2.0 *
+* *
+* --------------- Revision History ------------------------ *
+* *
+* Date Author Change *
+* ---- ----- ------------------------------------- *
+* 11/04/94 Subra.Hegde Added few more BUS Definitions *
+* 01/06/95 Subra.Hegde Reserved1 field in SYS_RESOURCES changed to *
+* Slot. *
+* 05/10/95 Mouli Re-defined DRV_IOCTL structure *
+* Removed IO_MBOX, HBA_MBOX structure defs *
+* 05/18/95 Subra Added DRIVER_VERSION structure *
+****************************************************************************/
+
+#ifndef _RAIDAPI_H
+#define _RAIDAPI_H
+
+
+#ifndef UCHAR
+#define UCHAR unsigned char
+#endif
+
+#ifndef USHORT
+#define USHORT unsigned short
+#endif
+
+#ifndef ULONG
+#define ULONG unsigned long
+#endif
+
+#ifndef VOID
+#define VOID void
+#endif
+
+/*
+ * Adapter Interface Type
+ */
+
+#define AI_INTERNAL 0x00
+#define AI_ISA_BUS 0x01 /* ISA Bus Type */
+#define AI_EISA_BUS 0x02 /* EISA Bus Type */
+#define AI_uCHNL_BUS 0x03 /* MicroChannel Bus Type */
+#define AI_TURBO_BUS 0x04 /* Turbo Channel Bus Type */
+#define AI_PCI_BUS 0x05 /* PCI Bus Type */
+#define AI_VME_BUS 0x06 /* VME Bus Type */
+#define AI_NU_BUS 0x07 /* NuBus Type */
+#define AI_PCMCIA_BUS 0x08 /* PCMCIA Bus Type */
+#define AI_C_BUS 0x09 /* C Bus */
+#define AI_MPI_BUS 0x0A /* MPI Bus */
+#define AI_MPSA_BUS 0x0B /* MPSA Bus */
+#define AI_SCSI2SCSI_BUS 0x0C /* SCSI to SCSI Bus */
+
+/*
+ * Interrupt Type
+ */
+
+#define IRQ_TYPE_EDGE 0x00 /* Irq is Edge Type */
+#define IRQ_TYPE_LEVEL 0x01 /* Irq is Level Type */
+
+/*
+ * definitions to identify new/old DAC960 adapters
+ */
+
+#define DAC960_OLD_ADAPTER 0x00 /* DAC960 with Fw Ver < 3.x */
+#define DAC960_NEW_ADAPTER 0x01 /* DAC960 with Fw Ver >= 3.x */
+
+/*
+ * All structure definitions are packed on 1-byte boundary.
+ */
+
+#pragma pack(1)
+
+/*
+ * Generic Mail Box Registers Structure Format
+ */
+
+typedef struct _HBA_GENERIC_MBOX {
+
+ UCHAR Reg0; /* HBA Mail Box Register 0 */
+ UCHAR Reg1; /* HBA Mail Box Register 1 */
+ UCHAR Reg2; /* HBA Mail Box Register 2 */
+ UCHAR Reg3; /* HBA Mail Box Register 3 */
+ UCHAR Reg4; /* HBA Mail Box Register 4 */
+ UCHAR Reg5; /* HBA Mail Box Register 5 */
+ UCHAR Reg6; /* HBA Mail Box Register 6 */
+ UCHAR Reg7; /* HBA Mail Box Register 7 */
+ UCHAR Reg8; /* HBA Mail Box Register 8 */
+ UCHAR Reg9; /* HBA Mail Box Register 9 */
+ UCHAR RegA; /* HBA Mail Box Register A */
+ UCHAR RegB; /* HBA Mail Box Register B */
+ UCHAR RegC; /* HBA Mail Box Register C */
+ UCHAR RegD; /* HBA Mail Box Register D */
+ UCHAR RegE; /* HBA Mail Box Register E */
+ UCHAR RegF; /* HBA Mail Box Register F */
+
+} HBA_GENERIC_MBOX, *PHBA_GENERIC_MBOX;
+
+/*
+ * Host Bus Adapter Embedded Software Version Control Information
+ */
+
+typedef struct _VERSION_CONTROL {
+
+ UCHAR MinorFirmwareRevision; /* HBA Firmware Minor Version No */
+ UCHAR MajorFirmwareRevision; /* HBA Firmware Major Version No */
+ UCHAR MinorBIOSRevision; /* HBA BIOS Minor Version No */
+ UCHAR MajorBIOSRevision; /* HBA BIOS Major Version No */
+ ULONG Reserved; /* Reserved */
+
+} VERSION_CONTROL, *PVERSION_CONTROL;
+
+/*
+ * System Resources used by Host Bus Adapter
+ */
+
+typedef struct _SYSTEM_RESOURCES {
+
+ UCHAR BusInterface; /* HBA System Bus Interface Type */
+ UCHAR BusNumber; /* System Bus No, HBA is sitting on */
+ UCHAR IrqVector; /* HBA Interrupt Vector No */
+ UCHAR IrqType; /* HBA Irq Type : Edge/Level */
+ UCHAR Slot; /* HBA Slot Number */
+ UCHAR Reserved2; /* Reserved */
+ ULONG IoAddress; /* HBA IO Base Address */
+ /* EISA : 0xzC80 */
+ /* PCI: Read_Config_word(Register 0x10) & 0xff80*/
+ ULONG MemAddress; /* HBA Memory Base Address */
+ ULONG BiosAddress; /* HBA BIOS Address (if enabled) */
+ ULONG Reserved3; /* Reserved */
+
+} SYSTEM_RESOURCES, *PSYSTEM_RESOURCES;
+
+/*
+ * Host Bus Adapter Features
+ */
+
+typedef struct _ADAPTER_FEATURES {
+
+ UCHAR Model; /* HBA Family Model */
+ UCHAR SubModel; /* HBA Sub Model */
+ UCHAR MaxSysDrv; /* Maximum System Drives */
+ UCHAR MaxTgt; /* Maximum Targets per Channel */
+ UCHAR MaxChn; /* Maximum Channels per Adapter */
+ UCHAR Reserved1; /* Reserved */
+ UCHAR Reserved2; /* Reserved */
+ UCHAR AdapterType; /* Controller type(0,1) */
+ UCHAR PktFormat; /* IOCTL packet format(0) */
+ ULONG CacheSize; /* HBA Cache Size In Mega Bytes */
+ ULONG OemCode; /* HBA OEM Identifier Code */
+ ULONG Reserved3; /* Reserved */
+
+} ADAPTER_FEATURES, *PADAPTER_FEATUTRES;
+
+typedef struct _ADAPTER_INFO {
+
+ UCHAR AdapterIndex; /* Logical Adapter Index */
+ ADAPTER_FEATURES AdpFeatures;
+ SYSTEM_RESOURCES SysResources;
+ VERSION_CONTROL VerControl;
+ UCHAR Reserved[12];
+
+} ADAPTER_INFO, *PADAPTER_INFO;
+
+/*
+ * Driver IOCTL Support Stuff.
+ */
+
+/*
+ * The DAC960 controller specific IOCTL commands
+ */
+#define DACDIO 0x44414300 /* DAC960 ioctls */
+#define DAC_DIODCDB (DACDIO|2) /* DAC960 direct cdb */
+#define DAC_DIODCMD (DACDIO|3) /* DAC960 direct cmd */
+
+/*
+ * DAC960 driver signature
+ */
+
+#define DRV_SIGNATURE 0x4D594C58 /* MYLX */
+
+/*
+ * Data Direction control defs
+ */
+
+#define DATA_XFER_NONE 0
+#define DATA_XFER_IN 1
+#define DATA_XFER_OUT 2
+
+/*
+ * Driver IoControl Request Format
+ */
+
+typedef struct _DRV_IOCTL {
+
+ ULONG Signature; /* Driver would look for this */
+ ULONG ControlCode; /* IOCTL Control Code */
+ VOID *IoctlBuffer; /* IOCTL Specific input buffer */
+ ULONG IoctlBufferLen; /* ioctl buffer length */
+ VOID *DataBufferAddr; /* User Virtual Buffer Address */
+ ULONG DataBufferLen; /* Data Buffer Length */
+ ULONG Reserved1; /* Reserved for future use */
+ ULONG Reserved2; /* Reserved for future use */
+ UCHAR AdapterIndex; /* Logical Adapter Index */
+ UCHAR DataDirection; /* Bytes xferred out by driver */
+ UCHAR TimeOutValue; /* Time out value - not used */
+ UCHAR Reserved3; /* Reserved for future use */
+ USHORT DriverErrorCode; /* Driver Returned Error Code */
+ USHORT CompletionCode; /* DAC960 command completion code */
+
+} DRV_IOCTL, *PDRV_IOCTL;
+
+/*
+ * Driver Version Number format - all fields in hex
+ */
+typedef struct _DRIVER_VERSION{
+
+ UCHAR DriverMajorVersion; /* Major version number */
+ UCHAR DriverMinorVersion; /* Minor version number */
+ UCHAR Month; /* Driver Build - Month */
+ UCHAR Date; /* Driver Build - Date */
+ UCHAR Year; /* Driver Build - Year */
+ UCHAR Reserved[3];
+
+} DRIVER_VERSION,*PDRIVER_VERSION;
+
+#pragma pack()
+
+/*
+ * IOCTL Codes for internal driver requests
+ */
+
+#define MIOC_ADP_INFO 0xA0 /* Get Adapter information */
+#define MIOC_DRIVER_VERSION 0xA1 /* Get Driver Version */
+
+/*
+ * Error Codes returned by Driver
+ */
+
+#define NOMORE_ADAPTERS 0x0001 /* wiil be made obsolete */
+#define INVALID_COMMANDCODE 0x0201 /* will be made obsolete */
+#define INVALID_ARGUMENT 0x0202 /* wiil be made obsolete */
+
+/*
+ * Driver Error Code Values
+ */
+
+#define DAC_IOCTL_SUCCESS 0x0000
+#define DAC_IOCTL_INVALID_ADAPTER_NUMBER 0x0001
+#define DAC_IOCTL_INVALID_ARGUMENT 0x0002
+#define DAC_IOCTL_UNSUPPORTED_REQUEST 0x0003
+#define DAC_IOCTL_RESOURCE_ALLOC_FAILURE 0x0004
+#define DAC_IOCTL_INTERNAL_XFER_ERROR 0x0005
+
+#endif
diff --git a/private/ntos/miniport/mylex/dac960/raiddefs.h b/private/ntos/miniport/mylex/dac960/raiddefs.h
new file mode 100644
index 000000000..a370d2f08
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/raiddefs.h
@@ -0,0 +1,34 @@
+
+#ifndef __RAIDDEFS_H
+#define __RAIDDEFS_H
+
+/*****************************************************************************
+* *
+* COPYRIGHT (C) Mylex Corporation 1992-1994 *
+* *
+* This software is furnished under a license and may be used and copied *
+* only in accordance with the terms and conditions of such license *
+* and with inclusion of the above copyright notice. This software or nay *
+* other copies thereof may not be provided or otherwise made available to *
+* any other person. No title to and ownership of the software is hereby *
+* transferred. *
+* *
+* The information in this software is subject to change without notices *
+* and should not be construed as a commitment by Mylex Corporation *
+*****************************************************************************/
+
+/*
+ Definitions used by Utilities and by the driver for Utility support
+*/
+
+/* IOCTL Codes For Driver */
+
+#define MIOC_ADP_INFO 0xA0 /* Get Interface Type */
+
+/* Error Codes returned by Driver */
+
+#define NOMORE_ADAPTERS 0x01
+#define INVALID_COMMANDCODE 0x201
+#define INVALID_ARGUMENT 0x202
+
+#endif
diff --git a/private/ntos/miniport/mylex/dac960/sources b/private/ntos/miniport/mylex/dac960/sources
new file mode 100644
index 000000000..ea9591b71
--- /dev/null
+++ b/private/ntos/miniport/mylex/dac960/sources
@@ -0,0 +1,13 @@
+TARGETNAME=dac960nt
+TARGETPATH=obj
+TARGETTYPE=DRIVER
+
+#INCLUDES=$(BASEDIR)\src\scsi\inc
+INCLUDES=..\..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=dac960nt.c dac960nt.rc dacioctl.c
+
+C_DEFINES=-DGAM_SUPPORT
+
diff --git a/private/ntos/miniport/mylex/dce376/dce376nt.c b/private/ntos/miniport/mylex/dce376/dce376nt.c
new file mode 100644
index 000000000..e3df65401
--- /dev/null
+++ b/private/ntos/miniport/mylex/dce376/dce376nt.c
@@ -0,0 +1,2741 @@
+/*
+** Mylex DCE376 miniport driver for Windows NT
+**
+** File: dce376nt.c
+** The driver
+**
+** (c) Copyright 1992 Deutsch-Amerikanische Freundschaft, Inc.
+** Written by Jochen Roth
+**
+** Contacts:
+** Paresh @MYLEX (510)796-6050 x222 (hardware, firmware)
+** Jochen @DAF (415)826-7934 (software)
+**
+**
+** Look for $$$ marking code that might need some attention
+**
+**
+** In ARCMODE, the NoncachedExtension sometimes is physically non-
+** continuous. Throwing out the error check on that solves the
+** problem in a very straight forward way.
+**
+**
+** Tape requests will not work if the data buffer is not
+** physically continuous. (We need MapBuffers=TRUE to update
+** the SenseInfo->Information field)
+**
+**
+** When multi-command firmware becomes available for the DCE, some
+** of the buffers in the NoncachedExtension need to be allocated
+** per request slot!
+**
+**
+** Ask Paresh for list of DCE error status codes to provide an error
+** mapping from DCE error codes to SCSI target status / request sense
+** keys.
+**
+**
+** Bus/adapter Reset for DCE ? nope!
+**
+** IOCTL only if MapBuffers is possible !
+**
+**
+*/
+
+
+#include "miniport.h"
+
+#include "dce376nt.h"
+
+
+
+#define MYPRINT 0
+#define NODEVICESCAN 0
+#define REPORTSPURIOUS 0 // Somewhat overwhelming in ARCMODE
+#define MAXLOGICALADAPTERS 3 // Set to 1: One DCE, disk only
+ // 2: One DCE, disk & scsi
+ // 3: Two DCEs, scsi only on 1st
+
+
+
+//
+// The DCE EISA id and mask
+//
+CONST UCHAR eisa_id[] = DCE_EISA_ID;
+CONST UCHAR eisa_mask[] = DCE_EISA_MASK;
+
+
+
+
+#if MYPRINT
+#define PRINT(f, a, b, c, d) dcehlpPrintf(deviceExtension, f, a, b, c, d)
+#define DELAY(x) ScsiPortStallExecution( (x) * 1000 )
+#else
+#define PRINT(f, a, b, c, d)
+#define DELAY(x)
+#endif
+
+
+
+//
+// Function declarations
+//
+// Functions that start with 'Dce376Nt' are entry points
+// for the OS port driver.
+// Functions that start with 'dcehlp' are helper functions.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+Dce376NtEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+Dce376NtConfiguration(
+ IN PVOID DeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+Dce376NtInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Dce376NtStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+Dce376NtInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Dce376NtResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+
+BOOLEAN
+dcehlpDiskRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+dcehlpScsiRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+dcehlpSendMBOX(
+ IN PUCHAR EisaAddress,
+ IN PDCE_MBOX mbox
+ );
+
+BOOLEAN
+dcehlpTransferMemory(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG HostAddress,
+ IN ULONG AdapterAddress,
+ IN USHORT Count,
+ IN UCHAR Direction
+ );
+
+VOID
+dcehlpCheckTarget(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN UCHAR TargetId
+ );
+
+BOOLEAN
+dcehlpContinueScsiRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+dcehlpContinueDiskRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG index,
+ IN BOOLEAN Start
+ );
+
+BOOLEAN
+dcehlpDiskRequestDone(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG index,
+ IN UCHAR Status
+ );
+
+BOOLEAN
+dcehlpSplitCopy(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN ULONG PhysicalBufferAddress,
+ IN PUCHAR VirtualUserAddress,
+ IN USHORT Count,
+ IN BOOLEAN ToUser
+ );
+
+
+USHORT dcehlpGetM16(PUCHAR p);
+ULONG dcehlpGetM24(PUCHAR p);
+ULONG dcehlpGetM32(PUCHAR p);
+void dcehlpPutM16(PUCHAR p, USHORT s);
+void dcehlpPutM24(PUCHAR p, ULONG l);
+void dcehlpPutM32(PUCHAR p, ULONG l);
+void dcehlpPutI16(PUCHAR p, USHORT s);
+void dcehlpPutI32(PUCHAR p, ULONG l);
+ULONG dcehlpSwapM32(ULONG l);
+
+
+
+#if MYPRINT
+ULONG dcehlpColumn = 0;
+UCHAR dcehlpHex[] = "0123456789ABCDEF";
+VOID dcehlpPutchar(PUSHORT BaseAddr, UCHAR c);
+VOID dcehlpPrintHex(PUSHORT BaseAddr, ULONG v, ULONG len);
+VOID dcehlpPrintf(PHW_DEVICE_EXTENSION deviceExtension,
+ PUCHAR fmt,
+ ULONG a1,
+ ULONG a2,
+ ULONG a3,
+ ULONG a4);
+#endif
+
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ return Dce376NtEntry(DriverObject, Argument2);
+
+} // end DriverEntry()
+
+
+
+
+
+ULONG
+Dce376NtEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from DriverEntry if this driver is installable
+ or directly from the system if the driver is built into the kernel.
+ It scans the EISA slots looking for DCE376 host adapters.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ SCANCONTEXT context;
+
+
+
+ //
+ // Zero out structure.
+ //
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++)
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+
+ context.Slot = 0;
+ context.AdapterCount = 0;
+
+ //
+ // Set size of hwInitializationData.
+ //
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+ hwInitializationData.HwInitialize = Dce376NtInitialize;
+ hwInitializationData.HwFindAdapter = Dce376NtConfiguration;
+ hwInitializationData.HwStartIo = Dce376NtStartIo;
+ hwInitializationData.HwInterrupt = Dce376NtInterrupt;
+ hwInitializationData.HwResetBus = Dce376NtResetBus;
+
+ //
+ // Set number of access ranges and bus type.
+ //
+#if MYPRINT
+ hwInitializationData.NumberOfAccessRanges = 2;
+#else
+ hwInitializationData.NumberOfAccessRanges = 1;
+#endif
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ //
+ // Indicate no buffer mapping.
+ // Indicate will need physical addresses.
+ //
+ hwInitializationData.MapBuffers = FALSE;
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Indicate auto request sense is supported.
+ //
+ hwInitializationData.AutoRequestSense = TRUE;
+ hwInitializationData.MultipleRequestPerLu = FALSE;
+
+ //
+ // Specify size of extensions.
+ //
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ //
+ // Ask for SRB extensions.
+ // $$$ Note: If we set SrbExtensionSize=0 NT crashes!
+ //
+ hwInitializationData.SrbExtensionSize = 4; // this works
+
+
+ return(ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &context));
+
+} // end Dce376NtEntry()
+
+
+
+
+ULONG
+Dce376NtConfiguration(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo - Configuration information structure describing HBA
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG eisaSlotNumber;
+ PUCHAR eisaAddress;
+ PSCANCONTEXT context = Context;
+ ULONG i;
+ ULONG length;
+ UCHAR abyte;
+ BOOLEAN found=FALSE;
+ BOOLEAN scsiThing=FALSE;
+ ULONG IrqLevel;
+ ULONG RangeStart, RangeLength;
+
+
+ //
+ // Check to see if adapter present in system.
+ //
+ if(context->AdapterCount==1) {
+ //
+ // Found first dce last time, so this is the scsi extension...
+ //
+ eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0),
+ 0x200,
+ TRUE);
+
+ scsiThing = TRUE;
+ eisaSlotNumber = context->Slot;
+ IrqLevel = DCE_SCSI_IRQ;
+ RangeStart = 0x1f0;
+ RangeLength = 8;
+ }
+ else {
+ //
+ // Scan for DCE EISA id
+ //
+ for(eisaSlotNumber=context->Slot + 1; eisaSlotNumber<MAXIMUM_EISA_SLOTS; eisaSlotNumber++) {
+
+ // Update the slot count to indicate this slot has been checked.
+ context->Slot++;
+
+ //
+ // Get the system address for this card.
+ // The card uses I/O space.
+ //
+ eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ TRUE);
+
+ // Look at EISA id
+ for(found=TRUE, i=0; i<EISA_ID_COUNT; i++) {
+ abyte = ScsiPortReadPortUchar(eisaAddress+EISA_ID_START+i);
+ if( ((UCHAR)(abyte & eisa_mask[i])) != eisa_id[i] ) {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if(found) {
+ break;
+ }
+
+ //
+ // If an adapter was not found unmap it.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension, eisaAddress);
+ } // end for (eisaSlotNumber ...
+
+
+ if(!found) {
+ // No adapter was found. Indicate that we are done and there are no
+ // more adapters here.
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ IrqLevel = context->AdapterCount ? DCE_SECONDARY_IRQ : DCE_PRIMARY_IRQ;
+ RangeStart = 0x1000 * eisaSlotNumber;
+ RangeLength = 0x1000;
+
+ } // end if(not next after first dce)
+
+
+
+#if MYPRINT
+ deviceExtension->printAddr =
+ ScsiPortGetDeviceBase(
+ deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress((ULONG)0xb0000),
+ 0x1000,
+ (BOOLEAN) FALSE); // InIoSpace
+
+ PRINT("\nHello, world! ", 0, 0, 0, 0);
+ PRINT("Version: " __DATE__ " " __TIME__ "\n", 0, 0, 0, 0);
+ PRINT(" slot=%b count=%b irq=%b io=%w\n",
+ eisaSlotNumber, context->AdapterCount, IrqLevel, RangeStart);
+
+ if(sizeof(DCE_MBOX)!=16) {
+ PRINT("\n MBOX SIZE FAILURE %b !!!!!!!\n", sizeof(DCE_MBOX), 0,0,0);
+ return(SP_RETURN_ERROR);
+ }
+
+#endif
+
+
+ deviceExtension->AdapterIndex = context->AdapterCount;
+ context->AdapterCount++;
+
+ if(context->AdapterCount < MAXLOGICALADAPTERS)
+ *Again = TRUE;
+ else
+ *Again = FALSE;
+
+
+ //
+ // There is still more to look at.
+ //
+
+
+ // Get the system interrupt vector and IRQL.
+ ConfigInfo->BusInterruptLevel = IrqLevel;
+
+ // Indicate maximum transfer length in bytes.
+ ConfigInfo->MaximumTransferLength = 0x20000;
+
+ // Maximum number of physical segments is 32.
+ ConfigInfo->NumberOfPhysicalBreaks = 17;
+
+ //
+ // Fill in the access array information.
+ //
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(RangeStart);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = RangeLength;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+#if MYPRINT
+ (*ConfigInfo->AccessRanges)[1].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0xb0000);
+ (*ConfigInfo->AccessRanges)[1].RangeLength = 0x2000;
+ (*ConfigInfo->AccessRanges)[1].RangeInMemory = TRUE;
+#endif
+
+
+ // Store host adapter SCSI id
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InitiatorBusId[0] = 7;
+
+ // Bob Rinne: since we say Busmaster & NeedPhysicalAddresses
+ // this is not even being looked at !
+ ConfigInfo->ScatterGather = TRUE;
+
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->CachesData = TRUE;
+ ConfigInfo->AtdiskPrimaryClaimed = scsiThing;
+ ConfigInfo->Dma32BitAddresses = TRUE; // $$$ Find out whether this costs
+
+
+ //
+ // Allocate a Noncached Extension to use for mail boxes.
+ //
+ deviceExtension->NoncachedExtension = ScsiPortGetUncachedExtension(
+ deviceExtension,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ if (deviceExtension->NoncachedExtension == NULL) {
+ // Sorry !
+ PRINT("Could not get uncached extension\n", 0, 0, 0, 0);
+ return(SP_RETURN_ERROR);
+ }
+
+
+
+ //
+ // Convert virtual to physical buffer addresses.
+ //
+ deviceExtension->NoncachedExtension->PhysicalBufferAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension->Buffer,
+ &length));
+ if(length < DCE_THUNK) {
+ PRINT("Noncached size too small %w/%w\n", length, DCE_THUNK, 0, 0);
+//$$$ return(SP_RETURN_ERROR);
+ }
+
+
+ if(scsiThing) {
+
+ //
+ // The SCSI routines need more:
+ //
+
+ deviceExtension->NoncachedExtension->PhysicalScsiReqAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension->ScsiReq,
+ &length));
+ if(length < DCE_SCSIREQLEN) {
+ PRINT("Noncached size dce scsireq too small %w/%w\n", length, DCE_SCSIREQLEN, 0, 0);
+//$$$ return(SP_RETURN_ERROR);
+ }
+
+ deviceExtension->NoncachedExtension->PhysicalReqSenseAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension->ReqSense,
+ &length));
+ if(length < DCE_MAXRQS) {
+ PRINT("Noncached size rqs buffer too small %w/%w\n", length, DCE_MAXRQS, 0, 0);
+//$$$ return(SP_RETURN_ERROR);
+ }
+
+ } // end if(scsiThing)
+
+
+
+ // Store EISA slot base address
+ deviceExtension->EisaAddress = eisaAddress;
+
+ deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0];
+
+ deviceExtension->ShutDown = FALSE;
+
+
+ //
+ // Setup our private control structures
+ //
+ for(i=0; i<8; i++)
+ deviceExtension->DiskDev[i] = 0;
+
+ deviceExtension->PendingSrb = NULL;
+
+ deviceExtension->ActiveCmds = 0;
+ for(i=0; i<DCE_MAX_IOCMDS; i++) {
+ deviceExtension->ActiveSrb[i] = NULL;
+ deviceExtension->ActiveRcb[i].WaitInt = FALSE;
+ }
+
+ deviceExtension->Kicked = FALSE;
+ deviceExtension->ActiveScsiSrb = NULL;
+
+ return SP_RETURN_FOUND;
+
+} // end Dce376NtConfiguration()
+
+
+
+
+BOOLEAN
+Dce376NtInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION NoncachedExtension;
+ PUCHAR EisaAddress;
+ DCE_MBOX mbox;
+ PDCE_DPT dpt;
+ ULONG i, cnt, length, unit, target, cyls, hds, spt;
+ UCHAR dbell, status, errcode;
+
+
+
+ NoncachedExtension = deviceExtension->NoncachedExtension;
+ EisaAddress = deviceExtension->EisaAddress;
+
+ PRINT("Initializing adapter %b ...\n", deviceExtension->AdapterIndex, 0, 0, 0);
+
+
+ if(deviceExtension->AdapterIndex==1) {
+ // scsiThing
+
+#if NODEVICESCAN
+
+ // Preset for disk on scsi(0), all others non-cached
+ deviceExtension->ScsiDevType[0] = 0;
+ deviceExtension->DiskDev[0] = 1;
+ for(i=1; i<7; i++)
+ deviceExtension->DiskDev[i] = 0;
+
+#else
+
+ // Check all devices
+ for(i=0; i<7; i++) {
+ dcehlpCheckTarget(deviceExtension, (UCHAR)i);
+ if(deviceExtension->ScsiDevType[i]==0)
+ // Hard drive
+ deviceExtension->DiskDev[i]=1;
+ }
+ DELAY(1000);
+
+ // Once again after possible bus reset Unit Attention
+ for(i=0; i<7; i++) {
+ dcehlpCheckTarget(deviceExtension, (UCHAR)i);
+ if(deviceExtension->ScsiDevType[i]==0)
+ // Hard drive
+ deviceExtension->DiskDev[i]=1;
+ }
+ DELAY(1000);
+
+#endif
+
+ return(TRUE);
+ }
+
+
+
+ // Disable DCE interrupts
+ PRINT("disable DCE interrupts\n", 0, 0, 0, 0);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB_ENABLE, 0);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_SYSINTCTRL, 0);
+
+
+
+ //
+ // If second DCE, set EOI interrupt vector
+ // AdapterIndex 1 (SCSI) is handled above
+ //
+ if(deviceExtension->AdapterIndex) {
+
+ PRINT("Set IRQ10 ", 0, 0, 0, 0);
+ mbox.eimbox.Command = DCE_EOCIRQ;
+ mbox.eimbox.Reserved1 = 0;
+ mbox.eimbox.Status = 0;
+ mbox.eimbox.IRQSelect = 1;
+ mbox.eimbox.Unused1 = 0;
+ mbox.eimbox.Unused2 = 0;
+ mbox.eimbox.Unused3 = 0;
+
+ dcehlpSendMBOX(EisaAddress, &mbox);
+
+ // Poll the complete bit
+ for(cnt=0; cnt<0x3FFFFFFL; cnt++) {
+ dbell = ScsiPortReadPortUchar(EisaAddress+BMIC_EISA_DB);
+ if(dbell & 1)
+ break;
+ ScsiPortStallExecution(100);
+ }
+
+ ScsiPortStallExecution(500);
+
+ status = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+2);
+ errcode = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+3);
+
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB, dbell);
+
+ PRINT("done db=%b s=%b e=%b\n", dbell, status, errcode, 0);
+ }
+
+
+
+#if NODEVICESCAN
+
+ // Preset for Maxtor 120 MB as target 0
+ PRINT("setting diskdev[0]=%d\n", 0x106 * 0xF * 0x3F, 0, 0, 0);
+ deviceExtension->DiskDev[0] = 1;
+ deviceExtension->Capacity[0] = 0x106 * 0xF * 0x3F;
+
+#else
+
+ // Scan for devices
+ PRINT("scanning for devices... ",0,0,0,0);
+ dpt = NoncachedExtension->DevParms;
+ mbox.dpmbox.PhysAddr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, dpt, &length));
+
+ if(length < sizeof(DCE_DPT)*DPT_NUMENTS) {
+ PRINT("DPT table too small\n", 0, 0, 0, 0);
+ return(FALSE);
+ }
+
+ // Preset end mark in case DCE does not respond
+ dpt[0].DriveID = 0xffff;
+
+ // Setup mailbox
+ mbox.dpmbox.Command = DCE_DEVPARMS;
+ mbox.dpmbox.Reserved1 = 0;
+ mbox.dpmbox.Status = 0;
+ mbox.dpmbox.DriveType = 0;
+ mbox.dpmbox.Reserved2 = 0;
+ mbox.dpmbox.Reserved3 = 0;
+ mbox.dpmbox.Reserved4 = 0;
+
+ dcehlpSendMBOX(EisaAddress, &mbox);
+
+ // Poll the complete bit
+ for(cnt=0; cnt < 0x10000; cnt++) {
+ dbell = ScsiPortReadPortUchar(EisaAddress+BMIC_EISA_DB);
+ if(dbell & 1)
+ break;
+ ScsiPortStallExecution(100);
+ }
+
+ status = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+2);
+ errcode = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+3);
+
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB, dbell);
+
+ PRINT("done db=%b s=%b e=%b\n", dbell, status, errcode, 0);
+
+ for(unit=0; unit<8; unit++) {
+ if((target=dpt[unit].DriveID)==0xffff)
+ break;
+ cyls = (ULONG)dpt[unit].Cylinders;
+ hds = (ULONG)dpt[unit].Heads;
+ spt = (ULONG)dpt[unit].SectorsPerTrack;
+ PRINT("dev %b: %w cyls %b hds %b spt\n",
+ target, cyls, hds, spt);
+ deviceExtension->DiskDev[target] = 1;
+ deviceExtension->Capacity[target] = cyls*hds*spt;
+ }
+
+ DELAY(1000);
+
+#endif
+
+ // Enable DCE interrupts
+ PRINT("enable DCE interrupts\n", 0, 0, 0, 0);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB_ENABLE, 1);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_SYSINTCTRL, BMIC_SIC_ENABLE);
+
+
+ PRINT("Get going!\n", 0, 0, 0, 0);
+
+
+ return(TRUE);
+} // end Dce376NtInitialize()
+
+
+
+
+
+BOOLEAN
+Dce376NtStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to start a request
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ ULONG i = 0;
+ BOOLEAN status;
+
+
+
+ PRINT("IO %b T%b F=%w ", Srb->Function, Srb->TargetId, Srb->SrbFlags, 0);
+
+
+
+ switch(Srb->Function) {
+
+ case SRB_FUNCTION_SHUTDOWN:
+ deviceExtension->ShutDown = TRUE;
+
+ case SRB_FUNCTION_FLUSH:
+ PRINT("FLUSH/SHUTDOWN\n",0,0,0,0);
+ DELAY(1000);
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ // Determine type of request needed
+ if(deviceExtension->DiskDev[Srb->TargetId])
+ status = dcehlpDiskRequest(deviceExtension, Srb);
+ else
+ status = dcehlpScsiRequest(deviceExtension, Srb);
+
+ if(status==FALSE) {
+ PRINT("StartIo: DCE is busy\n",0,0,0,0);
+
+ // Save the request until a pending one completes.
+ if(deviceExtension->PendingSrb != NULL) {
+ //
+ // This should never happen:
+ PRINT("StartIo: Queue already full\n",0,0,0,0);
+ // Already one queued, abort the newer one
+ //
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ }
+ else {
+ // Put this request on queue
+ deviceExtension->PendingSrb = Srb;
+ }
+ return(TRUE);
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ return(TRUE);
+
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+ PRINT("ABORT ",0,0,0,0);
+ abortedSrb = NULL;
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+ if(Srb->NextSrb == deviceExtension->PendingSrb ) {
+ // Was pending
+ abortedSrb = Srb->NextSrb;
+ deviceExtension->PendingSrb = NULL;
+ }
+ else {
+ // TAGTAG add tagging support here
+ if(Srb->NextSrb == deviceExtension->ActiveSrb[0] ) {
+ PRINT("StartIo: SRB to abort already running\n",0,0,0,0);
+ abortedSrb = deviceExtension->ActiveSrb[0];
+ deviceExtension->ActiveSrb[0] = NULL;
+ deviceExtension->ActiveCmds--;
+ //
+ // Reset DCE
+ //
+ //$$$ we need something here to wake up the
+ // DCE if it really hangs.
+ }
+ else {
+ PRINT("StartIo: SRB to abort not found\n",0,0,0,0);
+ // Complete abort SRB.
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+ }
+ }
+
+ if(abortedSrb==NULL) {
+ // Nope !
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+ }
+ else {
+ // Process the aborted request
+ abortedSrb->SrbStatus = SRB_STATUS_ABORTED;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ abortedSrb);
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ // Abort request completed
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ // Adapter ready for next request.
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return(TRUE);
+
+
+ case SRB_FUNCTION_IO_CONTROL:
+ case SRB_FUNCTION_RESET_BUS:
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+ PRINT("invalid request\n",0,0,0,0);
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return(TRUE);
+
+ } // end switch
+
+} // end Dce376NtStartIo()
+
+
+
+
+BOOLEAN
+Dce376NtInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the DCE376 SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if we handled the interrupt
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PUCHAR EisaAddress;
+ ULONG index;
+ UCHAR interruptStatus;
+ UCHAR status;
+ UCHAR errcode;
+
+
+
+ EisaAddress = deviceExtension->EisaAddress;
+#if REPORTSPURIOUS
+ PRINT("!",0,0,0,0);
+#endif
+
+ switch(deviceExtension->AdapterIndex) {
+
+ case 1: // First DCE SCSI part
+
+ // Check for pending request
+ if(deviceExtension->ActiveScsiSrb==NULL) {
+ // Nothing to do
+#if REPORTSPURIOUS
+ PRINT("}",0,0,0,0);
+#endif
+ deviceExtension->ScsiInterruptCount++; // If in init part
+ return(TRUE);
+ }
+
+
+ // Check if a command was started
+ if(deviceExtension->Kicked) {
+ // There's something waiting
+ errcode = ScsiPortReadPortUchar(EisaAddress+0x1f6);
+ if(errcode!=0xff) {
+ // No spurious interrupt
+ PRINT(">", 0, 0, 0, 0);
+ deviceExtension->Kicked=0;
+ if(dcehlpContinueScsiRequest(deviceExtension,
+ deviceExtension->ActiveScsiSrb)==FALSE) {
+ // Request no longer active
+ deviceExtension->ActiveScsiSrb = NULL;
+ }
+ }
+ }
+
+ // Check for pending requests. If there is one then start it now.
+ if(deviceExtension->ActiveScsiSrb==NULL)
+ if(deviceExtension->PendingSrb != NULL) {
+ PSCSI_REQUEST_BLOCK anotherSrb;
+
+ PRINT("pending-> \n",0,0,0,0);
+ anotherSrb = deviceExtension->PendingSrb;
+ deviceExtension->PendingSrb = NULL;
+ Dce376NtStartIo(deviceExtension, anotherSrb);
+ }
+
+ break;
+
+ default: // Disk parts
+
+ //
+ // Check interrupt pending.
+ //
+ interruptStatus = ScsiPortReadPortUchar(EisaAddress+BMIC_SYSINTCTRL);
+ if(!(interruptStatus & BMIC_SIC_PENDING)) {
+#if REPORTSPURIOUS
+ PRINT("Spurious interrupt\n", 0, 0, 0, 0);
+#endif
+ return FALSE;
+ }
+
+
+ //
+ // Read interrupt status from BMIC and acknowledge
+ //
+ // $$$ For setupapp, this needs some change:
+ // sometimes the SIC_PENDING is set, but
+ // EISA_DB is not. In that case we need to loop
+ // a couple times.
+ // $$$ We need not, because we get called again...
+ //
+ interruptStatus = ScsiPortReadPortUchar(EisaAddress+BMIC_EISA_DB);
+
+ status = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+2);
+ errcode = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+3);
+
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB, interruptStatus);
+
+ if(!(interruptStatus&1)) {
+ // From DCE, but unknown source
+#if REPORTSPURIOUS
+ PRINT("Dce376NtInterrupt: Unknown source\n", 0, 0, 0, 0);
+#endif
+ return(TRUE);
+ }
+
+
+ // Check...
+ if(deviceExtension->ActiveCmds<=0) {
+ // No one there interrupting us
+ PRINT("ActiveCmds==0!\n",0,0,0,0);
+ return(TRUE);
+ }
+
+
+ //
+ // TAGTAG Add tagging support here: find
+ // index of RCB for interrupting request
+ //
+ index = 0;
+
+
+ //
+ // Check whether this SRB is actually running
+ //
+ if(deviceExtension->ActiveSrb[index] == NULL) {
+ // No one there interrupting us, again
+ PRINT("ActiveSrb[%b]==0!\n",index,0,0,0);
+ return(TRUE);
+ }
+
+ if(deviceExtension->ActiveRcb[index].WaitInt == 0) {
+ // No one there interrupting us, again
+ PRINT("ActiveRcb[%b].WaitInt==0!\n",index,0,0,0);
+ return(TRUE);
+ }
+
+ // Update DCE status fields in RCB
+ deviceExtension->ActiveRcb[index].WaitInt = 0;
+ deviceExtension->ActiveRcb[index].DceStatus = status;
+ deviceExtension->ActiveRcb[index].DceErrcode = errcode;
+
+
+ // Continue or finish the interrupting SRB request
+ dcehlpContinueDiskRequest(deviceExtension, index, FALSE);
+
+
+ if(deviceExtension->ActiveCmds < DCE_MAX_IOCMDS) {
+ // A request slot is free now
+ // Check for pending requests.
+ // If there is one then start it now.
+
+ if(deviceExtension->PendingSrb != NULL) {
+ PSCSI_REQUEST_BLOCK anotherSrb;
+
+ PRINT("pending-> \n",0,0,0,0);
+ anotherSrb = deviceExtension->PendingSrb;
+ deviceExtension->PendingSrb = NULL;
+ Dce376NtStartIo(deviceExtension, anotherSrb);
+ }
+ }
+
+ // Definitively was our interrupt...
+ return TRUE;
+ }
+
+} // end Dce376NtInterrupt()
+
+
+
+
+BOOLEAN
+dcehlpDiskRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build disk request from SRB and send it to the DCE
+
+Arguments:
+
+ DeviceExtension
+ SRB
+
+Return Value:
+
+ TRUE if command was started
+ FALSE if host adapter is busy
+
+--*/
+{
+ ULONG index;
+ PRCB rcb;
+ ULONG blocks=0, blockAddr=0;
+ UCHAR Target;
+ UCHAR DceCommand;
+
+
+
+ Target = Srb->TargetId;
+
+ if(Srb->Lun!=0) {
+ // LUN not supported
+ Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ PRINT("diskio dce%b T%b: cmd=%b LUN=%b not supported\n",
+ deviceExtension->AdapterIndex, Target, Srb->Cdb[0], Srb->Lun);
+ return(TRUE);
+ }
+
+ if(deviceExtension->AdapterIndex==1) {
+ // Disk devices on SCSI part not supported
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ PRINT("diskio dce%b T%b: cmd=%b not supported\n",
+ deviceExtension->AdapterIndex, Target, Srb->Cdb[0], 0);
+ return(TRUE);
+ }
+
+
+ if(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
+
+ switch(Srb->Cdb[0]) {
+
+ case SCSIOP_READ:
+ DceCommand = DCE_LREAD;
+ blocks = (ULONG)dcehlpGetM16(&Srb->Cdb[7]);
+ blockAddr = dcehlpGetM32(&Srb->Cdb[2]);
+ break;
+
+ case SCSIOP_WRITE:
+ case SCSIOP_WRITE_VERIFY:
+ DceCommand = DCE_LWRITE;
+ blocks = (ULONG)dcehlpGetM16(&Srb->Cdb[7]);
+ blockAddr = dcehlpGetM32(&Srb->Cdb[2]);
+ break;
+
+ case SCSIOP_READ6:
+ DceCommand = DCE_LREAD;
+ blocks = (ULONG)Srb->Cdb[4];
+ blockAddr = dcehlpGetM24(&Srb->Cdb[1]) & 0x1fffff;
+ break;
+
+ case SCSIOP_WRITE6:
+ DceCommand = DCE_LWRITE;
+ blocks = (ULONG)Srb->Cdb[4];
+ blockAddr = dcehlpGetM24(&Srb->Cdb[1]) & 0x1fffff;
+ break;
+
+ case SCSIOP_REQUEST_SENSE:
+ case SCSIOP_INQUIRY:
+ case SCSIOP_READ_CAPACITY:
+
+ PRINT("T%b: cmd=%b len=%b \n",
+ Target, Srb->Cdb[0], Srb->DataTransferLength, 0);
+
+ DceCommand = DCE_HOSTSCSI;
+ blocks = 0;
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+ case SCSIOP_REZERO_UNIT:
+ case SCSIOP_SEEK6:
+ case SCSIOP_VERIFY6:
+ case SCSIOP_RESERVE_UNIT:
+ case SCSIOP_RELEASE_UNIT:
+ case SCSIOP_SEEK:
+ case SCSIOP_VERIFY:
+ PRINT("target %b: cmd=%b ignored\n",
+ Target, Srb->Cdb[0], 0, 0);
+
+ // Complete
+ Srb->ScsiStatus = SCSISTAT_GOOD;
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ return(TRUE);
+
+ case SCSIOP_FORMAT_UNIT:
+ default:
+ // Unknown request
+ PRINT("target %b: cmd=%b unknown\n",
+ Target, Srb->Cdb[0], 0, 0);
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ return(TRUE);
+ }
+ }
+ else {
+ // can only be flush
+ PRINT("T%b: FLUSH \n", Target, 0, 0, 0);
+ DceCommand = DCE_FLUSH;
+ blocks = 0;
+ }
+
+
+ // PRINT("T%b: cmd=%b @%d, %w ", Target, Srb->Cdb[0], blockAddr, blocks);
+
+
+ // Check for request slot availability
+ if(deviceExtension->ActiveCmds >= DCE_MAX_IOCMDS) {
+ // dce is busy
+ PRINT("dce is busy\n",0,0,0,0);
+ return(FALSE);
+ }
+
+ //
+ // Put this SRB on queue
+ // TAGTAG Add tag support here
+ //
+ index = 0;
+
+ deviceExtension->ActiveCmds++;
+ deviceExtension->ActiveSrb[index] = Srb;
+
+ rcb = &deviceExtension->ActiveRcb[index];
+ rcb->DceCommand = DceCommand;
+ if(Srb->SrbFlags & SRB_FLAGS_ADAPTER_CACHE_ENABLE)
+ rcb->RcbFlags = 0;
+ else {
+ if(DceCommand==DCE_LREAD)
+ rcb->RcbFlags = RCB_PREFLUSH;
+ else
+ rcb->RcbFlags = RCB_POSTFLUSH;
+ }
+
+
+ rcb->VirtualTransferAddress = (PUCHAR)(Srb->DataBuffer);
+ rcb->BlockAddress = blockAddr;
+ if(blocks!=0)
+ rcb->BytesToGo = blocks*512;
+ else
+ rcb->BytesToGo = Srb->DataTransferLength;
+
+ // Start command
+ dcehlpContinueDiskRequest(deviceExtension, index, TRUE);
+
+ return(TRUE);
+}
+
+
+
+
+BOOLEAN
+dcehlpScsiRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build SCSI request from SRB and send it to the DCE
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ TRUE if command was started
+ FALSE if host adapter is busy and request need be queued
+
+--*/
+
+{
+ PSCCB sccb;
+ ULONG length;
+
+
+
+ sccb = &deviceExtension->Sccb;
+
+ if(deviceExtension->AdapterIndex!=1) {
+ // Non-disk devices on disk part not supported
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ PRINT("scsiio dce%b T%b: cmd=%b not supported\n",
+ deviceExtension->AdapterIndex,
+ Srb->TargetId, Srb->Cdb[0], 0);
+ return(TRUE);
+ }
+
+ if(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI) {
+ //
+ // Not SCSI, must be flush
+ // Say ack
+ //
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ return(TRUE);
+ }
+
+ // Check for request slot availability
+ if(deviceExtension->ActiveScsiSrb) {
+ // dce is busy
+ PRINT("scsi is busy\n",0,0,0,0);
+ return(FALSE);
+ }
+
+ // This SRB is being run now
+ deviceExtension->ActiveScsiSrb = Srb;
+
+
+ // Set flag for first request
+ sccb->Started = 0;
+
+
+ // Call the breakdown routine
+ if(dcehlpContinueScsiRequest(deviceExtension, Srb)==FALSE) {
+ // Trouble starting this request
+ deviceExtension->ActiveScsiSrb = NULL;
+ }
+
+ // Don't put request on queue
+ return(TRUE);
+}
+
+
+
+
+VOID
+dcehlpSendMBOX(
+ IN PUCHAR EisaAddress,
+ IN PDCE_MBOX mbox
+ )
+
+/*++
+
+Routine Description:
+
+ Start up conventional DCE command
+
+Arguments:
+
+ Eisa base IO address
+ DCE mailbox
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PUCHAR ptr;
+ ULONG i;
+
+
+ ptr = (PUCHAR)mbox;
+ for(i=0; i<16; i++)
+ ScsiPortWritePortUchar(EisaAddress+BMIC_MBOX+i, ptr[i]);
+
+ // Kick butt
+ ScsiPortWritePortUchar(EisaAddress+BMIC_LOCAL_DB, 1);
+}
+
+
+
+
+BOOLEAN
+Dce376NtResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Dce376Nt SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+
+ PRINT("Reset Bus\n",0,0,0,0);
+ //
+ // Complete all outstanding requests.
+ //
+ ScsiPortCompleteRequest(deviceExtension,
+ 0,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ return TRUE;
+
+} // end Dce376NtResetBus()
+
+
+
+//
+// Transfer memory to/from DCE
+// Return FALSE if an error occured
+// TRUE otherwise
+//
+BOOLEAN
+dcehlpTransferMemory(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG HostAddress,
+ IN ULONG AdapterAddress,
+ IN USHORT Count,
+ IN UCHAR Direction
+ )
+{
+ PUCHAR EisaAddress;
+ DCE_MBOX mbox;
+ ULONG cnt;
+ UCHAR dbell, status, errcode;
+
+
+
+ EisaAddress = deviceExtension->EisaAddress;
+
+
+ // Disable DCE interrupts
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB_ENABLE, 0);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_SYSINTCTRL, 0);
+
+
+ // Setup mailbox
+ mbox.mtmbox.Command = DCE_MEMXFER;
+ mbox.mtmbox.Reserved1 = 0;
+ mbox.mtmbox.Status = 0;
+ mbox.mtmbox.Error = 0;
+ mbox.mtmbox.AdapterAddress = AdapterAddress;
+ mbox.mtmbox.HostAddress = HostAddress;
+ mbox.mtmbox.Direction = Direction;
+ mbox.mtmbox.Unused = 0;
+ mbox.mtmbox.TransferCount = Count;
+
+
+ dcehlpSendMBOX(EisaAddress, &mbox);
+
+ //
+ // Poll the complete bit
+ // Magic here: if called from ContinueScsiRequest,
+ // the dbell sticks to 0xff !!!???
+ //
+ for(cnt=0; cnt<0x1000; cnt++) {
+ ScsiPortStallExecution(100);
+ dbell = ScsiPortReadPortUchar(EisaAddress+BMIC_EISA_DB);
+ if(dbell==0xff && cnt<1000)
+ continue;
+ if(dbell & 1)
+ break;
+ }
+
+ ScsiPortStallExecution(100); // To be sure ! ???
+
+ status = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+2);
+ errcode = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+3);
+
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB, dbell);
+
+ ScsiPortStallExecution(100);
+
+ // Enable DCE interrupts
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB_ENABLE, 1);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_SYSINTCTRL, BMIC_SIC_ENABLE);
+
+ if( (cnt>0x4000) || (errcode&1) ) {
+ PRINT("MT cnt=%w db=%b s=%b e=%b\n", cnt, dbell, status, errcode);
+ DELAY(1000);
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+
+VOID
+dcehlpCheckTarget(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN UCHAR TargetId
+ )
+{
+ PNONCACHED_EXTENSION NoncachedExtension;
+ PUCHAR EisaAddress;
+ PUCHAR scsiReq;
+ ULONG i, cnt, tstat_reg, to_reg, err_reg;
+ PUCHAR pppScsiReq;
+
+
+
+ NoncachedExtension = deviceExtension->NoncachedExtension;
+ EisaAddress = deviceExtension->EisaAddress;
+ scsiReq = NoncachedExtension->ScsiReq;
+
+ PRINT("T%b : ", TargetId, 0, 0, 0);
+
+ // Clear scsi request block
+ for(i=0; i<DCE_SCSIREQLEN; i++)
+ scsiReq[i] = 0;
+
+
+ // Setup scsi request block
+#if 0
+ scsiReq->TargetID = TargetId;
+ scsiReq->cdbSize = 6;
+ scsiReq->cdb[0] = 0x12; // Inquiry command
+ scsiReq->cdb[4] = 36; // Response length
+ scsiReq->Opcode = DCE_SCSI_READ;
+ scsiReq->ppXferAddr = NoncachedExtension->PhysicalBufferAddress;
+ scsiReq->XferCount = 36;
+ scsiReq->ppSenseBuf = NoncachedExtension->PhysicalReqSenseAddress;
+ scsiReq->SenseLen = 14;
+#endif
+ scsiReq[0] = TargetId;
+ scsiReq[1] = 6;
+ scsiReq[2+0] = 0x12; // Inquiry command
+ scsiReq[2+4] = 36; // Response length
+ scsiReq[18] = DCE_SCSI_READ;
+ dcehlpPutI32(scsiReq+14, NoncachedExtension->PhysicalBufferAddress);
+ dcehlpPutI16(scsiReq+19, 36);
+ dcehlpPutI32(scsiReq+23, NoncachedExtension->PhysicalReqSenseAddress);
+ scsiReq[22] = 14;
+
+
+ // Program four bytes of physical address into dce
+ pppScsiReq = (PUCHAR)(&NoncachedExtension->PhysicalScsiReqAddress);
+ for(i=0; i<4; i++)
+ ScsiPortWritePortUchar(EisaAddress+0x1f2+i, pppScsiReq[i]);
+ deviceExtension->ScsiInterruptCount = 0;
+
+ //
+ // Set marker
+ // setupapp calls the interrupt handler continuosly,
+ // so we need this to determine if the
+ // DCE is actually through with the request
+ //
+ ScsiPortWritePortUchar(EisaAddress+0x1f6, 0xff);
+ NoncachedExtension->Buffer[0] = 0xff;
+
+ // Kick the dce
+ ScsiPortWritePortUchar(EisaAddress+0x1f7, 0x98);
+
+#if 0
+ // Output register values before execution finishes
+ tstat_reg = ScsiPortReadPortUchar(EisaAddress+0x1f5);
+ to_reg = ScsiPortReadPortUchar(EisaAddress+0x1f6);
+ err_reg = ScsiPortReadPortUchar(EisaAddress+0x1f2);
+ PRINT("ts=%b to=%b err=%b ", tstat_reg, to_reg, err_reg, 0);
+#endif
+
+ // Wait for command to finish
+ for(cnt=0; cnt<10000; cnt++) {
+ // Check if interrupt occured
+ if(deviceExtension->ScsiInterruptCount)
+ break;
+ // Check if interrupt got lost
+ if(ScsiPortReadPortUchar(EisaAddress+0x1f6) != (UCHAR)0xff)
+ break;
+ ScsiPortStallExecution(100);
+ }
+
+ // Wait another 100 ms to be sure
+ ScsiPortStallExecution(100 * 1000);
+
+ // Read execution status registers and ack the interrupt
+ tstat_reg = ScsiPortReadPortUchar(EisaAddress+0x1f5);
+ to_reg = ScsiPortReadPortUchar(EisaAddress+0x1f6);
+ err_reg = ScsiPortReadPortUchar(EisaAddress+0x1f2);
+ ScsiPortWritePortUchar(EisaAddress+0x1f2, 0x99);
+ PRINT("ts=%b to=%b err=%b\n", tstat_reg, to_reg, err_reg, 0);
+
+ deviceExtension->ScsiDevType[TargetId] = (UCHAR)0xff;
+ if(to_reg!=0x2d) {
+ if(tstat_reg!=2 && err_reg==0) {
+ PINQUIRYDATA inq = (PINQUIRYDATA)(NoncachedExtension->Buffer);
+
+ deviceExtension->ScsiDevType[TargetId] = inq->DeviceType;
+
+ #if MYPRINT
+ PRINT("target %b : type=%b/%b len=%b '",
+ TargetId, inq->DeviceType, inq->DeviceTypeModifier,
+ inq->AdditionalLength);
+ inq->VendorSpecific[0]=0;
+ PRINT(inq->VendorId, 0, 0, 0, 0);
+ PRINT("'\n", 0, 0, 0, 0);
+ #endif
+ }
+ }
+}
+
+
+
+/*
+** Continue scsi request
+** Return TRUE if request is active
+** FALSE if request has completed (or was never started)
+*/
+BOOLEAN
+dcehlpContinueScsiRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+{
+ PSCCB sccb;
+ ULONG bytes;
+ BOOLEAN nobreaks = FALSE;
+ PNONCACHED_EXTENSION NoncachedExtension;
+ PUCHAR EisaAddress;
+ PUCHAR scsiReq;
+ ULONG physDataPtr;
+ ULONG physRqsPtr;
+ ULONG maxBytesThisReq;
+ ULONG maxBlocksPerReq;
+ ULONG i, cnt, length;
+ UCHAR tstat_reg, to_reg, err_reg;
+ PUCHAR pppScsiReq;
+
+
+
+ NoncachedExtension = deviceExtension->NoncachedExtension;
+ EisaAddress = deviceExtension->EisaAddress;
+ scsiReq = NoncachedExtension->ScsiReq;
+ sccb = &deviceExtension->Sccb;
+
+
+ // Check if this is the first call
+ if(sccb->Started==0) {
+ //
+ // New kid on the control block. Get things started.
+ //
+ sccb->Started = 1;
+
+ PRINT("C%b L=%w ", Srb->Cdb[0], Srb->DataTransferLength, 0, 0);
+
+ // Check data transfer length
+ bytes = Srb->DataTransferLength;
+ if(!(Srb->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)))
+ bytes = 0;
+
+ if(bytes==0)
+ sccb->Opcode = DCE_SCSI_NONE;
+ else if(Srb->SrbFlags & SRB_FLAGS_DATA_IN)
+ sccb->Opcode = DCE_SCSI_READ;
+ else
+ sccb->Opcode = DCE_SCSI_WRITE;
+
+ // Store virtual data transfer address
+ sccb->VirtualTransferAddress = (PUCHAR)Srb->DataBuffer;
+
+ // Store SCSI device type
+ sccb->DevType = deviceExtension->ScsiDevType[Srb->TargetId];
+
+ //
+ // Determine data transfer parameters
+ //
+ switch(Srb->Cdb[0]) {
+ case SCSIOP_READ6:
+ case SCSIOP_WRITE6:
+ // Short CDB, determine device type
+ if(sccb->DevType == 1) {
+ // Sequential device (SCSI tape)
+ sccb->DeviceAddress = 0;
+ sccb->BlocksToGo = dcehlpGetM24(&Srb->Cdb[2]);
+ sccb->BytesPerBlock = bytes / sccb->BlocksToGo;
+ }
+ else {
+ // Non-sequential device (disk, cd-rom, etc)
+ // Note: we take the LUN bits into the device
+ // address; that makes the PutM() easier, too.
+ sccb->DeviceAddress = dcehlpGetM24(&Srb->Cdb[1]);
+ sccb->BlocksToGo = (ULONG)Srb->Cdb[4];
+ if(sccb->BlocksToGo==0)
+ sccb->BlocksToGo = 256;
+ sccb->BytesPerBlock = bytes / sccb->BlocksToGo;
+ }
+ break;
+
+ case SCSIOP_READ:
+ case SCSIOP_WRITE:
+ case SCSIOP_WRITE_VERIFY:
+ // Long CDB
+ sccb->DeviceAddress = dcehlpGetM32(&Srb->Cdb[2]);
+ sccb->BlocksToGo = (ULONG)dcehlpGetM16(&Srb->Cdb[7]);
+ if(sccb->BlocksToGo==0)
+ sccb->BlocksToGo==65536;
+ sccb->BytesPerBlock = bytes / sccb->BlocksToGo;
+ break;
+
+ default:
+ sccb->BytesPerBlock = 0;
+ nobreaks = TRUE;
+ break;
+ }
+
+ if(sccb->BytesPerBlock==0)
+ // Can't break this down
+ nobreaks = TRUE;
+
+ } // end if(sccb->Started==0)
+ else {
+ //
+ // We started before, so this is interrupt time
+ //
+
+ //
+ // Read execution status registers and ack the interrupt
+ //
+ tstat_reg = ScsiPortReadPortUchar(EisaAddress+0x1f5);
+ to_reg = ScsiPortReadPortUchar(EisaAddress+0x1f6);
+ err_reg = ScsiPortReadPortUchar(EisaAddress+0x1f2);
+ ScsiPortWritePortUchar(EisaAddress+0x1f2, 0x99);
+#if MYPRINT
+ if(tstat_reg || to_reg || err_reg) {
+ PRINT("ts=%b to=%b e=%b ", tstat_reg, to_reg, err_reg, 0);
+ }
+#endif
+
+ //
+ // Adjust pointers
+ //
+ sccb->DeviceAddress += sccb->BlocksThisReq;
+ sccb->BlocksToGo -= sccb->BlocksThisReq;
+ sccb->VirtualTransferAddress += sccb->BytesThisReq;
+
+ //
+ // Check for selection timeout
+ //
+ if(to_reg==0x2d) {
+ // Timeout on selection
+ PRINT("TOUT\n", 0, 0, 0, 0);
+ Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ return(FALSE);
+ }
+
+ //
+ // Check for other errors
+ //
+ if(err_reg) {
+ // Some error
+ Srb->ScsiStatus = tstat_reg;
+ if(tstat_reg==8)
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+ else {
+ if(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) {
+ PRINT("AutoSense DIS ",0,0,0,0);
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ }
+ else {
+ PRINT("AutoSense ",0,0,0,0);
+ Srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
+ // $$$ If tape request, change the Information[] field
+ // in SenseInfoBuffer. It represents the number of tape
+ // blocks/bytes not read or written.
+ // We cannot use dcehlpTransferMemory(), because we would
+ // have to syncronize this with disk requests running on
+ // a different logical adapter (As of now, the DCE runs
+ // only one request at a time). What a mess!
+ // Using MapBuffers would come in handy here...
+ }
+ }
+ PRINT("ERR\n", 0, 0, 0, 0);
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ return(FALSE);
+ }
+
+ //
+ // See if we're done
+ //
+ if(sccb->BlocksToGo==0) {
+ // We're done
+ PRINT("OK\n", 0, 0, 0, 0);
+ Srb->ScsiStatus = 0;
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ return(FALSE);
+ }
+
+ // Otherwise start next part of request
+ PRINT("Cont:\n", 0, 0, 0, 0);
+ }
+
+
+ //
+ // If we get here, there's something left to do
+ //
+
+
+ if(sccb->Opcode != DCE_SCSI_NONE) {
+ //
+ // Data to transfer
+ // Get physical data buffer address
+ //
+ physDataPtr = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ Srb,
+ sccb->VirtualTransferAddress,
+ &length));
+ }
+ else
+ physDataPtr = 0;
+
+ // Setup common part of scsi request block
+ scsiReq[0] = Srb->TargetId;
+ scsiReq[1] = Srb->CdbLength;
+ for(i=0; i<Srb->CdbLength; i++)
+ scsiReq[2+i] = Srb->Cdb[i];
+ dcehlpPutI32(scsiReq+14, physDataPtr);
+ scsiReq[18] = sccb->Opcode;
+ scsiReq[21] = 0;
+
+
+ if(nobreaks) {
+ //
+ // Request may not be broken up
+ // We got here on first pass, so 'bytes' is valid
+ //
+ if(length < bytes) {
+ // The data area is not physically continuous
+ // $$$ might use better error code here
+ PRINT("NOBREAKS SCSI S/G\n",0,0,0,0);
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ return(FALSE);
+ }
+ PRINT("ONCE ", 0, 0, 0, 0);
+ sccb->BlocksToGo = sccb->BlocksThisReq = 1;
+ sccb->BytesThisReq = sccb->BytesPerBlock = bytes;
+
+ // Leave CDB as is
+ }
+ else {
+ //
+ // Request can be broken down
+ // Determine number of blocks for this request
+ //
+ maxBytesThisReq = length < DCE_MAX_XFERLEN ? length : DCE_MAX_XFERLEN;
+ maxBlocksPerReq = maxBytesThisReq / sccb->BytesPerBlock;
+ if(maxBlocksPerReq == 0) {
+ // Out of luck!
+ PRINT("SCSI S/G ACROSS BLOCK (%w)\n", maxBytesThisReq, 0, 0, 0);
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ return(FALSE);
+ }
+
+ if(sccb->BlocksToGo > maxBlocksPerReq)
+ sccb->BlocksThisReq = maxBlocksPerReq;
+ else
+ sccb->BlocksThisReq = sccb->BlocksToGo;
+ sccb->BytesThisReq = sccb->BlocksThisReq * sccb->BytesPerBlock;
+
+ PRINT("mbr=%b btg=%b btr=%b ", maxBlocksPerReq, sccb->BlocksToGo, sccb->BlocksThisReq, 0);
+
+ // We have to modify the CDB
+ switch(scsiReq[2+0]) {
+ case SCSIOP_READ6:
+ case SCSIOP_WRITE6:
+ // Short CDB
+ if(sccb->DevType == 1) {
+ // Sequential device (SCSI tape)
+ dcehlpPutM24(&scsiReq[2+2], sccb->BlocksThisReq);
+ }
+ else {
+ // Non-sequential device (disk, cd-rom, etc)
+ // Note: we had the LUN bits in the device address!
+ dcehlpPutM24(&scsiReq[2+1], sccb->DeviceAddress);
+ scsiReq[2+4] = (UCHAR)(sccb->BlocksThisReq);
+ }
+ break;
+
+ case SCSIOP_READ:
+ case SCSIOP_WRITE:
+ case SCSIOP_WRITE_VERIFY:
+ // Long CDB
+ dcehlpPutM32(&scsiReq[2+2], sccb->DeviceAddress);
+ dcehlpPutM16(&scsiReq[2+7], (USHORT)sccb->BlocksThisReq);
+ break;
+
+ default:
+ PRINT("WEIRD!!! \n", 0, 0, 0, 0);
+ break;
+ }
+ }
+
+ // Update transfer length field
+ dcehlpPutI16(scsiReq+19, (USHORT)sccb->BytesThisReq);
+
+
+ //
+ // Set auto request sense fields
+ //
+ if(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) {
+ // Stuff the request sense info elsewhere
+ physRqsPtr = NoncachedExtension->PhysicalReqSenseAddress;
+ scsiReq[22] = 14;
+ }
+ else {
+ // Get physical address of SenseInfoBuffer
+ physRqsPtr = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ Srb->SenseInfoBuffer,
+ &length));
+ // $$$ should verify length >= SenseInfoBufferLength here
+ scsiReq[22] = Srb->SenseInfoBufferLength;
+ }
+ dcehlpPutI32(scsiReq+23, physRqsPtr);
+
+
+ //
+ // Program four bytes of physical address into DCE
+ //
+ PRINT("* ",0,0,0,0);
+ pppScsiReq = (PUCHAR)(&NoncachedExtension->PhysicalScsiReqAddress);
+ for(i=0; i<4; i++)
+ ScsiPortWritePortUchar(EisaAddress+0x1f2+i, pppScsiReq[i]);
+ deviceExtension->ScsiInterruptCount = 0;
+ deviceExtension->Kicked = 1;
+
+
+ // Set marker (see explanation at CheckTarget)
+ ScsiPortWritePortUchar(EisaAddress+0x1f6, 0xff);
+
+
+ // Kick the dce
+ ScsiPortWritePortUchar(EisaAddress+0x1f7, 0x98);
+
+
+ // Wait for interrupt
+ return(TRUE);
+}
+
+
+
+
+/*
+** Continue disk request
+** Return TRUE if a request slot became available
+** FALSE if not
+*/
+BOOLEAN
+dcehlpContinueDiskRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG index,
+ IN BOOLEAN Start
+ )
+{
+ PRCB rcb;
+ PSCSI_REQUEST_BLOCK srb;
+ PNONCACHED_EXTENSION nce;
+ DCE_MBOX mbox;
+ ULONG physAddr;
+ ULONG length, blocks, bytes;
+ PUCHAR EisaAddress;
+ ULONG i;
+
+
+
+ EisaAddress = deviceExtension->EisaAddress;
+ rcb = &deviceExtension->ActiveRcb[index];
+ srb = deviceExtension->ActiveSrb[index];
+ nce = deviceExtension->NoncachedExtension;
+
+
+
+ if(Start==FALSE) {
+ //
+ // DCE interrupt time call
+ // Determine status of last DCE request
+ //
+
+ if(rcb->DceErrcode & 1) {
+ // The DCE detected an error
+ PRINT("error=%b status=%b\n",rcb->DceErrcode,rcb->DceStatus,0,0);
+
+ // $$$ Add error code mapping here
+ dcehlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_TIMEOUT);
+
+ // Slot free
+ return(TRUE);
+ }
+
+ // Status was okay, check post-read copy flag
+ if(rcb->RcbFlags & RCB_NEEDCOPY) {
+ // Last block was a scattered single block read
+ if(!dcehlpSplitCopy(deviceExtension, srb,
+ nce->PhysicalBufferAddress,
+ rcb->VirtualTransferAddress, 512, TRUE)) {
+ // Error breaking up the s/g mess
+ PRINT("SG ERROR !\n",0,0,0,0);
+ dcehlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_PARITY_ERROR);
+ return(TRUE);
+ }
+
+ // Reset flag
+ rcb->RcbFlags &= (~RCB_NEEDCOPY);
+ }
+
+ // Advance pointers
+ rcb->BytesToGo -= rcb->BytesThisReq;
+ rcb->VirtualTransferAddress += rcb->BytesThisReq;
+
+ // Check if more to do
+ if(rcb->BytesToGo==0) {
+ //
+ // This SRB's data transfer is done
+ //
+ if(rcb->RcbFlags & RCB_POSTFLUSH) {
+ //
+ // Need to flush buffers before we're through
+ //
+ rcb->RcbFlags &= (~RCB_POSTFLUSH);
+ //PRINT("POSTFLUSH\n",0,0,0,0);
+ rcb->DceCommand = DCE_FLUSH;
+ }
+ else {
+ //
+ // We're actually done here !
+ //
+ PRINT("OK \r",0,0,0,0);
+
+ // Update SCSI status.
+ // $$$ can we manipulate this for non SCSI requests ?
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ // Finish
+ dcehlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_SUCCESS);
+ return TRUE;
+ }
+ }
+
+ //
+ // No error but SRB not completely done.
+ //
+ PRINT("MORE:\r",0,0,0,0);
+ }
+ else {
+ //
+ // We start an SRB here, initialize
+ // RCB control block variables
+ //
+ rcb->RcbFlags &= (~RCB_NEEDCOPY); // be safe
+
+ // $$$ Double check if flags indicate any data transfer at all !
+ }
+
+
+ if(rcb->BytesToGo) {
+ //
+ // We want to transfer some data, get the physical address
+ //
+ physAddr = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ srb,
+ rcb->VirtualTransferAddress,
+ &length));
+
+ // Get maximum length for this request
+ if(length < rcb->BytesToGo)
+ bytes = length;
+ else
+ bytes = rcb->BytesToGo;
+
+ if(rcb->DceCommand==DCE_LREAD || rcb->DceCommand==DCE_LWRITE) {
+ //
+ // Disk read/write: get number of blocks
+ //
+ if( (blocks = bytes/512) == 0 ) {
+ //
+ // Here we have a scatter gather break within the next block !
+ // Set I/O to one block to/from our buffer
+ //
+ blocks = 1;
+ physAddr = nce->PhysicalBufferAddress;
+
+ if(rcb->DceCommand==DCE_LWRITE) {
+ // Write command, fill buffer first
+ if(!dcehlpSplitCopy(deviceExtension, srb, physAddr,
+ rcb->VirtualTransferAddress, 512, FALSE)) {
+ // Error breaking up the s/g mess
+ PRINT("SG ERROR !\n",0,0,0,0);
+ dcehlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_PARITY_ERROR);
+ return(TRUE);
+ }
+ }
+ else {
+ // Read command, need copy later
+ rcb->RcbFlags |= RCB_NEEDCOPY;
+ }
+ }
+
+ //
+ // Important: in case of scatter/gather over block
+ // boundaries, round bytes down to full multiple of 512
+ // This will leave us with less than 512 bytes next time
+ // in case of a s/g across block boundaries
+ //
+ bytes = blocks*512;
+ }
+ else {
+ //
+ // Not a disk read/write
+ //
+ if(bytes != rcb->BytesToGo) {
+ //
+ // Scatter Gather within a non read/write command
+ // This would need a SplitCopy() :-|
+ // Stuff like this makes programmers happy and
+ // should cost h/w developers their job.
+ //
+ PRINT("S/G within non-rw, len=%w/%w\n",
+ length, rcb->BytesToGo, 0, 0);
+ dcehlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_PARITY_ERROR);
+ return(TRUE);
+ }
+ }
+ }
+ else {
+ //
+ // We don't have data to transfer
+ //
+ bytes = 0;
+ blocks = 0;
+ }
+
+
+ //
+ // Now look at the specific DCE command
+ //
+ switch(rcb->DceCommand) {
+
+ case DCE_LREAD:
+ case DCE_LWRITE:
+ // Disk read/write
+ if(blocks==0) {
+ PRINT("LIO: blocks==0! ",0,0,0,0);
+ // Cancel this command with some garbage error code
+ dcehlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_PARITY_ERROR);
+ return(TRUE);
+ }
+ //
+ // Check if we need to flush first (non-cached read)
+ //
+ if(rcb->RcbFlags & RCB_PREFLUSH) {
+ // Reset flush and copy flags, if set
+ rcb->RcbFlags &= (~(RCB_NEEDCOPY|RCB_PREFLUSH));
+ //PRINT("PREFLUSH\n",0,0,0,0);
+
+ // Flush buffers, invalidate cache
+ mbox.ivmbox.Command = DCE_INVALIDATE;
+ mbox.ivmbox.Reserved1 = 0;
+ mbox.ivmbox.Status = srb->TargetId;
+ mbox.ivmbox.Error = 0;
+ mbox.ivmbox.Unused1 = 0;
+ mbox.ivmbox.Unused2 = 0;
+ mbox.ivmbox.Unused3 = 0;
+ // Don't advance pointers this pass !
+ bytes = 0;
+ blocks = 0;
+ break;
+ }
+ else {
+ // Transfer data
+ mbox.iombox.Command = rcb->DceCommand;
+ mbox.iombox.Reserved1 = 0;
+ mbox.iombox.Status = srb->TargetId;
+ mbox.iombox.Error = 0;
+ mbox.iombox.SectorCount = (USHORT)blocks;
+ mbox.iombox.Reserved2 = 0;
+ mbox.iombox.PhysAddr = physAddr;
+ mbox.iombox.Block = rcb->BlockAddress;
+ // PRINT(" %d-%d,%w ", physAddr, rcb->BlockAddress, blocks, 0);
+ }
+ break;
+
+ default:
+ PRINT("DR: unknown DceCommand=%b\n", rcb->DceCommand, 0, 0, 0);
+
+ // Cancel this command with some garbage error code
+ dcehlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_PARITY_ERROR);
+ return(TRUE);
+
+ case DCE_RECAL:
+ // Recalibrate
+ mbox.rdmbox.Command = DCE_RECAL;
+ mbox.rdmbox.Reserved1 = 0;
+ mbox.rdmbox.Status = (UCHAR)srb->TargetId;
+ mbox.rdmbox.Error = 0;
+ mbox.rdmbox.Unused1 = 0;
+ mbox.rdmbox.Unused2 = 0;
+ mbox.rdmbox.Unused3 = 0;
+ rcb->BytesToGo = 0; // Just to be safe
+ bytes = 0;
+ break;
+
+ case DCE_FLUSH:
+ // Flush buffers
+ mbox.flmbox.Command = DCE_FLUSH;
+ mbox.flmbox.Reserved1 = 0;
+ mbox.flmbox.Status = 0;
+ mbox.flmbox.Error = 0;
+ mbox.flmbox.Unused1 = 0;
+ mbox.flmbox.Unused2 = 0;
+ mbox.flmbox.Unused3 = 0;
+
+ // In case we get here for a post-flush,
+ // set variables so we're done next time
+ rcb->BytesToGo = 0;
+ bytes = 0;
+ blocks = 0;
+ break;
+
+ case DCE_HOSTSCSI:
+ // SCSI commands like inquiry, read capacity
+ {
+ PUCHAR VirtualCdbPtr = nce->Buffer;
+ ULONG PhysicalCdbPtr = nce->PhysicalBufferAddress;
+
+ // Make the CDB storage dword aligned
+ while( PhysicalCdbPtr & 3 ) {
+ PhysicalCdbPtr++;
+ VirtualCdbPtr++;
+ }
+
+ // Copy CDB
+ for(i=0; i<(ULONG)srb->CdbLength; i++)
+ VirtualCdbPtr[i] = srb->Cdb[i];
+
+ // Setup mailbox
+ mbox.xsmbox.Command = rcb->DceCommand;
+ mbox.xsmbox.Reserved1 = 0;
+ mbox.xsmbox.Status = (UCHAR)srb->TargetId;
+ mbox.xsmbox.Error = srb->CdbLength;
+ mbox.xsmbox.CdbAddress = PhysicalCdbPtr;
+ mbox.xsmbox.HostAddress = physAddr;
+ mbox.xsmbox.Direction = DCE_DEV2HOST;
+ mbox.xsmbox.Unused = 0;
+ mbox.xsmbox.TransferCount = (USHORT)bytes;
+ }
+ break;
+ }
+
+
+ // Advance pointers
+ rcb->BytesThisReq = bytes;
+ rcb->BlockAddress += blocks;
+
+
+ // Fire up command
+ rcb->WaitInt = 1;
+ dcehlpSendMBOX(EisaAddress, &mbox);
+
+
+ // No SRB slot freed
+ return(FALSE);
+}
+
+
+
+//
+// Disk Request Done
+// Dequeue, set status, notify Miniport layer
+// Always returns TRUE (slot freed)
+//
+BOOLEAN
+dcehlpDiskRequestDone(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG index,
+ IN UCHAR Status
+ )
+{
+ PSCSI_REQUEST_BLOCK srb;
+
+
+
+ srb = deviceExtension->ActiveSrb[index];
+
+ // Set status
+ srb->SrbStatus = Status;
+
+ // This SRB is through
+ deviceExtension->ActiveSrb[index] = NULL;
+ deviceExtension->ActiveCmds--;
+
+ // Call notification routine for the SRB.
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ return(TRUE);
+}
+
+
+
+//
+// Return TRUE if successfull, FALSE otherwise
+//
+// The 'Srb' parameter is only used for the
+// ScsiPortGetPhysicalAddress() call and must
+// be NULL if we're dealing with e.g the
+// SenseInfoBuffer
+//
+BOOLEAN
+dcehlpSplitCopy(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN ULONG PhysicalBufferAddress,
+ IN PUCHAR VirtualUserAddress,
+ IN USHORT Count,
+ IN BOOLEAN ToUser
+ )
+{
+ ULONG physUserAddress;
+ ULONG length;
+ USHORT chunk;
+
+
+
+ PRINT("# ",0,0,0,0);
+ while(Count) {
+
+ // Prepare for check
+ length = 0;
+
+ // Get physical user address
+ physUserAddress = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ Srb,
+ VirtualUserAddress,
+ &length));
+
+ // Check length
+ if(length==0) {
+ // Something went wrong here
+ PRINT("SplitCopy: length==0!\n", 0, 0, 0, 0);
+ return(FALSE);
+ }
+
+ // Determine maximum transfer length this time
+ if(length > ((ULONG)Count))
+ chunk = Count;
+ else
+ chunk = (USHORT)length;
+
+ // Copy
+ if(ToUser) {
+ // Copy to user:
+ // Buffer -> DCE -> User
+ // PRINT("%p>%w>%p ", PhysicalBufferAddress, chunk, physUserAddress, 0);
+ if(!dcehlpTransferMemory(deviceExtension, PhysicalBufferAddress, DCE_BUFLOC, chunk, DCE_HOST2DCE))
+ // Error
+ return(FALSE);
+ if(!dcehlpTransferMemory(deviceExtension, physUserAddress, DCE_BUFLOC, chunk, DCE_DCE2HOST))
+ // Error
+ return(FALSE);
+ }
+ else {
+ // Copy from user:
+ // User -> DCE -> Buffer
+ // PRINT("%p<%w<%p ", PhysicalBufferAddress, chunk, physUserAddress, 0);
+ if(!dcehlpTransferMemory(deviceExtension, physUserAddress, DCE_BUFLOC, chunk, DCE_HOST2DCE))
+ // Error
+ return(FALSE);
+ if(!dcehlpTransferMemory(deviceExtension, PhysicalBufferAddress, DCE_BUFLOC, chunk, DCE_DCE2HOST))
+ // Error
+ return(FALSE);
+ }
+
+ // Advance pointers
+ VirtualUserAddress += chunk;
+ PhysicalBufferAddress += chunk;
+ Count -= chunk;
+ }
+
+ // PRINT("SC \n",0,0,0,0);
+
+ return(TRUE);
+}
+
+
+
+
+
+// Word order functions
+
+USHORT dcehlpGetM16(PUCHAR p)
+{
+ USHORT s;
+ PUCHAR sp=(PUCHAR)&s;
+
+ sp[0] = p[1];
+ sp[1] = p[0];
+ return(s);
+}
+
+ULONG dcehlpGetM24(PUCHAR p)
+{
+ ULONG l;
+ PUCHAR lp=(PUCHAR)&l;
+
+ lp[0] = p[2];
+ lp[1] = p[1];
+ lp[2] = p[0];
+ lp[3] = 0;
+ return(l);
+}
+
+ULONG dcehlpGetM32(PUCHAR p)
+{
+ ULONG l;
+ PUCHAR lp=(PUCHAR)&l;
+
+ lp[0] = p[3];
+ lp[1] = p[2];
+ lp[2] = p[1];
+ lp[3] = p[0];
+ return(l);
+}
+
+void dcehlpPutM16(PUCHAR p, USHORT s)
+{
+ PUCHAR sp=(PUCHAR)&s;
+
+ p[0] = sp[1];
+ p[1] = sp[0];
+}
+
+void dcehlpPutM24(PUCHAR p, ULONG l)
+{
+ PUCHAR lp=(PUCHAR)&l;
+
+ p[0] = lp[2];
+ p[1] = lp[1];
+ p[2] = lp[0];
+}
+
+void dcehlpPutM32(PUCHAR p, ULONG l)
+{
+ PUCHAR lp=(PUCHAR)&l;
+
+ p[0] = lp[3];
+ p[1] = lp[2];
+ p[2] = lp[1];
+ p[3] = lp[0];
+}
+
+void dcehlpPutI16(PUCHAR p, USHORT s)
+{
+ PUCHAR sp=(PUCHAR)&s;
+
+ p[0] = sp[0];
+ p[1] = sp[1];
+}
+
+void dcehlpPutI32(PUCHAR p, ULONG l)
+{
+ PUCHAR lp=(PUCHAR)&l;
+
+ p[0] = lp[0];
+ p[1] = lp[1];
+ p[2] = lp[2];
+ p[3] = lp[3];
+}
+
+ULONG dcehlpSwapM32(ULONG l)
+{
+ ULONG lres;
+ PUCHAR lp=(PUCHAR)&l;
+ PUCHAR lpres=(PUCHAR)&lres;
+
+ lpres[0] = lp[3];
+ lpres[1] = lp[2];
+ lpres[2] = lp[1];
+ lpres[3] = lp[0];
+
+ return(lres);
+}
+
+
+
+#if MYPRINT
+//
+// The monochrome screen printf() helpers start here
+//
+VOID dcehlpPutchar(PUSHORT BaseAddr, UCHAR c)
+{
+ BOOLEAN newline=FALSE;
+ USHORT s;
+ ULONG i;
+
+
+ if(c=='\r')
+ dcehlpColumn = 0;
+ else if(c=='\n')
+ newline=TRUE;
+ else {
+ if(c==9) c==' ';
+ ScsiPortWriteRegisterUshort(
+ BaseAddr+80*24+dcehlpColumn, (USHORT)(((USHORT)c)|0xF00));
+ if(++dcehlpColumn >= 80)
+ newline=TRUE;
+ }
+
+ if(newline) {
+ for(i=0; i<80*24; i++) {
+ s = ScsiPortReadRegisterUshort(BaseAddr+80+i);
+ ScsiPortWriteRegisterUshort(BaseAddr+i, s);
+ }
+ for(i=0; i<80; i++)
+ ScsiPortWriteRegisterUshort(BaseAddr+80*24+i, 0x720);
+ dcehlpColumn = 0;
+ }
+}
+
+
+
+VOID dcehlpPrintHex(PUSHORT BaseAddr, ULONG v, ULONG len)
+{
+ ULONG shift;
+ ULONG nibble;
+
+ len *= 2;
+ shift = len*4;
+ while(len--) {
+ shift -= 4;
+ nibble = (v>>shift) & 0xF;
+ dcehlpPutchar(BaseAddr, dcehlpHex[nibble]);
+ }
+}
+
+
+
+VOID dcehlpPrintf(PHW_DEVICE_EXTENSION deviceExtension,
+ PUCHAR fmt,
+ ULONG a1,
+ ULONG a2,
+ ULONG a3,
+ ULONG a4)
+{
+
+ if(deviceExtension->printAddr == 0)
+ return;
+
+ while(*fmt) {
+
+ if(*fmt=='%') {
+ fmt++;
+ switch(*fmt) {
+ case 0:
+ fmt--;
+ break;
+ case 'b':
+ dcehlpPrintHex(deviceExtension->printAddr, a1, 1);
+ break;
+ case 'w':
+ dcehlpPrintHex(deviceExtension->printAddr, a1, 2);
+ break;
+ case 'p':
+ dcehlpPrintHex(deviceExtension->printAddr, a1, 3);
+ break;
+ case 'd':
+ dcehlpPrintHex(deviceExtension->printAddr, a1, 4);
+ break;
+ default:
+ dcehlpPutchar(deviceExtension->printAddr, '?');
+ break;
+ }
+ fmt++;
+ a1 = a2;
+ a2 = a3;
+ a3 = a4;
+ }
+ else {
+ dcehlpPutchar(deviceExtension->printAddr, *fmt);
+ fmt++;
+ }
+ }
+}
+#endif // MYPRINT
+
diff --git a/private/ntos/miniport/mylex/dce376/dce376nt.h b/private/ntos/miniport/mylex/dce376/dce376nt.h
new file mode 100644
index 000000000..883776fb0
--- /dev/null
+++ b/private/ntos/miniport/mylex/dce376/dce376nt.h
@@ -0,0 +1,383 @@
+/*
+** Mylex DCE376 miniport driver for Windows NT
+**
+** File: dce376nt.h
+** Equates for DCE376 adapter
+**
+** (c) Copyright 1992 Deutsch-Amerikanische Freundschaft, Inc.
+** Written by Jochen Roth
+*/
+
+
+#include "scsi.h"
+
+
+
+/*
+** Firmware related stuff
+*/
+#define DCE_MAX_IOCMDS 1
+#define DCE_MAX_XFERLEN 0x4000 // SCSI only. This must be 16 kBytes or less
+ // because we use the other half of the SCSI
+ // IO buffer for s/g breakdown...
+#define DCE_THUNK 512
+#define DCE_MAXRQS 64
+#define DCE_BUFLOC 0x79000 // 0x75000 + 16kBytes
+
+
+
+/*
+** EISA specific stuff
+*/
+#define EISA_IO_SLOT1 0x1000
+#define EISA_IO_STEP 0x1000
+#define MAXIMUM_EISA_SLOTS 6 // Leave out non-bus master slots
+#define EISA_ID_START 0x0c80 /* Offset from IO base to ID */
+#define EISA_ID_COUNT 4
+
+#define DCE_EISA_MASK { 0xff, 0xff, 0xff, 0xf0 } /* 4 bytes EISA ID mask */
+#define DCE_EISA_ID { 0x35, 0x98, 0, 0x20 } /* 4 bytes EISA ID */
+
+
+
+/*
+** EISA side of BMIC chip
+*/
+#define BMIC_GLBLCFG 0xc88
+#define BMIC_SYSINTCTRL 0xc89 // System interrupt enable/status
+#define BMIC_SIC_ENABLE 0x01 // read-write interrupt enable
+#define BMIC_SIC_PENDING 0x02 // read-only interrupt(s) pending
+#define BMIC_LOCAL_DB_ENABLE 0xc8c // Read-only from EISA side
+#define BMIC_LOCAL_DB 0xc8d // EISA to local notification
+#define BMIC_EISA_DB_ENABLE 0xc8e // Read-write from EISA side
+#define BMIC_EISA_DB 0xc8f // Local to EISA notification
+
+#define BMIC_MBOX 0xc90 // BMIC mailbox registers
+
+
+
+/*
+** More defines
+*/
+#define DCE_PRIMARY_IRQ 15
+#define DCE_SECONDARY_IRQ 10
+#define DCE_SCSI_IRQ 14
+
+
+
+/*
+** Various DCE mailbox formats
+*/
+typedef struct { // I/O mailbox
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status; // Also drive unit (target)
+ UCHAR Error; // Also error
+ USHORT SectorCount;
+ USHORT Reserved2;
+ ULONG PhysAddr;
+ ULONG Block;
+ } DCE_IOMBOX;
+
+typedef struct { // Request Drive Parameters
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status;
+ UCHAR DriveType; // Also error
+ USHORT Reserved2;
+ USHORT Reserved3;
+ ULONG PhysAddr; // Address of DCE_DPT
+ ULONG Reserved4;
+ } DCE_DPMBOX;
+
+typedef struct { // Change EOC IRQ
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status;
+ UCHAR IRQSelect; // 0:IRQ15,1:IRQ10 ; Also error
+ ULONG Unused1;
+ ULONG Unused2;
+ ULONG Unused3;
+ } DCE_EIMBOX;
+
+typedef struct { // Recalibrate drive
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status; // also drive
+ UCHAR Error;
+ ULONG Unused1;
+ ULONG Unused2;
+ ULONG Unused3;
+ } DCE_RDMBOX;
+
+typedef struct { // Transfer memory DCE <-> Host
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status;
+ UCHAR Error;
+ ULONG AdapterAddress;
+ ULONG HostAddress;
+ UCHAR Direction;
+ UCHAR Unused;
+ USHORT TransferCount;
+ } DCE_MTMBOX;
+#define DCE_DCE2HOST 2
+#define DCE_HOST2DCE 3
+
+typedef struct { // Flush data
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status;
+ UCHAR Error;
+ ULONG Unused1;
+ ULONG Unused2;
+ ULONG Unused3;
+ } DCE_FLMBOX;
+
+typedef struct { // Invalidate data
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status; // also drive
+ UCHAR Error;
+ ULONG Unused1;
+ ULONG Unused2;
+ ULONG Unused3;
+ } DCE_IVMBOX;
+
+typedef struct { // Execute SCSI cmd
+ UCHAR Command;
+ UCHAR Reserved1;
+ UCHAR Status; // also drive
+ UCHAR Error; // also cdb length
+ ULONG CdbAddress; // Must be dword aligned
+ ULONG HostAddress; // data transfer
+ UCHAR Direction;
+ UCHAR Unused;
+ USHORT TransferCount;
+ } DCE_XSMBOX;
+#define DCE_DEV2HOST 2
+#define DCE_HOST2DEV 3
+
+
+//
+// The DCE Command codes
+//
+#define DCE_RECAL 0x0b
+#define DCE_LREAD 0x11
+#define DCE_LWRITE 0x12
+#define DCE_DEVPARMS 0x09
+#define DCE_EOCIRQ 0x0e
+#define DCE_MEMXFER 0x13
+#define DCE_FLUSH 0x06
+#define DCE_INVALIDATE 0x0f
+#define DCE_HOSTSCSI 0x0d
+
+//
+// These command codes are used to mark special states
+// the device driver gets into, like flush-after-write
+//
+#define DCX_UNCACHEDREAD 0xf0
+#define DCX_UNCACHEDWRITE 0xf1
+
+
+typedef union {
+ DCE_IOMBOX iombox;
+ DCE_DPMBOX dpmbox;
+ DCE_EIMBOX eimbox;
+ DCE_RDMBOX rdmbox;
+ DCE_MTMBOX mtmbox;
+ DCE_FLMBOX flmbox;
+ DCE_IVMBOX ivmbox;
+ DCE_XSMBOX xsmbox;
+ } DCE_MBOX;
+typedef DCE_MBOX *PDCE_MBOX;
+
+
+
+/*
+** Device parameters as returned from DCE firmware
+*/
+typedef struct {
+ USHORT DriveID;
+ USHORT Heads;
+ USHORT Cylinders;
+ USHORT SectorsPerTrack;
+ USHORT BytesPerSector;
+ USHORT Reserved[3];
+ } DCE_DPT;
+
+typedef DCE_DPT *PDCE_DPT;
+#define DPT_NUMENTS 10
+
+
+
+
+/*
+** SCSI stuff
+*/
+typedef struct {
+ UCHAR TargetID; // 0
+ UCHAR cdbSize; // 1
+ UCHAR cdb[12]; // 2-13
+ ULONG ppXferAddr; // 14
+ UCHAR Opcode; // 18
+ USHORT XferCount; // 19
+ UCHAR Reserved; // 21
+ UCHAR SenseLen; // 22
+ ULONG ppSenseBuf; // 23
+ UCHAR StuffIt; // 27
+ } DCE_SCSI_REQ, *PDCE_SCSI_REQ;
+
+#define DCE_SCSIREQLEN 28
+#define DCE_SCSI_NONE 0
+#define DCE_SCSI_READ 2
+#define DCE_SCSI_WRITE 3 // was 1
+
+
+#define DCES_ERR_REG 0x1f6
+#define DCES_MBOX_REG 0x1f2
+#define DCES_KICK_REG 0x1f7
+#define DCES_TSTAT_REG 0x1f7
+#define DCES_TRIGGER 0x98
+#define DCES_ACK 0x99
+
+//
+// 1f2 (err_reg) seems to hold the sense key
+//
+
+
+
+//
+// Context structure for board scanning
+//
+typedef struct {
+ ULONG Slot;
+ ULONG AdapterCount;
+ } SCANCONTEXT, *PSCANCONTEXT;
+
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+typedef struct _NONCACHED_EXTENSION {
+
+ //
+ // Device Parameter Table for the
+ // Get Device Parameters request
+ //
+ DCE_DPT DevParms[DPT_NUMENTS];
+
+ ULONG PhysicalBufferAddress;
+ UCHAR Buffer[DCE_THUNK];
+
+ ULONG PhysicalScsiReqAddress;
+ UCHAR ScsiReq[DCE_SCSIREQLEN+10];
+
+ ULONG PhysicalReqSenseAddress;
+ UCHAR ReqSense[DCE_MAXRQS];
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+
+
+//
+// Request Control Block (SRB Extension)
+// All information required to break down and execute
+// a disk request is stored here
+//
+typedef struct _RCB {
+ PUCHAR VirtualTransferAddress;
+ ULONG BlockAddress;
+ ULONG BytesToGo;
+ ULONG BytesThisReq;
+ UCHAR DceCommand;
+ UCHAR RcbFlags;
+ UCHAR WaitInt;
+ UCHAR DceStatus;
+ UCHAR DceErrcode;
+ } RCB, *PRCB;
+
+#define RCB_NEEDCOPY 1
+#define RCB_PREFLUSH 2
+#define RCB_POSTFLUSH 4
+
+
+//
+// SCSI Command Control Block
+// We use this block to break down a non-disk scsi request
+//
+typedef struct _SCCB {
+ PUCHAR VirtualTransferAddress;
+ ULONG DeviceAddress;
+ ULONG BytesPerBlock;
+ ULONG BlocksToGo;
+ ULONG BlocksThisReq;
+ ULONG BytesThisReq;
+ UCHAR Started;
+ UCHAR Opcode;
+ UCHAR DevType;
+ } SCCB, *PSCCB;
+
+
+
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ //
+ // NonCached extension
+ //
+ PNONCACHED_EXTENSION NoncachedExtension;
+
+
+ //
+ // Adapter parameters and variables
+ //
+ PVOID EisaAddress; // base address for slot (X000h)
+ PUSHORT printAddr;
+ ULONG AdapterIndex; // 0:first DCE, 1:first DCE SCSI,
+ // 2:second DCE
+ UCHAR HostTargetId;
+ BOOLEAN ShutDown; // We received a shutdown request
+
+
+ // SCSI device management
+ UCHAR DiskDev[8]; // Flag: TRUE if disk, FLASE otherwise
+ UCHAR ScsiDevType[8]; // Device type: 1:tape, 5:cd-rom,...
+ ULONG Capacity[8]; // Device size if disk device
+
+
+ //
+ // Pending request.
+ // This request has not been sent to the adapter yet
+ // because the adapter was busy
+ //
+ PSCSI_REQUEST_BLOCK PendingSrb;
+
+
+ //
+ // Pointers to disk IO requests sent to adapter
+ // and their statuses
+ //
+ ULONG ActiveCmds;
+ PSCSI_REQUEST_BLOCK ActiveSrb[DCE_MAX_IOCMDS];
+ RCB ActiveRcb[DCE_MAX_IOCMDS];
+
+
+ //
+ // Pointer to non-disk SCSI requests sent to adapter
+ //
+ PSCSI_REQUEST_BLOCK ActiveScsiSrb;
+ SCCB Sccb;
+ ULONG Kicked;
+ ULONG ScsiInterruptCount;
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+
diff --git a/private/ntos/miniport/mylex/dce376/dce376nt.rc b/private/ntos/miniport/mylex/dce376/dce376nt.rc
new file mode 100644
index 000000000..80ff457f3
--- /dev/null
+++ b/private/ntos/miniport/mylex/dce376/dce376nt.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "DCE 376 x SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "dce376nt.sys"
+#define VER_ORIGINALFILENAME_STR "dce376nt.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/mylex/dce376/makefile b/private/ntos/miniport/mylex/dce376/makefile
new file mode 100644
index 000000000..0d61f853d
--- /dev/null
+++ b/private/ntos/miniport/mylex/dce376/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/mylex/dce376/sources b/private/ntos/miniport/mylex/dce376/sources
new file mode 100644
index 000000000..d33edabf8
--- /dev/null
+++ b/private/ntos/miniport/mylex/dce376/sources
@@ -0,0 +1,12 @@
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=dce376nt
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DRIVER
+
+INCLUDES=$(BASEDIR)\private\ntos\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=dce376nt.c dce376nt.rc
diff --git a/private/ntos/miniport/mylex/dirs b/private/ntos/miniport/mylex/dirs
new file mode 100644
index 000000000..e56d09712
--- /dev/null
+++ b/private/ntos/miniport/mylex/dirs
@@ -0,0 +1,25 @@
+!IF 0
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=dac960 \
+ dce376
+
diff --git a/private/ntos/miniport/mylex/dmc960/dac960nt.c b/private/ntos/miniport/mylex/dmc960/dac960nt.c
new file mode 100644
index 000000000..8f2d7c19b
--- /dev/null
+++ b/private/ntos/miniport/mylex/dmc960/dac960nt.c
@@ -0,0 +1,2093 @@
+/************************************************************************
+* *
+* COPYRIGHT (C) Mylex Corporation 1994 *
+* *
+* This software is furnished under a license and may be used *
+* and copied only in accordance with the terms and conditions *
+* of such license and with inclusion of the the above copyright *
+* notice. This software or any other copies therof may not be *
+* provided or otherwise made available to any other person. No *
+* title to and ownership of the software is hereby transfered. *
+* *
+* The information in this software is subject to change without *
+* notices and should not be construed as a committmet by Mylex *
+* Corporation. *
+* *
+************************************************************************/
+
+/*
+ File : dac960nt.c
+ Description: Mylex DAC960 SCSI miniport driver - for Windows NT
+
+ Version : 1.12
+
+ Revision :
+
+ Ver 1.10 : First Release
+ Ver 1.11 : Added 32GB Support
+ Ver 1.12 : Driver was not getting loaded in Windows NT (Daytona)
+ : Physical Addresses can be obtained only for certain
+ : Virtual Addresses.
+ : Added code to determine No.Of Channels supported by Adaptor.
+
+*/
+
+#include "miniport.h"
+
+#include "dac960nt.h"
+
+
+#define NODEVICESCAN 0
+#define REPORTSPURIOUS 0 // Somewhat overwhelming in ARCMODE
+#define MAXLOGICALADAPTERS 4
+#define MYPRINT 0
+
+#define DELAY(x) ScsiPortStallExecution( (x) * 1000 )
+
+#if MYPRINT
+
+#define PRINT(f, a, b, c, d) dachlpPrintf(deviceExtension, f, a, b, c, d)
+
+ULONG dachlpColumn = 0;
+UCHAR dachlpHex[] = "0123456789ABCDEF";
+VOID dachlpPutchar(PUSHORT BaseAddr, UCHAR c);
+VOID dachlpPrintHex(PUSHORT BaseAddr, ULONG v, ULONG len);
+VOID dachlpPrintf(PHW_DEVICE_EXTENSION deviceExtension,
+ PUCHAR fmt,
+ ULONG a1,
+ ULONG a2,
+ ULONG a3,
+ ULONG a4);
+#else
+#define PRINT(f, a, b, c, d)
+#endif
+
+
+// The DAC EISA id and mask
+
+CONST UCHAR eisa_id[] = DAC_EISA_ID;
+CONST UCHAR eisa_mask[] = DAC_EISA_MASK;
+
+
+// Function declarations
+//
+// Functions that start with 'Dac960Nt' are entry points
+// for the OS port driver.
+// Functions that start with 'dachlp' are helper functions.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+);
+
+ULONG
+Dac960NtEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+);
+
+ULONG
+Dac960NtConfiguration(
+ IN PVOID DeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+);
+
+BOOLEAN
+Dac960NtInitialize(
+ IN PVOID DeviceExtension
+);
+
+BOOLEAN
+Dac960NtStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+BOOLEAN
+Dac960NtInterrupt(
+ IN PVOID DeviceExtension
+);
+
+BOOLEAN
+Dac960NtResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+);
+
+
+BOOLEAN
+dachlpDiskRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+);
+
+VOID
+dachlpSendMBOX(
+ IN PUCHAR EisaAddress,
+ IN PDAC_MBOX mbox
+);
+
+
+BOOLEAN
+dachlpContinueDiskRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG index,
+ IN BOOLEAN Start
+);
+
+BOOLEAN
+dachlpDiskRequestDone(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG index,
+ IN UCHAR Status
+);
+
+
+USHORT dachlpGetM16(PUCHAR p);
+ULONG dachlpGetM24(PUCHAR p);
+ULONG dachlpGetM32(PUCHAR p);
+void dachlpPutM16(PUCHAR p, USHORT s);
+void dachlpPutM24(PUCHAR p, ULONG l);
+void dachlpPutM32(PUCHAR p, ULONG l);
+void dachlpPutI16(PUCHAR p, USHORT s);
+void dachlpPutI32(PUCHAR p, ULONG l);
+ULONG dachlpSwapM32(ULONG l);
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+)
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ return Dac960NtEntry(DriverObject, Argument2);
+
+} // end DriverEntry()
+
+
+
+ULONG
+Dac960NtEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from DriverEntry if this driver is installable
+ or directly from the system if the driver is built into the kernel.
+ It scans the EISA slots looking for DAC960 host adapters.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ SCANCONTEXT context;
+
+
+
+ // Zero out structure.
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++)
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+
+ context.Slot = 0;
+ context.AdapterCount = 0;
+
+ // Set size of hwInitializationData.
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ // Set entry points.
+
+ hwInitializationData.HwInitialize = Dac960NtInitialize;
+ hwInitializationData.HwFindAdapter = Dac960NtConfiguration;
+ hwInitializationData.HwStartIo = Dac960NtStartIo;
+ hwInitializationData.HwInterrupt = Dac960NtInterrupt;
+ hwInitializationData.HwResetBus = Dac960NtResetBus;
+
+ // Set number of access ranges and bus type.
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ // Indicate no buffer mapping.
+ // Indicate will need physical addresses.
+
+ hwInitializationData.MapBuffers = TRUE; //FALSE;
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+
+ // Indicate auto request sense is supported.
+
+ hwInitializationData.AutoRequestSense = TRUE;
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+
+ // Specify size of extensions.
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ // Ask for SRB extensions.
+
+ hwInitializationData.SrbExtensionSize = 17*8 + 90;
+
+
+ return(ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &context));
+
+} // end Dac960NtEntry()
+
+
+
+ULONG
+Dac960NtConfiguration(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+)
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo - Configuration information structure describing HBA
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG eisaSlotNumber;
+ PUCHAR eisaAddress;
+ PSCANCONTEXT context = Context;
+ ULONG uniqueID;
+ ULONG length;
+ UCHAR abyte;
+ BOOLEAN found=FALSE;
+ BOOLEAN scsiThing=FALSE;
+ ULONG IrqLevel;
+ ULONG RangeStart, RangeLength;
+ DAC_MBOX mbox;
+ ULONG cnt;
+ UCHAR dbell, status, errcode;
+ PUCHAR charptr;
+ UCHAR i, j;
+ ULONG Bios_Base;
+
+
+ // Scan for DAC EISA id
+
+ for(eisaSlotNumber=context->Slot + 1; eisaSlotNumber<MAXIMUM_EISA_SLOTS; eisaSlotNumber++) {
+
+ // Update the slot count to indicate this slot has been checked.
+
+ context->Slot++;
+
+#if MYPRINT
+ deviceExtension->printAddr =
+ ScsiPortGetDeviceBase(
+ deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress((ULONG)0xb8000),
+ 0x1000,
+ (BOOLEAN) FALSE); // InIoSpace
+#endif
+
+ DebugPrint((1,"\n\nDAC960 Adaptor MiniPort Driver\n"));
+
+ // Get the system address for this card. The card uses I/O space.
+
+ eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x100,
+ TRUE);
+
+ // Look at EISA id
+
+ for(found=TRUE, i=0; i<EISA_ID_COUNT; i++) {
+ abyte = ScsiPortReadPortUchar(eisaAddress+EISA_ID_START+i);
+ if(((UCHAR)(abyte & eisa_mask[i])) != eisa_id[i] ) {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if(found) {
+ break;
+ }
+
+ // If an adapter was not found unmap it.
+
+ ScsiPortFreeDeviceBase(deviceExtension, eisaAddress);
+
+ } // end for (eisaSlotNumber ...
+
+
+ if(!found) {
+
+ // No adapter was found. Indicate that we are done and there
+ // are no more adaptors.
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ ScsiPortWritePortUchar(eisaAddress+BMIC_LOCAL_DB, 2);
+
+ for(i=0;i<MAX_WAIT_SECS;i++) {
+ if((ScsiPortReadPortUchar(eisaAddress+BMIC_LOCAL_DB) & 2) == 0)
+ break;
+
+ DELAY(1000);
+ }
+
+ status = ScsiPortReadPortUchar(eisaAddress+BMIC_MBOX+0x0e);
+ errcode = ScsiPortReadPortUchar(eisaAddress+BMIC_MBOX+0x0f);
+
+ if(i == MAX_WAIT_SECS) {
+
+ // Adapter timed out, so register error
+
+ status = HERR;
+ errcode = ERR;
+ }
+
+ // Log the error.
+
+ if((status == ABRT) && (errcode == ERR)) {
+ uniqueID = INSTL_ABRT;
+ }
+ else if((status == FWCHK) && (errcode == ERR)) {
+ uniqueID = INSTL_FWCK;
+ }
+ else if((status == HERR) && (errcode == ERR)) {
+ uniqueID = INSTL_HERR;
+ }
+ else
+ uniqueID = 0;
+
+ if(uniqueID) {
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ uniqueID
+ );
+
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+
+
+ deviceExtension->AdapterIndex = context->AdapterCount;
+ context->AdapterCount++;
+
+ if(context->AdapterCount < MAXLOGICALADAPTERS)
+ *Again = TRUE;
+ else
+ *Again = FALSE;
+
+
+ // There is still more to look at.
+ // Get the system interrupt vector and IRQL.
+
+ abyte = ScsiPortReadPortUchar(eisaAddress+EISA_INTR);
+ abyte &= 0x60;
+
+ switch(abyte) {
+
+ case 0:
+ IrqLevel=15;
+ break;
+
+ case 0x20:
+ IrqLevel=11;
+ break;
+
+ case 0x40:
+ IrqLevel=12;
+ break;
+
+ case 0x60:
+ IrqLevel=14;
+ break;
+ }
+
+
+ ConfigInfo->BusInterruptLevel = IrqLevel;
+
+
+ // Disable DAC interrupts
+
+ ScsiPortWritePortUchar(eisaAddress+BMIC_EISA_DB_ENABLE, 0);
+ ScsiPortWritePortUchar(eisaAddress+BMIC_SYSINTCTRL, 0);
+
+ // Indicate maximum transfer length in bytes.
+
+ ConfigInfo->MaximumTransferLength = 0xf000;
+
+ // Maximum number of physical segments is 16.
+
+ ConfigInfo->NumberOfPhysicalBreaks = 16;
+
+ // Fill in the access array information.
+
+ RangeStart = (0x1000 * eisaSlotNumber) + EISA_ADDRESS_BASE;
+ RangeLength = 0x100;
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(RangeStart);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = RangeLength;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->CachesData = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE; // Find out whether this costs
+
+
+ // Allocate a Noncached Extension to use for mail boxes.
+
+ deviceExtension->NoncachedExtension = ScsiPortGetUncachedExtension(
+ deviceExtension,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ if (deviceExtension->NoncachedExtension == NULL) {
+ return(SP_RETURN_ERROR);
+ }
+
+
+ // Get Physical Address of NoncachedExtension.
+
+ deviceExtension->NCE_PhyAddr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ deviceExtension->NoncachedExtension,
+ &length));
+
+ deviceExtension->EisaAddress = eisaAddress;
+
+ // Determine No of SCSI Channels supported by this adaptor
+
+
+ for(i = 0; i < MAXCHANNEL; i++) {
+
+ mbox.generalmbox.Byte0 = DAC_GETDEVST;
+ mbox.generalmbox.Byte1 = 0;
+ mbox.generalmbox.Byte2 = i;
+ mbox.generalmbox.Byte3 = 0;
+
+
+ (*((ULONG *) &mbox.generalmbox.Byte8)) = deviceExtension->NCE_PhyAddr + (PUCHAR)(& deviceExtension->NoncachedExtension->DevParms) - (PUCHAR)deviceExtension->NoncachedExtension;
+
+ dachlpSendMBOX(eisaAddress, &mbox);
+
+ for(cnt = 0; cnt < 0x10000; cnt++) {
+ dbell = ScsiPortReadPortUchar(eisaAddress+BMIC_EISA_DB);
+
+ if(dbell & 1) break;
+
+ ScsiPortStallExecution(100);
+ }
+
+ status = ScsiPortReadPortUchar(eisaAddress+BMIC_MBOX+0x0e);
+ errcode = ScsiPortReadPortUchar(eisaAddress+BMIC_MBOX+0x0f);
+
+ ScsiPortWritePortUchar(eisaAddress+BMIC_EISA_DB, dbell);
+ ScsiPortWritePortUchar(eisaAddress+BMIC_LOCAL_DB, 2);
+
+
+ if( (errcode << 8 | status) == 0x105) break;
+ }
+
+ // Store host adapter SCSI id
+
+ ConfigInfo->NumberOfBuses = i;
+ deviceExtension->MaxChannels = i;
+
+ for(j = 0; j < i; j++)
+ ConfigInfo->InitiatorBusId[j] = 7;
+
+
+
+ // Check for edge/level interrupt
+
+ mbox.dpmbox.Command = DAC_ENQ2;
+ mbox.dpmbox.Id = 0;
+ mbox.dpmbox.PhysAddr = deviceExtension->NCE_PhyAddr + (PUCHAR)(& deviceExtension->NoncachedExtension->DevParms) - (PUCHAR)deviceExtension->NoncachedExtension;
+
+ DebugPrint((1,"DAC: Sending ENQ2\n"));
+
+ dachlpSendMBOX(eisaAddress, &mbox);
+
+ // Poll the complete bit
+
+ for(cnt=0; cnt < 0x10000; cnt++) {
+ dbell = ScsiPortReadPortUchar(eisaAddress+BMIC_EISA_DB);
+
+ if(dbell & 1) break;
+
+ ScsiPortStallExecution(100);
+ }
+
+ DebugPrint((1,"DAC: ENQ2 Done\n"));
+
+ status = ScsiPortReadPortUchar(eisaAddress+BMIC_MBOX+0x0e);
+ errcode = ScsiPortReadPortUchar(eisaAddress+BMIC_MBOX+0x0f);
+
+ ScsiPortWritePortUchar(eisaAddress+BMIC_EISA_DB, dbell);
+ ScsiPortWritePortUchar(eisaAddress+BMIC_LOCAL_DB, 2);
+
+
+ if(status || errcode)
+ ConfigInfo->InterruptMode = LevelSensitive;
+ else {
+ charptr = (PUCHAR) &deviceExtension->NoncachedExtension;
+
+ if(charptr[ILFLAG] & BIT0)
+ ConfigInfo->InterruptMode = LevelSensitive;
+ else
+ ConfigInfo->InterruptMode = Latched;
+ }
+
+
+ deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0];
+
+// deviceExtension->ShutDown = FALSE;
+
+
+ // Setup our private control structures
+
+ deviceExtension->PendingSrb = NULL;
+ deviceExtension->PendingNDSrb = NULL;
+ deviceExtension->NDPending = 0;
+ deviceExtension->ActiveCmds = 0;
+
+ for(i = 0; i < DAC_MAX_IOCMDS; i++) {
+ deviceExtension->ActiveSrb[i] = NULL;
+ }
+
+ deviceExtension->Kicked = FALSE;
+ deviceExtension->ActiveScsiSrb = NULL;
+
+ return SP_RETURN_FOUND;
+
+} // end Dac960NtConfiguration()
+
+
+
+
+BOOLEAN
+Dac960NtInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION NoncachedExtension;
+ PUCHAR EisaAddress;
+ DAC_MBOX mbox;
+ PDAC_DPT dpt;
+ ULONG i, cnt, length, unit, target, cyls, hds, spt;
+ UCHAR dbell, status, errcode;
+ PDIRECT_CDB dacdcdb;
+ int channel;
+
+
+
+ NoncachedExtension = deviceExtension->NoncachedExtension;
+ EisaAddress = deviceExtension->EisaAddress;
+
+
+ // Disable DAC interrupts
+
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB_ENABLE, 0);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_SYSINTCTRL, 0);
+
+
+ // Scan for devices
+ // Preset end mark in case DAC does not respond
+
+ dpt = & NoncachedExtension->DevParms;
+ dpt->No_Drives = 0;
+
+ // Setup mailbox
+
+ mbox.dpmbox.Command = DAC_ENQUIRE;
+ mbox.dpmbox.Id = 0;
+ mbox.dpmbox.PhysAddr = deviceExtension->NCE_PhyAddr;
+
+ DebugPrint((1,"DAC: Sending ENQUIRE\n"));
+
+ dachlpSendMBOX(EisaAddress, &mbox);
+
+ // Poll the complete bit
+
+ for(cnt=0; cnt < 0x10000; cnt++) {
+
+ dbell = ScsiPortReadPortUchar(EisaAddress+BMIC_EISA_DB);
+ if(dbell & 1) break;
+
+ ScsiPortStallExecution(100);
+ }
+
+ DebugPrint((1,"DAC: ENQUIRE Done\n"));
+
+ status = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+0x0e);
+ errcode = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+0x0f);
+
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB, dbell);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_LOCAL_DB, 2);
+
+
+ deviceExtension->MaxCmds = dpt->max_io_cmds;
+ deviceExtension->No_SysDrives = dpt->No_Drives;
+
+
+ // Now check for Non-Disk devices
+
+ dacdcdb = (PDIRECT_CDB)NoncachedExtension->Buffer;
+
+
+ mbox.dpmbox.PhysAddr = deviceExtension->NCE_PhyAddr + (NoncachedExtension->Buffer - (PUCHAR)NoncachedExtension);
+
+ dacdcdb->ptr = mbox.dpmbox.PhysAddr + DATA_OFFSET;
+
+ mbox.dpmbox.Command = DAC_DCDB;
+ dacdcdb->cdb_len = 6;
+ dacdcdb->sense_len = 0;
+ dacdcdb->dir = 0x80 + DAC_IN;
+ dacdcdb->cdb[0] = 0x12;
+ dacdcdb->cdb[1] = 0;
+ dacdcdb->cdb[2] = 0;
+ dacdcdb->cdb[3] = 0;
+ dacdcdb->cdb[4] = 0x30;
+ dacdcdb->cdb[5] = 0;
+
+ for(target = 0; target < MAXTARGET; target++) {
+ deviceExtension->ND_DevMap[target] = 0xff;
+ }
+
+ for(channel = 0; channel < deviceExtension->MaxChannels; channel++)
+ for(target = 1; target < MAXTARGET; target++) {
+
+ if(deviceExtension->ND_DevMap[target] != 0xff) continue;
+
+ NoncachedExtension->Buffer[DATA_OFFSET]=0; //Just in case
+
+ dacdcdb->byte_cnt = 0x30;
+ dacdcdb->device = (channel << 4) | target;
+
+ dachlpSendMBOX(EisaAddress, &mbox);
+
+ // Poll the complete bit
+
+ for(cnt=0; cnt < 0x10000; cnt++) {
+ dbell = ScsiPortReadPortUchar(EisaAddress+BMIC_EISA_DB);
+
+ if(dbell & 1) break;
+
+ ScsiPortStallExecution(100);
+ }
+
+ status = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+0x0e);
+ errcode = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+0x0f);
+
+ if((status == 0) && (errcode == 0) && NoncachedExtension->Buffer[DATA_OFFSET]) {
+ deviceExtension->ND_DevMap[target] = channel;
+ }
+
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB, dbell);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_LOCAL_DB, 2);
+ }
+
+
+ // Enable DAC interrupts
+
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB_ENABLE, 1);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_SYSINTCTRL, BMIC_SIC_ENABLE);
+
+
+ return(TRUE);
+
+} // end Dac960NtInitialize()
+
+
+BOOLEAN
+Dac960NtStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to start a request
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ ULONG i = 0;
+ BOOLEAN status;
+ PUCHAR dptr;
+
+ switch(Srb->Function) {
+
+ case SRB_FUNCTION_SHUTDOWN:
+ // deviceExtension->ShutDown = TRUE;
+
+ case SRB_FUNCTION_FLUSH:
+
+ // DELAY(1000);
+
+ case SRB_FUNCTION_IO_CONTROL:
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ status = dachlpDiskRequest(deviceExtension, Srb);
+
+ if(status == FALSE) {
+
+ PSCSI_REQUEST_BLOCK pnextsrb, *ptr;
+
+ // Queue it up in t he right queue.
+
+ if(Srb->Function != SRB_FUNCTION_IO_CONTROL) {
+ if(Srb->TargetId)
+ {
+ // Save the request until a pending one completes.
+
+ if(deviceExtension->PendingNDSrb != NULL) {
+ pnextsrb = deviceExtension->PendingNDSrb;
+ deviceExtension->PendingNDSrb = Srb;
+ ptr=(PSCSI_REQUEST_BLOCK *)Srb->SrbExtension;
+ *ptr=pnextsrb;
+ }
+ else {
+ // Put this request on queue
+
+ deviceExtension->PendingNDSrb = Srb;
+ ptr=(PSCSI_REQUEST_BLOCK *)Srb->SrbExtension;
+ *ptr=(PSCSI_REQUEST_BLOCK)0l;
+ }
+ }
+ else
+ {
+ // Save the request until a pending one completes.
+ if(deviceExtension->PendingSrb != NULL) {
+ pnextsrb=deviceExtension->PendingSrb;
+ deviceExtension->PendingSrb=Srb;
+ ptr=(PSCSI_REQUEST_BLOCK *)Srb->SrbExtension;
+ *ptr=pnextsrb;
+ }
+ else {
+ // Put this request on queue
+ deviceExtension->PendingSrb = Srb;
+ ptr=(PSCSI_REQUEST_BLOCK *)Srb->SrbExtension;
+ *ptr=(PSCSI_REQUEST_BLOCK)0l;
+ }
+ }
+ }
+ else {
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ }
+
+ return(TRUE);
+ }
+
+ // Adapter ready for next request.
+
+ if(Srb->Function != SRB_FUNCTION_IO_CONTROL)
+ {
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ }
+ else
+ {
+ ScsiPortNotification(NextRequest,
+ deviceExtension);
+
+ }
+
+ return(TRUE);
+
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ // Abort request completed with error
+
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ // Adapter ready for next request.
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ return(TRUE);
+
+
+ case SRB_FUNCTION_RESET_BUS:
+ default:
+
+ // Set error, complete request
+ // and signal ready for next request.
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ return(TRUE);
+
+ } // end switch
+
+} // end Dac960NtStartIo()
+
+
+
+
+BOOLEAN
+Dac960NtInterrupt(
+ IN PVOID HwDeviceExtension
+)
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the DAC960 SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if we handled the interrupt
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PUCHAR EisaAddress;
+ ULONG index;
+ UCHAR interruptStatus;
+ UCHAR status;
+ UCHAR errcode;
+
+ PSCSI_REQUEST_BLOCK Srb;
+
+
+ EisaAddress = deviceExtension->EisaAddress;
+
+
+
+ //
+ // Check interrupt pending.
+ //
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB_ENABLE, 0);
+ interruptStatus = ScsiPortReadPortUchar(EisaAddress+BMIC_EISA_DB);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB, interruptStatus);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_EISA_DB_ENABLE, 1);
+ if(!(interruptStatus & 1)) {
+ return FALSE;
+ }
+
+
+ //
+ // Read interrupt status from BMIC and acknowledge
+ //
+ //
+// interruptStatus = ScsiPortReadPortUchar(EisaAddress+BMIC_EISA_DB);
+
+ status = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+0x0e);
+ errcode = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+0x0f);
+
+
+ //
+ // TAGTAG Add tagging support here: find
+ // index of RCB for interrupting request
+ //
+ index = ScsiPortReadPortUchar(EisaAddress+BMIC_MBOX+0x0d);
+ ScsiPortWritePortUchar(EisaAddress+BMIC_LOCAL_DB, 2);
+
+
+/*
+ // Check...
+ if(deviceExtension->ActiveCmds<=0) {
+ // No one there interrupting us
+ return(TRUE);
+ }
+*/
+
+
+
+
+ //
+ // Check whether this SRB is actually running
+ //
+ if(deviceExtension->ActiveSrb[index] == NULL) {
+ // No one there interrupting us, again
+ return(TRUE);
+ }
+ Srb=deviceExtension->ActiveSrb[index];
+
+
+ // Update DAC status fields in RCB
+ deviceExtension->ActiveRcb[index].DacStatus = status;
+ deviceExtension->ActiveRcb[index].DacErrcode = errcode;
+
+
+ // Continue or finish the interrupting SRB request
+ dachlpContinueDiskRequest(deviceExtension, index, FALSE);
+
+
+ if(deviceExtension->ActiveCmds < deviceExtension->MaxCmds) {
+ // A request slot is free now
+ // Check for pending non_disk requests.
+ // If there is one then start it now.
+
+ if((deviceExtension->NDPending==0) && (deviceExtension->PendingNDSrb != NULL)) {
+ PSCSI_REQUEST_BLOCK anotherSrb,*ptr;
+
+ anotherSrb = deviceExtension->PendingNDSrb;
+ ptr=(PSCSI_REQUEST_BLOCK *)anotherSrb->SrbExtension;
+ deviceExtension->PendingNDSrb = *ptr;
+ Dac960NtStartIo(deviceExtension, anotherSrb);
+ }
+ }
+ if(deviceExtension->ActiveCmds < deviceExtension->MaxCmds) {
+ // A request slot is free now
+ // Check for pending requests.
+ // If there is one then start it now.
+
+ if(deviceExtension->PendingSrb != NULL) {
+ PSCSI_REQUEST_BLOCK anotherSrb,*ptr;
+
+ anotherSrb = deviceExtension->PendingSrb;
+ ptr=(PSCSI_REQUEST_BLOCK *)anotherSrb->SrbExtension;
+ deviceExtension->PendingSrb = *ptr;
+ Dac960NtStartIo(deviceExtension, anotherSrb);
+ }
+ }
+
+ // Definitely was our interrupt...
+ return TRUE;
+
+} // end Dac960NtInterrupt()
+
+
+
+
+BOOLEAN
+dachlpDiskRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+)
+
+/*++
+
+Routine Description:
+
+ Build disk request from SRB and send it to the DAC
+
+Arguments:
+
+ DeviceExtension
+ SRB
+
+Return Value:
+
+ TRUE if command was started
+ FALSE if host adapter is busy
+
+--*/
+{
+ ULONG index;
+ PRCB rcb;
+ ULONG blocks=0, blockAddr=0;
+ UCHAR Target;
+ UCHAR DacCommand;
+ ULONG lsize;
+ PUCHAR pbyte;
+ int i;
+
+ if(Srb->Function == SRB_FUNCTION_IO_CONTROL)
+ {
+ pbyte = (PUCHAR) Srb->DataBuffer;
+
+ if(pbyte[sizeof(SRB_IO_CONTROL) + 0x10] == 0x99) // INP function.
+ {
+ USHORT port;
+ PUCHAR lport;
+
+ pbyte[sizeof(SRB_IO_CONTROL) + 4] = 0;
+ pbyte[sizeof(SRB_IO_CONTROL) + 5] = 0;
+
+ port=((USHORT)(pbyte[sizeof(SRB_IO_CONTROL)+0x12]) << 8) +\
+ (pbyte[sizeof(SRB_IO_CONTROL)+0x13]& 0xff);
+
+ lport=(PUCHAR)deviceExtension->EisaAddress + (port & 0x0fff);
+
+ pbyte[sizeof(SRB_IO_CONTROL) + 0x10]=ScsiPortReadPortUchar(lport);
+
+ Srb->ScsiStatus = SCSISTAT_GOOD;
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+
+ DacCommand = DAC_DCMD;
+ blocks = 0; // Actual length filled in later.
+
+ goto give_command;
+ }
+
+
+ if(Srb->TargetId) {
+
+ if(Srb->Lun != 0) {
+
+ // For Non-Disk Devices, LUN is not supported
+
+ // Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+
+ if(deviceExtension->ND_DevMap[Srb->TargetId] == 0xff) {
+
+ // We didn't see this Target Device.
+
+ // Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+
+ if(Srb->PathId != deviceExtension->ND_DevMap[Srb->TargetId]) {
+ // Target is not present on this channel.
+
+ // Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+ }
+ else if(Srb->PathId != 0) {
+ // System Drives are Mapped to
+ // Channel: 0, Target Id: 0, Lun: 0-7
+
+
+ // Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+ else if(Srb->Lun >= deviceExtension->No_SysDrives) {
+ // Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+
+ if(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
+
+ PUCHAR dptr;
+
+ DebugPrint((2,"DAC: command= %x\n",Srb->Cdb[0]));
+
+ if(Srb->TargetId)
+ {
+ DacCommand = DAC_DCDB;
+ blocks = 0; // Actual length filled in later.
+
+ goto give_command;
+ }
+
+ switch(Srb->Cdb[0]) {
+
+ case SCSIOP_READ:
+
+ DacCommand = DAC_LREAD;
+ blocks = (ULONG)dachlpGetM16(&Srb->Cdb[7]);
+ blockAddr = dachlpGetM32(&Srb->Cdb[2]);
+
+ break;
+
+ case SCSIOP_WRITE:
+ case SCSIOP_WRITE_VERIFY:
+
+ DacCommand = DAC_LWRITE;
+ blocks = (ULONG)dachlpGetM16(&Srb->Cdb[7]);
+ blockAddr = dachlpGetM32(&Srb->Cdb[2]);
+
+ break;
+
+ case SCSIOP_READ6:
+
+ DacCommand = DAC_LREAD;
+ blocks = (ULONG)Srb->Cdb[4];
+ blockAddr = dachlpGetM24(&Srb->Cdb[1]) & 0x1fffff;
+
+ break;
+
+ case SCSIOP_WRITE6:
+
+ DacCommand = DAC_LWRITE;
+ blocks = (ULONG)Srb->Cdb[4];
+ blockAddr = dachlpGetM24(&Srb->Cdb[1]) & 0x1fffff;
+
+ break;
+
+ case SCSIOP_REQUEST_SENSE:
+ break;
+
+ case SCSIOP_READ_CAPACITY:
+
+ if(Srb->Lun < deviceExtension->No_SysDrives) {
+
+ dptr = Srb->DataBuffer;
+ lsize = deviceExtension->NoncachedExtension->DevParms.Size[Srb->Lun];
+
+ lsize--;
+ pbyte=(UCHAR *)&lsize;
+
+ dptr[0] = pbyte[3];
+ dptr[1] = pbyte[2];
+ dptr[2] = pbyte[1];
+ dptr[3] = pbyte[0];
+ dptr[4] = 0;
+ dptr[5] = 0;
+ dptr[6] = 2;
+ dptr[7] = 0;
+
+ DebugPrint((1,"DAC RDCAP: %x,%x,%x,%x\n",dptr[0],dptr[1],dptr[2],dptr[3]));
+
+ // Complete
+ Srb->ScsiStatus = SCSISTAT_GOOD;
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+ else
+ {
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ // Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+
+ case SCSIOP_INQUIRY:
+
+ if(Srb->Lun < deviceExtension->No_SysDrives) {
+ if(Srb->DataTransferLength > 35)
+ {
+ dptr = Srb->DataBuffer;
+ dptr[0] = 0;
+ dptr[1] = 0;
+ dptr[2] = 1;
+ dptr[3] = 0;
+ dptr[4] = 0x20;
+ dptr[5] = 0;
+ dptr[6] = 0;
+ dptr[7] = 0;
+ dptr[8] = 'M';
+ dptr[9] = 'Y';
+ dptr[10] = 'L';
+ dptr[11] = 'E';
+ dptr[12] = 'X';
+
+ for(i = 13; i < 36; i++)
+ dptr[i] = ' ';
+
+ }
+ else ;
+ }
+ else
+ {
+/*
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+*/
+ // Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+
+ case SCSIOP_TEST_UNIT_READY:
+ case SCSIOP_REZERO_UNIT:
+ case SCSIOP_SEEK6:
+ case SCSIOP_VERIFY6:
+ case SCSIOP_RESERVE_UNIT:
+ case SCSIOP_RELEASE_UNIT:
+ case SCSIOP_SEEK:
+ case SCSIOP_VERIFY:
+
+ // Complete
+
+ Srb->ScsiStatus = SCSISTAT_GOOD;
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+
+ case SCSIOP_FORMAT_UNIT:
+ default:
+
+ // Unknown request
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ return(TRUE);
+ }
+
+ }
+ else {
+ // can only be flush
+
+ DacCommand = DAC_FLUSH;
+ blocks = 0;
+ }
+
+give_command:
+
+ // Check for request slot availability
+
+ if(deviceExtension->ActiveCmds >= deviceExtension->MaxCmds) {
+ return(FALSE);
+ }
+
+ // If Non_Disk fire it only if no Non_Disk is pending.
+
+ if(Srb->Function != SRB_FUNCTION_IO_CONTROL)
+ if(Srb->TargetId)
+ {
+ if(deviceExtension->NDPending) return (FALSE);
+
+ deviceExtension->NDPending++;
+ }
+
+ // Put this SRB on queue
+ // TAGTAG Add tag support here
+
+ for(index = 0; index < DAC_MAX_IOCMDS; index++)
+ if(deviceExtension->ActiveSrb[index] == NULL) break;
+
+
+ deviceExtension->ActiveCmds++;
+ deviceExtension->ActiveSrb[index] = Srb;
+
+ rcb = &deviceExtension->ActiveRcb[index];
+ rcb->DacCommand = DacCommand;
+
+ rcb->VirtualTransferAddress = (PUCHAR)(Srb->DataBuffer);
+ rcb->BlockAddress = blockAddr;
+
+ if(blocks !=0 )
+ rcb->BytesToGo = blocks*512;
+ else
+ rcb->BytesToGo = Srb->DataTransferLength;
+
+ // Start command
+ dachlpContinueDiskRequest(deviceExtension, index, TRUE);
+
+ return(TRUE);
+}
+
+
+VOID
+dachlpSendMBOX(
+ IN PUCHAR EisaAddress,
+ IN PDAC_MBOX mbox
+ )
+
+/*++
+
+Routine Description:
+
+ Start up conventional DAC command
+
+Arguments:
+
+ Eisa base IO address
+ DAC mailbox
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PUCHAR ptr;
+ ULONG i;
+
+
+ ptr = (PUCHAR)mbox;
+ // DebugPrint((1,"DAC: cmdwait .... "));
+ while(ScsiPortReadPortUchar(EisaAddress+BMIC_LOCAL_DB) & 1)
+ ScsiPortStallExecution(100);
+ // DebugPrint((1,"DAC: cmddone\n"));
+ for(i=0; i<13; i++)
+ ScsiPortWritePortUchar(EisaAddress+BMIC_MBOX+i, ptr[i]);
+
+ // Kick butt
+ ScsiPortWritePortUchar(EisaAddress+BMIC_LOCAL_DB, 1);
+}
+
+
+
+
+BOOLEAN
+Dac960NtResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Dac960Nt SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+
+ //
+ // Complete all outstanding requests.
+ //
+ ScsiPortCompleteRequest(deviceExtension,
+ 0,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ return TRUE;
+
+} // end Dac960NtResetBus()
+
+
+
+//
+// Disk Request Done
+// Dequeue, set status, notify Miniport layer
+// Always returns TRUE (slot freed)
+//
+BOOLEAN
+dachlpDiskRequestDone(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG index,
+ IN UCHAR Status
+ )
+{
+ PSCSI_REQUEST_BLOCK srb;
+
+
+
+ srb = deviceExtension->ActiveSrb[index];
+
+ // Set status
+ srb->SrbStatus = Status;
+
+ // This SRB is through
+ deviceExtension->ActiveSrb[index] = NULL;
+ deviceExtension->ActiveCmds--;
+
+ // Call notification routine for the SRB.
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ return(TRUE);
+}
+
+
+
+// Word order functions
+
+USHORT dachlpGetM16(PUCHAR p)
+{
+ USHORT s;
+ PUCHAR sp=(PUCHAR)&s;
+
+ sp[0] = p[1];
+ sp[1] = p[0];
+ return(s);
+}
+
+ULONG dachlpGetM24(PUCHAR p)
+{
+ ULONG l;
+ PUCHAR lp=(PUCHAR)&l;
+
+ lp[0] = p[2];
+ lp[1] = p[1];
+ lp[2] = p[0];
+ lp[3] = 0;
+ return(l);
+}
+
+ULONG dachlpGetM32(PUCHAR p)
+{
+ ULONG l;
+ PUCHAR lp=(PUCHAR)&l;
+
+ lp[0] = p[3];
+ lp[1] = p[2];
+ lp[2] = p[1];
+ lp[3] = p[0];
+ return(l);
+}
+
+void dachlpPutM16(PUCHAR p, USHORT s)
+{
+ PUCHAR sp=(PUCHAR)&s;
+
+ p[0] = sp[1];
+ p[1] = sp[0];
+}
+
+void dachlpPutM24(PUCHAR p, ULONG l)
+{
+ PUCHAR lp=(PUCHAR)&l;
+
+ p[0] = lp[2];
+ p[1] = lp[1];
+ p[2] = lp[0];
+}
+
+void dachlpPutM32(PUCHAR p, ULONG l)
+{
+ PUCHAR lp=(PUCHAR)&l;
+
+ p[0] = lp[3];
+ p[1] = lp[2];
+ p[2] = lp[1];
+ p[3] = lp[0];
+}
+
+void dachlpPutI16(PUCHAR p, USHORT s)
+{
+ PUCHAR sp=(PUCHAR)&s;
+
+ p[0] = sp[0];
+ p[1] = sp[1];
+}
+
+void dachlpPutI32(PUCHAR p, ULONG l)
+{
+ PUCHAR lp=(PUCHAR)&l;
+
+ p[0] = lp[0];
+ p[1] = lp[1];
+ p[2] = lp[2];
+ p[3] = lp[3];
+}
+
+ULONG dachlpSwapM32(ULONG l)
+{
+ ULONG lres;
+ PUCHAR lp=(PUCHAR)&l;
+ PUCHAR lpres=(PUCHAR)&lres;
+
+ lpres[0] = lp[3];
+ lpres[1] = lp[2];
+ lpres[2] = lp[1];
+ lpres[3] = lp[0];
+
+ return(lres);
+}
+/*
+** Continue disk request
+** Return TRUE if a request slot became available
+** FALSE if not
+*/
+BOOLEAN
+dachlpContinueDiskRequest(
+ IN PHW_DEVICE_EXTENSION deviceExtension,
+ IN ULONG index,
+ IN BOOLEAN Start
+)
+
+{
+ PVOID dataPointer;
+ ULONG bytesLeft;
+ PSGL sgl;
+ ULONG descriptorCount = 0;
+ PDIRECT_CDB dacdcdb;
+ PUCHAR sptr;
+ PRCB rcb;
+ PSCSI_REQUEST_BLOCK srb;
+ PNONCACHED_EXTENSION nce;
+ DAC_MBOX mbox;
+ ULONG physAddr;
+ ULONG length, blocks, bytes;
+ PUCHAR EisaAddress;
+ ULONG i;
+
+ EisaAddress = deviceExtension->EisaAddress;
+ rcb = &deviceExtension->ActiveRcb[index];
+ srb = deviceExtension->ActiveSrb[index];
+ nce = deviceExtension->NoncachedExtension;
+ bytes = 0;
+
+ dacdcdb=(PDIRECT_CDB)nce->Buffer;
+
+ sgl = srb->SrbExtension;
+
+ if(Start == FALSE) {
+ // DAC interrupt time call. Determine status of last DAC request
+
+ DebugPrint((2,"DAC: Contreq;Start=False"));
+
+
+ if(srb->Function == SRB_FUNCTION_IO_CONTROL)
+ {
+ UCHAR * dptr;
+
+ dptr=(UCHAR *)srb->DataBuffer;
+ dptr[sizeof (SRB_IO_CONTROL) + 4] = rcb->DacStatus;
+ dptr[sizeof (SRB_IO_CONTROL) + 5] = rcb->DacErrcode;
+
+ // We're actually done here !
+ // Update SCSI status.
+
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ // Finish
+ dachlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_SUCCESS);
+ return TRUE;
+
+ }
+
+ if(srb->TargetId) {
+ deviceExtension->NDPending--;
+ }
+
+ if(rcb->DacErrcode | rcb->DacStatus)
+ {
+ if(srb->Function != SRB_FUNCTION_IO_CONTROL)
+ if(srb->TargetId == 0)
+ {
+ // The DAC detected an error
+ dachlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_TIMEOUT);
+
+ // Slot free
+ return(TRUE);
+ }
+ else
+ {
+ // Set target SCSI status in SRB.
+
+ if(rcb->DacStatus == 0x02)
+ srb->ScsiStatus = 0x02; // CheckCondition
+ else
+ srb->ScsiStatus = dacdcdb->status;
+
+ if (dacdcdb->sense_len) {
+ int i;
+ char *senseptr;
+
+ senseptr=(char *)srb->SenseInfoBuffer;
+
+ // Indicate the sense information is valid and
+ // update the length.
+
+ for(i = 0; i < dacdcdb->sense_len; i++)
+ senseptr[i] = dacdcdb->sense[i];
+
+ srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ srb->SenseInfoBufferLength = dacdcdb->sense_len;
+ }
+
+ // The DAC detected an error
+ dachlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_ERROR);
+
+ // Slot free
+ return(TRUE);
+ }
+ }
+
+ // We're actually done here !
+ // Update SCSI status.
+ // $$$ can we manipulate this for non SCSI requests ?
+
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ // Finish
+ DebugPrint((2,"DAC: Success\n"));
+
+ dachlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_SUCCESS);
+
+ return TRUE;
+ }
+ else {
+ DebugPrint((2,"DAC:Cont;Start=TRUE\n"));
+
+ if((rcb->BytesToGo) && ((rcb->DacCommand == DAC_LREAD) || (rcb->DacCommand == DAC_LWRITE) || (rcb->DacCommand == DAC_DCDB))) {
+
+ // We want to transfer some data, get the physical address
+
+ dataPointer=rcb->VirtualTransferAddress,
+ bytesLeft = rcb->BytesToGo;
+
+ if(bytesLeft > 0xf000)
+ DebugPrint((1,"DAC: bytesleft = %ld\n",bytesLeft));
+
+ do {
+
+ // Get physical address and length of contiguous physical buffer.
+
+ physAddr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((2, "DAC960: SGL Physical address %lx\n", physAddr));
+ DebugPrint((2, "DAC960: SGL Data length %lx\n", length));
+ DebugPrint((2, "DAC960: SGL Bytes left %lx\n", bytesLeft));
+
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+
+ if(length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ if(length > 0xf000)
+ DebugPrint((1,"DAC: length=%ld\n",length));
+
+ sgl->Descriptor[descriptorCount].Address = physAddr;
+ sgl->Descriptor[descriptorCount].Length = length;
+
+ // Adjust counts.
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ // Get physical SGL address.
+
+ physAddr = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL,
+ sgl, &length));
+
+ // Assume physical memory contiguous for sizeof(SGL) bytes.
+
+ ASSERT(length >= sizeof(SGL));
+
+ // Create SGL segment descriptors.
+
+
+ if(rcb->DacCommand==DAC_LREAD || rcb->DacCommand==DAC_LWRITE || rcb->DacCommand == DAC_DCDB) {
+
+ // Disk read/write: get number of blocks
+
+ bytes=rcb->BytesToGo;
+ blocks=bytes/512;
+ bytes = blocks*512;
+ }
+ else {
+ // Not a scatter-gather type operation
+
+ if(bytes != rcb->BytesToGo) {
+ dachlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_PARITY_ERROR);
+ return(TRUE);
+ }
+ }
+ }
+ else {
+ // We don't have data to transfer
+ bytes = 0;
+ blocks = 0;
+ }
+
+
+ // Now look at the specific DAC command
+
+ switch(rcb->DacCommand) {
+
+ case DAC_LREAD:
+ case DAC_LWRITE:
+ if(blocks==0) {
+ // Cancel this command with some garbage error code
+ dachlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_PARITY_ERROR);
+ return(TRUE);
+ }
+
+ // Transfer data
+
+ mbox.iombox.Command = rcb->DacCommand | 0x80;
+ mbox.iombox.Id = index;
+ mbox.iombox.Reserved1 = 0;
+ mbox.iombox.SectorCount = (USHORT)blocks;
+ mbox.iombox.PhysAddr = physAddr;
+ mbox.iombox.Block = rcb->BlockAddress;
+
+ /* Support for 32G */
+
+ mbox.generalmbox.Byte3 = ((rcb->BlockAddress) >> (24-6)) & 0xc0;
+ mbox.generalmbox.Byte7 = srb->Lun;
+
+ mbox.generalmbox.Bytec = descriptorCount;
+
+ if(descriptorCount > 17)
+ DebugPrint((1,"DAC: SGcount =%d\n",descriptorCount));
+
+ break;
+
+ case DAC_DCDB:
+
+ dacdcdb->device = (deviceExtension->ND_DevMap[srb->TargetId] << 4) + srb->TargetId;
+
+ dacdcdb->dir = 0x80;
+
+ if(srb->SrbFlags & SRB_FLAGS_DATA_IN)
+ dacdcdb->dir |= DAC_IN;
+ else if(srb->SrbFlags & SRB_FLAGS_DATA_OUT)
+ dacdcdb->dir |= DAC_OUT;
+
+ dacdcdb->sense_len= srb->SenseInfoBufferLength;
+ dacdcdb->cdb_len = srb->CdbLength;
+ dacdcdb->byte_cnt = (USHORT)(srb->DataTransferLength);
+
+ for(i = 0; i < srb->CdbLength; i++)
+ dacdcdb->cdb[i]=srb->Cdb[i];
+
+ if (srb->SenseInfoBufferLength != 0 &&
+ !(srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)) {
+ dacdcdb->dir |= DAC_NO_AUTOSENSE;
+ dacdcdb->sense_len=0;
+ }
+
+ if(dacdcdb->dir & 0x03) /* if data xfer involved */
+ mbox.iombox.Command = rcb->DacCommand | 0x80;
+ else
+ mbox.iombox.Command = rcb->DacCommand;
+
+ mbox.iombox.Id = index;
+ mbox.iombox.Reserved1 = 0;
+
+ dacdcdb->ptr = physAddr;
+ mbox.iombox.PhysAddr = deviceExtension->NCE_PhyAddr + (nce->Buffer - (PUCHAR) nce);
+ mbox.generalmbox.Bytec = descriptorCount;
+
+ if(descriptorCount > 17)
+ DebugPrint((1,"DAC: SGcount =%d\n",descriptorCount));
+
+ break;
+
+ default:
+
+ // Cancel this command with some garbage error code
+ dachlpDiskRequestDone(deviceExtension, index,
+ SRB_STATUS_PARITY_ERROR);
+
+ return(TRUE);
+
+ case DAC_DCMD:
+
+ sptr = (PUCHAR)srb->DataBuffer+ sizeof(SRB_IO_CONTROL)+ 0x10;
+
+ if(sptr[0] != 0x04) // Not a Direct CDB via IOCTL
+ {
+ mbox.iombox.Command = sptr[0];
+ mbox.iombox.Id = index;
+ mbox.generalmbox.Byte2 = sptr[2];
+ mbox.generalmbox.Byte3 = sptr[3];
+ mbox.generalmbox.Byte4 = sptr[4];
+ mbox.generalmbox.Byte5 = sptr[5];
+ mbox.generalmbox.Byte6 = sptr[6];
+ mbox.generalmbox.Byte7 = sptr[7];
+ sptr += 0x10;
+
+ physAddr = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ srb, srb->DataBuffer, &length));
+
+ mbox.iombox.PhysAddr = physAddr + sizeof(SRB_IO_CONTROL) \
+ + 0x10 + 0x10;
+ }
+ else
+ {
+ mbox.iombox.Command = sptr[0];
+ mbox.iombox.Id = index;
+ sptr += 0x10;
+
+ physAddr = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, srb,
+ srb->DataBuffer, &length));
+
+ mbox.iombox.PhysAddr = physAddr + 0x10;
+
+ dacdcdb = (PDIRECT_CDB)sptr;
+ dacdcdb->ptr = physAddr + 0x10 + 100;
+ }
+ break;
+
+ case DAC_FLUSH:
+ // Flush buffers
+ mbox.iombox.Command = DAC_FLUSH;
+ mbox.iombox.Id = index;
+
+ // In case we get here for a post-flush,
+ // set variables so we're done next time
+ rcb->BytesToGo = 0;
+ bytes = 0;
+ blocks = 0;
+ break;
+
+ }
+
+ // Fire command
+
+ dachlpSendMBOX(EisaAddress, &mbox);
+
+
+ // No SRB slot freed
+
+ return(FALSE);
+ }
+}
+
+#if MYPRINT
+//
+// The monochrome screen printf() helpers start here
+//
+VOID dachlpPutchar(PUSHORT BaseAddr, UCHAR c)
+{
+ BOOLEAN newline=FALSE;
+ USHORT s;
+ ULONG i;
+
+
+ if(c=='\r') {
+ dachlpColumn = 0;
+ }
+ else if(c=='\n') {
+ newline=TRUE;
+ }
+ else if(c=='\b') {
+ if(dachlpColumn)
+ dachlpColumn--;
+ return;
+ }
+ else {
+ if(c==9) c==' ';
+ ScsiPortWriteRegisterUshort(
+ BaseAddr+80*24+dachlpColumn, (USHORT)(((USHORT)c)|0xF00));
+ if(++dachlpColumn >= 80)
+ newline=TRUE;
+ }
+
+ if(newline) {
+ for(i=0; i<80*24; i++) {
+ s = ScsiPortReadRegisterUshort(BaseAddr+80+i);
+ ScsiPortWriteRegisterUshort(BaseAddr+i, s);
+ }
+ for(i=0; i<80; i++)
+ ScsiPortWriteRegisterUshort(BaseAddr+80*24+i, 0x720);
+ dachlpColumn = 0;
+ }
+}
+
+
+VOID dachlpPrintHex(PUSHORT BaseAddr, ULONG v, ULONG len)
+{
+ ULONG shift;
+ ULONG nibble;
+
+ len *= 2;
+ shift = len*4;
+ while(len--) {
+ shift -= 4;
+ nibble = (v>>shift) & 0xF;
+ dachlpPutchar(BaseAddr, dachlpHex[nibble]);
+ }
+}
+
+
+VOID dachlpPrintf(PHW_DEVICE_EXTENSION deviceExtension,
+ PUCHAR fmt,
+ ULONG a1,
+ ULONG a2,
+ ULONG a3,
+ ULONG a4)
+{
+
+ if(deviceExtension->printAddr == 0)
+ return;
+
+ while(*fmt) {
+
+ if(*fmt=='%') {
+ fmt++;
+ switch(*fmt) {
+ case 0:
+ fmt--;
+ break;
+ case 'b':
+ dachlpPrintHex(deviceExtension->printAddr, a1, 1);
+ break;
+ case 'w':
+ dachlpPrintHex(deviceExtension->printAddr, a1, 2);
+ break;
+ case 'p':
+ dachlpPrintHex(deviceExtension->printAddr, a1, 3);
+ break;
+ case 'd':
+ dachlpPrintHex(deviceExtension->printAddr, a1, 4);
+ break;
+ default:
+ dachlpPutchar(deviceExtension->printAddr, '?');
+ break;
+ }
+ fmt++;
+ a1 = a2;
+ a2 = a3;
+ a3 = a4;
+ }
+ else {
+ dachlpPutchar(deviceExtension->printAddr, *fmt);
+ fmt++;
+ }
+ }
+}
+#endif // MYPRINT
+
diff --git a/private/ntos/miniport/mylex/dmc960/dac960nt.h b/private/ntos/miniport/mylex/dmc960/dac960nt.h
new file mode 100644
index 000000000..1fad7c455
--- /dev/null
+++ b/private/ntos/miniport/mylex/dmc960/dac960nt.h
@@ -0,0 +1,371 @@
+/************************************************************************
+* *
+* COPYRIGHT (C) Mylex Corporation 1994 *
+* *
+* This software is furnished under a license and may be used *
+* and copied only in accordance with the terms and conditions *
+* of such license and with inclusion of the the above copyright *
+* notice. This software or any other copies therof may not be *
+* provided or otherwise made available to any other person. No *
+* title to and ownership of the software is hereby transfered. *
+* *
+* The information in this software is subject to change without *
+* notices and should not be construed as a committmet by Mylex *
+* Corporation. *
+* *
+************************************************************************/
+
+/*
+** Mylex DAC960 miniport driver for Windows NT
+**
+** File: dac960nt.h
+** Equates for DAC960 adapter
+**
+*/
+
+
+#include "scsi.h"
+
+
+
+/*
+** Firmware related stuff
+*/
+
+#define MAX_DRVS 8
+#define DAC_MAX_IOCMDS 0x40
+#define DAC_MAXRQS 0x40
+#define DAC_THUNK 512
+
+
+#define MAX_WAIT_SECS 360
+
+#define ERR 2
+#define ABRT 4
+#define FWCHK 2
+#define HERR 1
+#define INSTL_ABRT 0x54524241
+#define INSTL_FWCK 0x4b434746
+#define INSTL_HERR 0x52524548
+#define INSTL_WEIRD 0x3f3f3f3f
+
+#define BIOS_PORT 0x0CC1
+#define BIOS_EN 0x40
+#define BASE_MASK 0x07
+#define BIOS_SIZE 16384
+
+/*
+** EISA specific stuff
+*/
+#define EISA_ADDRESS_BASE 0x0C80
+#define EISA_IO_SLOT1 0x1000
+#define EISA_IO_STEP 0x1000
+#define MAXIMUM_EISA_SLOTS 0x10 // Leave out non-bus master slots
+#define EISA_ID_START 0x0c80 /* Offset from IO base to ID */
+#define EISA_INTR 0xcc3
+#define EISA_ID_COUNT 4
+
+#define DAC_EISA_MASK { 0xff, 0xff, 0xff, 0xf0 } /* 4 bytes EISA ID mask */
+#define DAC_EISA_ID { 0x35, 0x98, 0, 0x70 } /* 4 bytes EISA ID */
+
+
+
+/*
+** EISA side of BMIC chip
+*/
+#define BMIC_GLBLCFG 0xc88
+#define BMIC_SYSINTCTRL 0xc89 // System interrupt enable/status
+#define BMIC_SIC_ENABLE 0x01 // read-write interrupt enable
+#define BMIC_SIC_PENDING 0x02 // read-only interrupt(s) pending
+#define BMIC_LOCAL_DB_ENABLE 0xc8c // Read-only from EISA side
+#define BMIC_LOCAL_DB 0xc8d // EISA to local notification
+#define BMIC_EISA_DB_ENABLE 0xc8e // Read-write from EISA side
+#define BMIC_EISA_DB 0xc8f // Local to EISA notification
+
+#define BMIC_MBOX 0xc90 // BMIC mailbox registers
+
+
+
+/*
+** More defines
+*/
+
+//
+// The DAC Command codes
+//
+#define DAC_LREAD 0x02
+#define DAC_LWRITE 0x03
+#define DAC_ENQUIRE 0x05
+#define DAC_ENQ2 0x1c
+#define DAC_FLUSH 0x0a
+#define DAC_DCDB 0x04
+#define DAC_DCMD 0x99
+#define DAC_GETDEVST 0x14
+
+#define ILFLAG 8
+#define BIT0 1
+
+#define ILFLAG 8
+
+#define MAXCHANNEL 5
+#define MAXTARGET 7
+#define DAC_DISCONNECT 0x80
+#define DATA_OFFSET 100
+#define NON_DISK 2 /* Bus ID for NonDisk Devices */
+#define DAC_NONE 0
+#define DAC_IN 1
+#define DAC_OUT 2
+#define DAC_NO_AUTOSENSE 0x40
+
+#define MAXIMUM_SGL_DESCRIPTORS 0x11
+
+#define RCB_NEEDCOPY 1
+#define RCB_PREFLUSH 2
+#define RCB_POSTFLUSH 4
+
+
+/*
+ * Various DAC mailbox formats
+ */
+
+#pragma pack(1)
+
+typedef struct { // I/O mailbox
+ UCHAR Byte0;
+ UCHAR Byte1;
+ UCHAR Byte2;
+ UCHAR Byte3;
+ UCHAR Byte4;
+ UCHAR Byte5;
+ UCHAR Byte6;
+ UCHAR Byte7;
+ UCHAR Byte8;
+ UCHAR Byte9;
+ UCHAR Bytea;
+ UCHAR Byteb;
+ UCHAR Bytec;
+ UCHAR Byted;
+ UCHAR Bytee;
+ UCHAR Bytef;
+
+} DAC_GENERAL;
+
+typedef struct { // I/O mailbox
+ UCHAR Command;
+ UCHAR Id;
+ USHORT SectorCount;
+ ULONG Block;
+ ULONG PhysAddr;
+ UCHAR Reserved1;
+ UCHAR RetId;
+ UCHAR Status;
+ UCHAR Error;
+
+} DAC_IOMBOX;
+
+typedef struct { // Request Drive Parameters
+ UCHAR Command;
+ UCHAR Id;
+ USHORT Reserved2;
+ ULONG Reserved3;
+ ULONG PhysAddr; // Address of DAC_DPT
+ UCHAR RetId;
+ UCHAR Status;
+ UCHAR Error;
+
+} DAC_DPMBOX;
+
+
+// IOCTL STUFFS
+
+typedef struct _SRB_IO_CONTROL
+{
+ ULONG HeaderLength;
+ UCHAR Signature[8];
+ ULONG Timeout;
+ ULONG ControlCode;
+ ULONG ReturnCode;
+ ULONG Length;
+
+} SRB_IO_CONTROL, * PSRB_IO_CONTROL;
+
+typedef struct{
+ SRB_IO_CONTROL srbioctl;
+ UCHAR DataBuf[512];
+
+}PASS_THROUGH_STRUCT, *PPT;
+
+
+
+typedef union {
+ DAC_IOMBOX iombox;
+ DAC_DPMBOX dpmbox;
+ DAC_GENERAL generalmbox;
+
+} DAC_MBOX;
+typedef DAC_MBOX *PDAC_MBOX;
+
+
+
+/*
+** Device parameters as returned from DAC firmware
+*/
+
+typedef struct {
+ ULONG No_Drives;
+ ULONG Size[MAX_DRVS];
+ UCHAR Filler0[7];
+ UCHAR max_io_cmds; /* Maxm No Of Concurrent commands */
+ UCHAR Filler[150];
+
+} DAC_DPT;
+
+typedef DAC_DPT *PDAC_DPT;
+
+
+/*
+** SCSI stuff
+*/
+/* 88-bytes */
+
+typedef struct {
+ UCHAR device; /* device -> chn(4):dev(4) */
+ UCHAR dir; /* direction-> 0=>no xfr, 1=>IN, 2=>OUT, MSB =1 =>
+ disconnecting,=0=> non-disconnecting */
+ USHORT byte_cnt; /* 64K max data xfr */
+ ULONG ptr; /* pointer to the data (in system memory) */
+ UCHAR cdb_len; /* length of cdb */
+ UCHAR sense_len; /* length of valid sense information */
+ UCHAR cdb[12];
+ UCHAR sense[64];
+ UCHAR status;
+ UCHAR fill;
+
+} DIRECT_CDB, *PDIRECT_CDB;
+
+
+
+//
+// Context structure for board scanning
+//
+typedef struct {
+ ULONG Slot;
+ ULONG AdapterCount;
+
+} SCANCONTEXT, *PSCANCONTEXT;
+
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+typedef struct _NONCACHED_EXTENSION {
+
+ // Device Parameter Table for the Get_Device_Parameters request
+
+ DAC_DPT DevParms;
+ UCHAR Buffer[DAC_THUNK];
+ ULONG PhysicalScsiReqAddress;
+ ULONG PhysicalReqSenseAddress;
+ UCHAR ReqSense[DAC_MAXRQS];
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+
+
+//
+// Request Control Block (SRB Extension)
+// All information required to break down and execute
+// a disk request is stored here
+//
+typedef struct _RCB {
+ PUCHAR VirtualTransferAddress;
+ ULONG BlockAddress;
+ ULONG BytesToGo;
+ UCHAR DacCommand;
+ UCHAR DacStatus;
+ UCHAR DacErrcode;
+
+} RCB, *PRCB;
+
+
+//
+// SCSI Command Control Block
+// We use this block to break down a non-disk scsi request
+//
+
+typedef struct _SCCB {
+ PUCHAR VirtualTransferAddress;
+ ULONG DeviceAddress;
+ ULONG BytesPerBlock;
+ ULONG BlocksToGo;
+ ULONG BlocksThisReq;
+ ULONG BytesThisReq;
+ UCHAR Started;
+ UCHAR Opcode;
+ UCHAR DevType;
+
+} SCCB, *PSCCB;
+
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ // NonCached extension
+
+ PNONCACHED_EXTENSION NoncachedExtension;
+ ULONG NCE_PhyAddr;
+ PVOID EisaAddress; // base address for slot (X000h)
+ PUSHORT printAddr;
+ ULONG AdapterIndex;
+ UCHAR HostTargetId;
+ UCHAR MaxChannels;
+ UCHAR No_SysDrives;
+ UCHAR ND_DevMap[MAXTARGET];
+
+ // Pending request.
+ // This request has not been sent to the adapter yet
+ // because the adapter was busy
+
+ PSCSI_REQUEST_BLOCK PendingSrb;
+ PSCSI_REQUEST_BLOCK PendingNDSrb;
+ ULONG NDPending;
+
+ // Pointers to disk IO requests sent to adapter
+ // and their statuses
+
+ ULONG ActiveCmds;
+ USHORT MaxCmds;
+ PSCSI_REQUEST_BLOCK ActiveSrb[DAC_MAX_IOCMDS];
+ RCB ActiveRcb[DAC_MAX_IOCMDS];
+
+
+ // Pointer to non-disk SCSI requests sent to adapter
+
+ PSCSI_REQUEST_BLOCK ActiveScsiSrb;
+ SCCB Sccb;
+ ULONG Kicked;
+ ULONG ScsiInterruptCount;
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+// Scatter Gather List *
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Address;
+ ULONG Length;
+
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+typedef struct _SGL {
+ SG_DESCRIPTOR Descriptor[MAXIMUM_SGL_DESCRIPTORS];
+} SGL, *PSGL;
+
+#pragma pack()
+
+
diff --git a/private/ntos/miniport/mylex/dmc960/dac960nt.rc b/private/ntos/miniport/mylex/dmc960/dac960nt.rc
new file mode 100644
index 000000000..d0f7835df
--- /dev/null
+++ b/private/ntos/miniport/mylex/dmc960/dac960nt.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "DAC960 SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "DAC960NT.sys"
+#define VER_ORIGINALFILENAME_STR "DAC960NT.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/mylex/dmc960/makefile b/private/ntos/miniport/mylex/dmc960/makefile
new file mode 100644
index 000000000..0d61f853d
--- /dev/null
+++ b/private/ntos/miniport/mylex/dmc960/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/mylex/dmc960/sources b/private/ntos/miniport/mylex/dmc960/sources
new file mode 100644
index 000000000..f8ee54133
--- /dev/null
+++ b/private/ntos/miniport/mylex/dmc960/sources
@@ -0,0 +1,42 @@
+
+
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+
+TARGETNAME=dac960nt
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+!IF $(ALPHA)
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib $(BASEDIR)\public\sdk\lib\*\libcntpr.lib
+!ENDIF
+
+SOURCES=dac960nt.c dac960nt.rc
diff --git a/private/ntos/miniport/ncr53c94/i386/ncr53c94.c b/private/ntos/miniport/ncr53c94/i386/ncr53c94.c
new file mode 100644
index 000000000..424212f94
--- /dev/null
+++ b/private/ntos/miniport/ncr53c94/i386/ncr53c94.c
@@ -0,0 +1,37 @@
+#include "ntddk.h"
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the main entry point for this driver. This routine exists so
+ that this driver can be built for non-x86 platforms and still be loaded
+ as a driver into the system, since it must be loaded by the OS loader
+ during the initial boot phase. It simply returns a status that indicates
+ that it did not successfully initialize, and will therefore allows the
+ system to boot.
+
+Arguments:
+
+ DriverObject - Supplies a pointer to the driver object that represents
+ the loaded instantiation of this driver in memory.
+
+Return Value:
+
+ The final return status is always an error.
+
+--*/
+
+{
+ //
+ // Simply return an error and get out of here.
+ //
+
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+}
diff --git a/private/ntos/miniport/ncr53c94/makefile b/private/ntos/miniport/ncr53c94/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/ncr53c94/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/ncr53c94/mcadefs.h b/private/ntos/miniport/ncr53c94/mcadefs.h
new file mode 100644
index 000000000..4c80788f9
--- /dev/null
+++ b/private/ntos/miniport/ncr53c94/mcadefs.h
@@ -0,0 +1,78 @@
+/*++
+
+Copyright (c) 1991 NCR Corporation
+
+Module Name:
+
+ mcadefs.h
+
+Abstract:
+
+ The module defines constants necessary for using the system dma
+ controller on microchannel machines
+
+Author:
+
+ David Risner (o-ncrdr) 10-Jun-1991
+
+Revision History:
+
+
+--*/
+
+
+#ifndef _MCADEFS_
+#define _MCADEFS_
+
+
+//
+// System Control Port definition
+//
+
+#define SystemControlPortA 0x92
+
+typedef struct _SYSTEM_PORT_A {
+ UCHAR AlternateHotReset : 1;
+ UCHAR AlternateGateA20 : 1;
+ UCHAR Reserved0 : 1;
+ UCHAR WatchdogTimerStatus : 1;
+ UCHAR SecurityLockLatch : 1;
+ UCHAR Reserved1 : 1;
+ UCHAR DiskActivityLight : 2;
+} SYSTEM_PORT_A, *PSYSTEM_PORT_A;
+
+
+//
+// MicroChannel extended DMA functions
+//
+
+#define MCA_DmaFunc 0x18 // extended function register
+#define MCA_DmaFuncExec 0x1a // extended function execute
+
+#define MCA_DmaIoAddrWr 0x00 // write I/O address reg
+#define MCA_DmaMemAddrWr 0x20 // write memory address reg
+#define MCA_DmaMemAddrRd 0x30 // read memory address reg
+#define MCA_DmaXfrCntWr 0x40 // write transfer count reg
+#define MCA_DmaXfrCntRd 0x50 // read transfer count reg
+#define MCA_DmaStatusRd 0x60 // read status register
+#define MCA_DmaMode 0x70 // access mode register
+#define MCA_DmaArbus 0x80 // access arbus register
+#define MCA_DmaMaskBitSet 0x90 // set bit in mask reg
+#define MCA_DmaMaskBitClr 0xa0 // clear bit in mask reg
+#define MCA_DmaMasterClr 0xd0 // master clear
+
+//
+// DMA mode options
+//
+
+#define MCA_Dma8Bits 0x00 // use 8 bit data
+#define MCA_Dma16Bits 0x40 // use 16 bit data
+#define MCA_DmaRead 0x00 // read data into memory
+#define MCA_DmaWrite 0x08 // write data from memory
+#define MCA_DmaVerify 0x00 // verify data
+#define MCA_DmaXfr 0x04 // transfer data
+#define MCA_DmaIoZero 0x00 // use I/O address 0000h
+#define MCA_DmaIoAddr 0x01 // use programed I/O address
+
+
+#endif
diff --git a/private/ntos/miniport/ncr53c94/ncr53c9x.c b/private/ntos/miniport/ncr53c94/ncr53c9x.c
new file mode 100644
index 000000000..a336c5a1f
--- /dev/null
+++ b/private/ntos/miniport/ncr53c94/ncr53c9x.c
@@ -0,0 +1,5616 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ncr53c9x.c
+
+Abstract:
+
+ This module contains the NCR 53c9x specific functions for the NT SCSI port
+ driver.
+
+Author:
+
+ Jeff Havens (jhavens) 28-Feb-1991
+
+Environment:
+
+ Kernel Mode only
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "scsi.h"
+
+#include "ncr53c9x.h"
+#include "mcadefs.h"
+#include "string.h"
+
+#include "jazzdef.h"
+#include "jazzdma.h"
+
+#if DBG
+int NcrDebug;
+#define NcrPrint(arg) ScsiDebugPrint arg
+#else
+#define NcrPrint(arg)
+#endif
+
+//
+// Define SCSI Protocol Chip configuration parameters.
+//
+
+#define INITIATOR_BUS_ID 0x7
+#define SELECT_TIMEOUT_FACTOR 33
+#define SYNCHRONOUS_OFFSET 0x0f
+#define ASYNCHRONOUS_OFFSET 0
+#define ASYNCHRONOUS_PERIOD 0x05
+#define RESET_STALL_TIME 25 // The minimum assertion time for
+ // a SCSI bus reset.
+#define INTERRUPT_STALL_TIME 5 // Time to wait for the next interrupt.
+
+
+//
+// NCR 53c9x specific port driver device extension flags.
+//
+
+#define PD_SYNCHRONOUS_RESPONSE_SENT 0x0001
+#define PD_SYNCHRONOUS_TRANSFER_SENT 0x0002
+#define PD_PENDING_START_IO 0x0004
+#define PD_MESSAGE_OUT_VALID 0x0008
+#define PD_DISCONNECT_EXPECTED 0x0010
+#define PD_SEND_MESSAGE_REQUEST 0x0020
+#define PD_POSSIBLE_EXTRA_MESSAGE_OUT 0x0040
+#define PD_PENDING_DATA_TRANSFER 0x0080
+#define PD_PARITY_ERROR_LOGGED 0x0100
+#define PD_EXPECTING_RESET_INTERRUPT 0x0200
+#define PD_EXPECTING_QUEUE_TAG 0x0400
+#define PD_TAGGED_SELECT 0x0800
+#define PD_NCR_ADAPTER 0x1000
+
+//
+// The following defines specify masks which are used to clear flags when
+// specific events occur, such as reset or disconnect.
+//
+
+#define PD_ADAPTER_RESET_MASK ( PD_SYNCHRONOUS_TRANSFER_SENT | \
+ PD_PENDING_START_IO | \
+ PD_MESSAGE_OUT_VALID | \
+ PD_SEND_MESSAGE_REQUEST | \
+ PD_POSSIBLE_EXTRA_MESSAGE_OUT | \
+ PD_PENDING_DATA_TRANSFER | \
+ PD_PARITY_ERROR_LOGGED | \
+ PD_EXPECTING_QUEUE_TAG | \
+ PD_TAGGED_SELECT | \
+ PD_DISCONNECT_EXPECTED \
+ )
+
+#define PD_ADAPTER_DISCONNECT_MASK ( PD_SYNCHRONOUS_TRANSFER_SENT | \
+ PD_MESSAGE_OUT_VALID | \
+ PD_SEND_MESSAGE_REQUEST | \
+ PD_POSSIBLE_EXTRA_MESSAGE_OUT | \
+ PD_PENDING_DATA_TRANSFER | \
+ PD_PARITY_ERROR_LOGGED | \
+ PD_EXPECTING_QUEUE_TAG | \
+ PD_TAGGED_SELECT | \
+ PD_DISCONNECT_EXPECTED \
+ )
+
+//
+// The largest SCSI bus message expected.
+//
+
+#define MESSAGE_BUFFER_SIZE 8
+
+//
+// Retry count limits.
+//
+
+#define RETRY_SELECTION_LIMIT 1
+#define RETRY_ERROR_LIMIT 2
+#define MAX_INTERRUPT_COUNT 64
+
+//
+// Bus and chip states.
+//
+
+typedef enum _ADAPTER_STATE {
+ BusFree,
+ AttemptingSelect,
+ CommandComplete,
+ CommandOut,
+ DataTransfer,
+ DisconnectExpected,
+ MessageAccepted,
+ MessageIn,
+ MessageOut,
+ Reselected
+} ADAPTER_STATE, *PADAPTER_STATE;
+
+//
+// Define the types of chips this driver will support.
+//
+
+typedef enum _CHIP_TYPES {
+ Ncr53c90,
+ Ncr53c94,
+ Fas216,
+ Fas216Fast
+}CHIP_TYPES, *PCHIP_TYPES;
+
+//
+// NCR 53c9x specific port driver logical unit flags.
+//
+
+#define PD_STATUS_VALID 0x0004
+#define PD_DO_NOT_CHECK_TRANSFER_LENGTH 0x0008
+#define PD_INITIATE_RECOVERY 0x0010
+#define PD_QUEUED_COMMANDS_EXECUTING 0x0020
+
+//
+// The following defines specify masks which are used to clear flags when
+// specific events occur, such as reset or command complete.
+//
+
+#define PD_LU_COMPLETE_MASK ( PD_STATUS_VALID | \
+ PD_DO_NOT_CHECK_TRANSFER_LENGTH | \
+ PD_INITIATE_RECOVERY \
+ )
+
+#define PD_LU_RESET_MASK ( PD_STATUS_VALID | \
+ PD_DO_NOT_CHECK_TRANSFER_LENGTH | \
+ PD_QUEUED_COMMANDS_EXECUTING | \
+ PD_INITIATE_RECOVERY \
+ )
+
+//
+// NCR 53c9x specific port driver SRB extension.
+//
+
+typedef struct _SRB_EXTENSION {
+ ULONG SrbExtensionFlags;
+ ULONG SavedDataPointer;
+ ULONG SavedDataLength;
+ ULONG MaximumTransferLength;
+}SRB_EXTENSION, *PSRB_EXTENSION;
+
+#define SRB_EXT(x) ((PSRB_EXTENSION)(x->SrbExtension))
+
+//
+// NCR 53c9x specific port driver logical unit extension.
+//
+
+typedef struct _SPECIFIC_LOGICAL_UNIT_EXTENSION {
+ USHORT LuFlags;
+ UCHAR RetryCount;
+ ULONG SavedDataPointer;
+ ULONG SavedDataLength;
+ PSCSI_REQUEST_BLOCK ActiveLuRequest;
+ PSCSI_REQUEST_BLOCK ActiveSendRequest;
+}SPECIFIC_LOGICAL_UNIT_EXTENSION, *PSPECIFIC_LOGICAL_UNIT_EXTENSION;
+
+//
+// NCR 53c9x specific per target controller information.
+//
+
+typedef struct _SPECIFIC_TARGET_EXTENSION {
+ UCHAR TargetFlags;
+ UCHAR SynchronousPeriod;
+ UCHAR SynchronousOffset;
+ SCSI_CONFIGURATION3 Configuration3;
+}SPECIFIC_TARGET_EXTENSION, *PSPECIFIC_TARGET_EXTENSION;
+
+//
+// Define target controller specific flags.
+//
+
+#define PD_SYNCHRONOUS_NEGOTIATION_DONE 0x0001
+#define PD_DO_NOT_NEGOTIATE 0x0002
+
+//
+// NCR 53c9x specific port driver device object extension.
+//
+
+typedef struct _SPECIFIC_DEVICE_EXTENSION {
+ ULONG AdapterFlags;
+ ADAPTER_STATE AdapterState; // Current state of the adapter
+ PADAPTER_REGISTERS AdapterBase; // Address of the NCR 53c9x adapter
+ PSCSI_REGISTERS Adapter; // Address of the NCR 53c9x chip
+ PSCSI_REQUEST_BLOCK ActiveLuRequest;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION ActiveLogicalUnit;
+ // Pointer to the acitive request.
+ PSCSI_REQUEST_BLOCK NextSrbRequest; // Pointer to the next SRB to process.
+ ULONG ActiveDataPointer; // SCSI bus active data pointer
+ ULONG ActiveDataLength; // The amount of data to be transferred.
+ LONG InterruptCount; // Count of interrupts since connection.
+ SPECIFIC_TARGET_EXTENSION TargetState[SCSI_MAXIMUM_TARGETS];
+ CHIP_TYPES ChipType; // Type or version of the chip.
+ SCSI_STATUS AdapterStatus; // Saved status register value
+ SCSI_SEQUENCE_STEP SequenceStep; // Saved sequence step register value
+ SCSI_INTERRUPT AdapterInterrupt; // Saved interrupt status register
+ SCSI_CONFIGURATION3 Configuration3;
+ UCHAR AdapterBusId; // This adapter's SCSI bus ID
+ UCHAR AdapterBusIdMask; // This adapter's SCSI bus ID bit mask
+ UCHAR ClockSpeed; // Chip clock speed in megahetrz.
+ BOOLEAN InterruptPending; // Interrupt pending indicator
+ UCHAR MessageBuffer[MESSAGE_BUFFER_SIZE]; // SCSI bus message buffer
+ UCHAR MessageCount; // Count of bytes in message buffer
+ UCHAR MessageSent; // Count of bytes sent to target
+ UCHAR TargetId; // Saved target id.
+ UCHAR Lun; // Saved lun id.
+ UCHAR ErrorCount;
+} SPECIFIC_DEVICE_EXTENSION, *PSPECIFIC_DEVICE_EXTENSION;
+
+
+//
+// Define the synchrouns data transfer parameters structure.
+//
+
+typedef struct _SYNCHRONOUS_TYPE_PARAMETERS {
+ UCHAR MaximumPeriodCyles;
+ UCHAR SynchronousPeriodCyles;
+ UCHAR InitialRegisterValue;
+}SYNCHRONOUS_TYPE_PARAMETERS, *PSYNCHRONOUS_TYPE_PARAMETERS;
+
+//
+// Define the table of synchronous transfer types.
+//
+
+const SYNCHRONOUS_TYPE_PARAMETERS SynchronousTransferTypes[] = {
+ { 0, 0, 5},
+ { 32, 5, 5},
+ { 32, 8, 7},
+ { 12, 4, 4}
+};
+
+//
+// SCSI Protocol Chip Control read and write macros.
+//
+
+#ifdef SCSI_READ
+#undef SCSI_READ
+#undef SCSI_WRITE
+#endif
+
+#if defined(DECSTATION)
+
+#define SCSI_READ(ChipAddr, Register) ScsiPortReadRegisterUchar(&((ChipAddr)->ReadRegisters.Register.Byte))
+
+#define SCSI_WRITE(ChipAddr, Register, Value) ScsiPortWriteRegisterUchar(&((ChipAddr)->WriteRegisters.Register.Byte), (Value))
+
+#else
+
+#define SCSI_READ(ChipAddr, Register) ScsiPortReadPortUchar(&((ChipAddr)->ReadRegisters.Register))
+#define SCSI_WRITE(ChipAddr, Register, Value) (ScsiPortWritePortUchar(&((ChipAddr)->WriteRegisters.Register), (Value)))
+
+#endif
+
+
+//
+// Functions passed to the OS-specific port driver.
+//
+
+ULONG
+NcrEisaFindAdapter(
+ IN PVOID ServiceContext,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+ULONG
+NcrMcaFindAdapter(
+ IN PVOID ServiceContext,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+ULONG
+NcrMipsFindAdapter(
+ IN PVOID ServiceContext,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+NcrInitializeAdapter(
+ IN PVOID ServiceContext
+ );
+
+BOOLEAN
+NcrInterruptServiceRoutine(
+ IN PVOID ServiceContext
+ );
+
+BOOLEAN
+NcrResetScsiBus(
+ IN PVOID ServiceContext,
+ IN ULONG PathId
+ );
+
+BOOLEAN
+NcrStartIo(
+ IN PVOID ServiceContext,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+NcrStartDataTransfer(
+ IN PVOID ServiceContext
+ );
+
+//
+// NCR 53c9x internal mini-port driver functions.
+//
+
+VOID
+NcrAcceptMessage(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN SetAttention,
+ IN BOOLEAN SetSynchronousParameters
+ );
+
+VOID
+NcrCleanupAfterReset(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN ExternalReset
+ );
+
+VOID
+NcrCompleteSendMessage(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR SrbStatus
+ );
+
+BOOLEAN
+NcrDecodeSynchronousRequest(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN PSPECIFIC_TARGET_EXTENSION TargetState,
+ IN BOOLEAN ResponseExpected
+ );
+
+VOID
+NcrDumpState(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+NcrMessageDecode(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+NcrLogError(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG ErrorCode,
+ IN ULONG UniqueCode
+ );
+
+VOID
+NcrProcessRequestCompletion(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+NcrResetScsiBusInternal(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG PathId
+ );
+
+VOID
+NcrSelectTarget(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ );
+
+VOID
+NcrSendMessage(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ );
+
+VOID
+NcrStartExecution(
+ PSCSI_REQUEST_BLOCK Srb,
+ PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ );
+
+
+VOID
+NcrAcceptMessage(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN SetAttention,
+ IN BOOLEAN SetSynchronousParameters
+ )
+/*++
+
+Routine Description:
+
+ This procedure tells the adapter to accept a pending message on the SCSI
+ bus. Optionally, it will set the synchronous transfer parameters and the
+ attention signal.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension.
+
+ SetAttention - Indicates the attention line on the SCSI bus should be set.
+
+ SetSynchronousParameters - Indicates the synchronous data transfer
+ parameters should be set.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PSPECIFIC_TARGET_EXTENSION targetState;
+
+ //
+ // Check to see if the synchonous data transfer parameters need to be set.
+ //
+
+ if (SetSynchronousParameters) {
+
+ //
+ // These must be set before a data transfer is started.
+ //
+
+ targetState = &DeviceExtension->TargetState[DeviceExtension->TargetId];
+
+ SCSI_WRITE( DeviceExtension->Adapter,
+ SynchronousPeriod,
+ targetState->SynchronousPeriod
+ );
+ SCSI_WRITE( DeviceExtension->Adapter,
+ SynchronousOffset,
+ targetState->SynchronousOffset
+ );
+ SCSI_WRITE( DeviceExtension->Adapter,
+ Configuration3,
+ *((PUCHAR) &targetState->Configuration3)
+ );
+ }
+
+ //
+ // Check to see if the attention signal needs to be set.
+ //
+
+ if (SetAttention) {
+
+ //
+ // This requests that the target enter the message-out phase.
+ //
+
+ SCSI_WRITE( DeviceExtension->Adapter, Command, SET_ATTENTION );
+ }
+
+ //
+ // Indicate to the adapter that the message-in phase may now be completed.
+ //
+
+ SCSI_WRITE(DeviceExtension->Adapter, Command, MESSAGE_ACCEPTED);
+}
+
+
+VOID
+NcrCleanupAfterReset(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN ExternalReset
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up the adapter-specific
+ and logical-unit-specific data structures. Any active requests are
+ completed and the synchronous negotiation flags are cleared.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to device extension for the bus that
+ was reset.
+
+ ExternalReset - When set, indicates that the reset was generated by a
+ SCSI device other than this host adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR pathId = 0;
+ UCHAR targetId;
+ UCHAR luId;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ PSPECIFIC_TARGET_EXTENSION targetState;
+
+ //
+ // Check to see if a data transfer was in progress, if so, flush the DMA.
+ //
+
+ if (DeviceExtension->AdapterState == DataTransfer) {
+
+ SCSI_WRITE(DeviceExtension->Adapter, Command, FLUSH_FIFO);
+ ScsiPortFlushDma(DeviceExtension);
+
+ }
+
+ //
+ // if the current state is AttemptingSelect then SCSI port driver needs
+ // to be notified that new requests can be sent.
+ //
+
+ if (DeviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ //
+ // Ask for another request and clear the pending one. The pending
+ // request will be processed when the request of the active requests
+ // are returned.
+
+ DeviceExtension->NextSrbRequest = NULL;
+ DeviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
+
+ ScsiPortNotification( NextRequest, DeviceExtension, NULL );
+
+ }
+
+ //
+ // If there was an active request, then complete it with
+ // SRB_STATUS_PHASE_SEQUENCE_FAILURE so the class driver will know not
+ // to retry it too many times.
+ //
+
+ if (DeviceExtension->ActiveLuRequest != NULL) {
+
+ //
+ // Set the SrbStatus in the SRB, complete the request and
+ // clear the active pointers
+ //
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+
+ DeviceExtension->ActiveLuRequest->SrbStatus =
+ SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+
+ targetState = &DeviceExtension->TargetState[DeviceExtension->TargetId];
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ DeviceExtension->ActiveLuRequest
+ );
+
+ //
+ // Check to see if there was a synchronous negotiation in progress. If
+ // there was then do not try to negotiate with this target again.
+ //
+
+ if (DeviceExtension->AdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT |
+ PD_SYNCHRONOUS_TRANSFER_SENT)) {
+
+ //
+ // This target cannot negotiate properly. Set a flag to prevent
+ // further attempts and set the synchronous parameters to use
+ // asynchronous data transfer.
+ //
+
+ targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE;
+ targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ targetState->Configuration3.FastScsi = 0;
+
+ }
+
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->RetryCount = 0;
+ DeviceExtension->ActiveLogicalUnit = NULL;
+ DeviceExtension->ActiveLuRequest = NULL;
+ }
+
+ //
+ // Clear the appropriate state flags as well as the next request.
+ // The request will actually be cleared when the logical units are processed.
+ // Note that it is not necessary to fail the request waiting to be started
+ // since it will be processed properly by the target controller, but it
+ // is cleared anyway.
+ //
+
+ for (targetId = 0; targetId < SCSI_MAXIMUM_TARGETS; targetId++) {
+
+ //
+ // Loop through each of the possible logical units for this target.
+ //
+
+ //
+ // Clear the synchronous negotiation flage for the target controller.
+ //
+
+ DeviceExtension->TargetState[targetId].TargetFlags &=
+ ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
+
+ for (luId = 0; luId < SCSI_MAXIMUM_LOGICAL_UNITS; luId++) {
+
+ luExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ pathId,
+ targetId,
+ luId
+ );
+
+ if (luExtension == NULL) {
+ continue;
+ }
+
+ ScsiPortCompleteRequest(
+ DeviceExtension,
+ pathId,
+ targetId,
+ luId,
+ SRB_STATUS_BUS_RESET
+ );
+
+ luExtension->ActiveLuRequest = NULL;
+
+ if (luExtension->ActiveSendRequest != NULL) {
+
+ //
+ // Set the SrbStatus in the SRB, complete the request and
+ // clear the active pointers
+ //
+
+ luExtension->ActiveSendRequest->SrbStatus =
+ SRB_STATUS_BUS_RESET;
+
+ //
+ // Complete the request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ luExtension->ActiveSendRequest
+ );
+
+ luExtension->ActiveSendRequest = NULL;
+
+ }
+
+ //
+ // Clear the necessary logical unit flags.
+ //
+
+ luExtension->LuFlags &= ~PD_LU_RESET_MASK;
+
+ } /* for luId */
+ } /* for targetId */
+
+ //
+ // Clear the adapter flags and set the bus state to free.
+ //
+
+ DeviceExtension->AdapterState = BusFree;
+ DeviceExtension->AdapterFlags &= ~PD_ADAPTER_RESET_MASK;
+
+}
+
+VOID
+NcrCompleteSendMessage(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR SrbStatus
+ )
+/*++
+
+Routine Description:
+
+ This function does the cleanup necessary to complete a send-message request.
+ This includes completing any affected execute-I/O requests and cleaning
+ up the device extension state.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension of the SCSI bus
+ adapter. The active logical unit is stored in ActiveLogicalUnit.
+
+ SrbStatus - Indicates the status that the request should be completeted with
+ if the request did not complete normally, then any active execute
+ requests are not considered to have been affected.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ PSCSI_REQUEST_BLOCK srbAbort;
+ UCHAR pathId = 0;
+ UCHAR targetId;
+ UCHAR luId;
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+ srb = luExtension->ActiveSendRequest;
+
+ //
+ // Clean up any EXECUTE requests which may have been affected by this
+ // message.
+ //
+
+ if (SrbStatus == SRB_STATUS_SUCCESS) {
+ switch (srb->Function) {
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ //
+ // Make sure there is still a request to complete. If so complete
+ // it with an SRB_STATUS_ABORTED status.
+ //
+
+ srbAbort = ScsiPortGetSrb(
+ DeviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun,
+ srb->QueueTag
+ );
+
+ if (srbAbort != srb->NextSrb) {
+
+ //
+ // If there is no request, then fail the abort.
+ //
+
+ SrbStatus = SRB_STATUS_ABORT_FAILED;
+ break;
+ }
+
+ srbAbort->SrbStatus = SRB_STATUS_ABORTED;
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ srbAbort
+ );
+
+ if (DeviceExtension->ActiveLuRequest == srbAbort) {
+
+ DeviceExtension->ActiveLuRequest = NULL;
+ }
+
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
+ luExtension->RetryCount = 0;
+
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ //
+ // Cycle through each of the possible logical units looking
+ // for requests which have been cleared by the target reset.
+ //
+
+ targetId = srb->TargetId;
+ DeviceExtension->TargetState[targetId].TargetFlags &=
+ ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
+
+ for (luId = 0; luId < SCSI_MAXIMUM_LOGICAL_UNITS; luId) {
+
+ luExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ pathId,
+ targetId,
+ luId
+ );
+
+ if (luExtension == NULL) {
+ continue;
+ }
+
+ ScsiPortCompleteRequest(
+ DeviceExtension,
+ pathId,
+ targetId,
+ luId,
+ SRB_STATUS_BUS_RESET
+ );
+
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->RetryCount = 0;
+
+ //
+ // Clear the necessary logical unit flags.
+ //
+
+ luExtension->LuFlags &= ~PD_LU_RESET_MASK;
+
+ } /* for luId */
+
+ /* TODO: Handle CLEAR QUEUE */
+ }
+ } else {
+
+ //
+ // If an abort request fails then complete target of the abort;
+ // otherwise the target of the ABORT may never be compileted.
+ //
+
+ if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Make sure there is still a request to complete. If so
+ // it with an SRB_STATUS_ABORTED status.
+ //
+
+ srbAbort = ScsiPortGetSrb(
+ DeviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun,
+ srb->QueueTag
+ );
+
+ if (srbAbort == srb->NextSrb) {
+
+ srbAbort->SrbStatus = SRB_STATUS_ABORTED;
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ srbAbort
+ );
+
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
+ luExtension->RetryCount = 0;
+
+ }
+ }
+
+ }
+
+ //
+ // Complete the actual send-message request.
+ //
+
+ srb->SrbStatus = SrbStatus;
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ srb
+ );
+
+ //
+ // Clear the active send request and PD_SEND_MESSAGE_REQUEST flag.
+ //
+
+ luExtension->RetryCount = 0;
+ luExtension->ActiveSendRequest = NULL;
+ DeviceExtension->AdapterFlags &= ~PD_SEND_MESSAGE_REQUEST;
+}
+
+BOOLEAN
+NcrMessageDecode(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ This function decodes the SCSI bus message-in the device extension message
+ buffer. After the message is decoded it decides what action to take in
+ response to the message. If an outgoing message needs to be sent, then
+ it is placed in the message buffer and TRUE is returned. If the message
+ is acceptable, then the device state is set either to DisconnectExpected or
+ MessageAccepted and the MessageCount is reset to 0.
+
+ Some messages are made up of several bytes. This funtion will simply
+ return false when an incomplete message is detected, allowing the target
+ to send the rest of the message. The message count is left unchanged.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+Return Value:
+
+ TRUE - Returns true if there is a reponse message to be sent.
+
+ FALSE - If there is no response message.
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK srb;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ LONG offset;
+ PSPECIFIC_TARGET_EXTENSION targetState;
+ LONG i;
+ ULONG savedAdapterFlags;
+ PSCSI_EXTENDED_MESSAGE extendedMessage;
+
+ //
+ // NOTE: The ActivelogicalUnit field could be invalid if the
+ // PD_DISCONNECT_EXPECTED flag is set, so luExtension cannot
+ // be used until this flag has been checked.
+ //
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+ savedAdapterFlags = DeviceExtension->AdapterFlags;
+ srb = DeviceExtension->ActiveLuRequest;
+ targetState = &DeviceExtension->TargetState[DeviceExtension->TargetId];
+
+ //
+ // If a queue message is expected then it must be the first message byte.
+ //
+
+ if (DeviceExtension->AdapterFlags & PD_EXPECTING_QUEUE_TAG &&
+ DeviceExtension->MessageBuffer[0] != SRB_SIMPLE_TAG_REQUEST) {
+
+ NcrPrint((1, "NcrMessageDecode: Unexpected message recieved when que tag expected.\n"));
+
+ //
+ // The target did not reselect correctly Send a
+ // message reject of this message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ }
+
+ //
+ // A number of special cases must be handled if a special message has
+ // just been sent. These special messages are synchronous negotiations
+ // or a messages which implie a disconnect. The special cases are:
+ //
+ // If a disconnect is expected because of a send-message request,
+ // then the only valid message-in is a MESSAGE REJECT; other messages
+ // are a protocol error and are rejected.
+ //
+ // If a synchronous negotiation response was just sent and the message
+ // in was not a MESSAGE REJECT, then the negotiation has been accepted.
+ //
+ // If a synchronous negotiation request was just sent, then valid responses
+ // are a MESSAGE REJECT or an extended synchronous message back.
+ //
+
+ if (DeviceExtension->AdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT |
+ PD_DISCONNECT_EXPECTED | PD_SYNCHRONOUS_TRANSFER_SENT)) {
+
+ if (DeviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED &&
+ DeviceExtension->MessageBuffer[0] != SCSIMESS_MESSAGE_REJECT) {
+
+ //
+ // The target is not responding correctly to the message. Send a
+ // message reject of this message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ }
+
+ if (DeviceExtension->AdapterFlags & PD_SYNCHRONOUS_RESPONSE_SENT &&
+ DeviceExtension->MessageBuffer[0] != SCSIMESS_MESSAGE_REJECT) {
+
+ //
+ // The target did not reject our response so the synchronous
+ // transfer negotiation is done. Clear the adapter flags and
+ // set the logical unit flags indicating this. Continue processing
+ // the message which is unrelated to negotiation.
+ //
+
+ DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_RESPONSE_SENT;
+ targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ }
+
+ //
+ // Save the adapter flags for later use.
+ //
+
+ savedAdapterFlags = DeviceExtension->AdapterFlags;
+
+ if (DeviceExtension->AdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT ) {
+
+ //
+ // The target is sending a message after a synchronous transfer
+ // request was sent. Valid responses are a MESSAGE REJECT or an
+ // extended synchronous message; any other message negates the
+ // fact that a negotiation was started. However, since extended
+ // messages are multi-byte, it is difficult to determine what the
+ // incoming message is. So at this point, the fact that a
+ // sychronous transfer was sent will be saved and cleared from the
+ // AdapterFlags. If the message looks like a synchronous transfer
+ // request, then restore this fact back into the AdapterFlags. If
+ // the complete message is not the one expected, then opening
+ // negotiation will be forgotten. This is an error by the target,
+ // but minor so nothing will be done about it. Finally, to prevent
+ // this cycle from reoccurring on the next request indicate that
+ // the negotiation is done.
+ //
+
+ DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
+ targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ }
+
+ }
+
+ switch (DeviceExtension->MessageBuffer[0]) {
+ case SCSIMESS_COMMAND_COMPLETE:
+
+ //
+ // For better or worse the command is complete. Process request which
+ // set the SrbStatus and clean up the device and logical unit states.
+ //
+
+ NcrProcessRequestCompletion(DeviceExtension);
+
+ //
+ // Complete the request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ srb
+ );
+
+ //
+ // Everything is ok with the message so do not send one and set the
+ // state to DisconnectExpected.
+ //
+
+ DeviceExtension->AdapterState = DisconnectExpected;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_DISCONNECT:
+
+ //
+ // The target wants to disconnect. Set the state to DisconnectExpected,
+ // and do not request a message-out.
+ //
+
+ DeviceExtension->AdapterState = DisconnectExpected;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_EXTENDED_MESSAGE:
+
+ //
+ // The format of an extended message is:
+ // Extended Message Code
+ // Length of Message
+ // Extended Message Type
+ // .
+ // .
+ //
+ // Until the entire message has been read in, just keep getting bytes
+ // from the target, making sure that the message buffer is not
+ // overrun.
+ //
+
+ extendedMessage = (PSCSI_EXTENDED_MESSAGE)
+ DeviceExtension->MessageBuffer;
+
+ if (DeviceExtension->MessageCount < 2 ||
+ (DeviceExtension->MessageCount < MESSAGE_BUFFER_SIZE &&
+ DeviceExtension->MessageCount < extendedMessage->MessageLength + 2)
+ ) {
+
+ //
+ // Update the state and return; also restore the AdapterFlags.
+ //
+
+ DeviceExtension->AdapterFlags = savedAdapterFlags;
+ DeviceExtension->AdapterState = MessageAccepted;
+ return(FALSE);
+
+ }
+
+ //
+ // Make sure the length includes an extended op-code.
+ //
+
+ if (DeviceExtension->MessageCount < 3) {
+
+ //
+ // This is an illegal extended message. Send a MESSAGE_REJECT.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ }
+
+ //
+ // Determine the extended message type.
+ //
+
+ switch (extendedMessage->MessageType) {
+ case SCSIMESS_MODIFY_DATA_POINTER:
+
+ //
+ // Verify the message length.
+ //
+
+ if (extendedMessage->MessageLength != SCSIMESS_MODIFY_DATA_LENGTH) {
+
+ //
+ // Reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ }
+
+ //
+ // Calculate the modification to be added to the data pointer.
+ //
+
+ offset = 0;
+ for (i = 0; i < 4; i++) {
+ offset << 8;
+ offset += extendedMessage->ExtendedArguments.Modify.Modifier[i];
+ }
+
+ //
+ // Verify that the new data pointer is still within the range
+ // of the buffer.
+ //
+
+ if (DeviceExtension->ActiveDataLength - offset >
+ srb->DataTransferLength ||
+ ((LONG) DeviceExtension->ActiveDataLength - offset) < 0 ) {
+
+ //
+ // The new pointer is not valid, so reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ }
+
+ //
+ // Everything has checked out, so update the pointer.
+ //
+
+ DeviceExtension->ActiveDataPointer += offset;
+ DeviceExtension->ActiveDataLength -= offset;
+
+ //
+ // Everything is ok, so accept the message as is.
+ //
+
+ DeviceExtension->MessageCount = 0;
+ DeviceExtension->AdapterState = MessageAccepted;
+ return(FALSE);
+
+ case SCSIMESS_SYNCHRONOUS_DATA_REQ:
+
+ //
+ // A SYNCHRONOUS DATA TRANSFER REQUEST message was received.
+ // Make sure the length is correct.
+ //
+
+ if ( extendedMessage->MessageLength !=
+ SCSIMESS_SYNCH_DATA_LENGTH) {
+
+ //
+ // The length is invalid, so reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ //
+ // If synchrouns negotiation has been disabled for this request,
+ // then reject any synchronous messages; however, when synchronous
+ // transfers are allowed then a new attempt can be made.
+ //
+
+ if (srb != NULL &&
+ !(savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT) &&
+ srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) {
+
+ //
+ // Reject the synchronous transfer message since synchonrous
+ // transfers are not desired at this time.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+
+ }
+
+ //
+ // Call NcrDecodeSynchronousMessage to decode the message and
+ // formulate a response if necessary.
+ // NcrDecodeSynchronousRequest will return FALSE if the
+ // message is not accepable and should be rejected.
+ //
+
+ if (!NcrDecodeSynchronousRequest(
+ DeviceExtension,
+ targetState,
+ (BOOLEAN)(!(savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT))
+ )) {
+
+ //
+ // Indicate that a negotiation has been done in the logical
+ // unit and clear the negotiation flags.
+ //
+
+ targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+
+ DeviceExtension->AdapterFlags &=
+ ~(PD_SYNCHRONOUS_RESPONSE_SENT|
+ PD_SYNCHRONOUS_TRANSFER_SENT);
+
+ //
+ // The message was not acceptable so send a MESSAGE_REJECT.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ //
+ // If a reponse was expected, then set the state for a message-out.
+ // Otherwise, NcrDecodeSynchronousRequest has put a reponse
+ // in the message buffer to be returned to the target.
+ //
+
+ if (savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT){
+
+ //
+ // We initiated the negotiation, so no response is necessary.
+ //
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
+ targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+ }
+
+ //
+ // Set up the state to send the reponse. The message count is
+ // still correct.
+ //
+
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->AdapterState = MessageOut;
+ DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
+ DeviceExtension->AdapterFlags |= PD_SYNCHRONOUS_RESPONSE_SENT;
+ return(TRUE);
+
+ case SCSIMESS_WIDE_DATA_REQUEST:
+
+ //
+ // A WIDE DATA TRANSFER REQUEST message was received.
+ // Make sure the length is correct.
+ //
+
+ if ( extendedMessage->MessageLength !=
+ SCSIMESS_WIDE_DATA_LENGTH) {
+
+ //
+ // The length is invalid reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ //
+ // Since this SCSI protocol chip only supports 8-bits return
+ // a width of 0 which indicates an 8-bit-wide transfers. The
+ // MessageCount is still correct for the message.
+ //
+
+ extendedMessage->ExtendedArguments.Wide.Width = 0;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+
+ default:
+
+ //
+ // This is an unknown or illegal message, so send-message REJECT.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ case SCSIMESS_INITIATE_RECOVERY:
+
+ //
+ // Save the fact that a INITIATE RECOVERY message was received.
+ //
+
+ SRB_EXT(srb)->SrbExtensionFlags |= PD_INITIATE_RECOVERY;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_LINK_CMD_COMP:
+
+ //
+ // A link command completed. Process the completion. Since the link
+ // FLAG was not set, do not call ScsiPortNotification. Get the next
+ // segment of the request and accept the message.
+ //
+
+ //
+ // Make sure that this is a linked command.
+ // Linked commands are not supported.
+ //
+
+ if (TRUE) {
+
+ //
+ // Something is messed up. Reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ NcrProcessRequestCompletion(DeviceExtension);
+
+ DeviceExtension->ActiveLuRequest = srb->NextSrb;
+
+ //
+ // Everything is ok with the message, so do not send one and set the
+ // state to MessageAccepted.
+ //
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_LINK_CMD_COMP_W_FLAG:
+
+ //
+ // A link command completed. Process the completion and get the next
+ // segment of the request. Since the link FLAG was set, call
+ // ScsiPortNotification to notify the class driver.
+ //
+
+ //
+ // Make sure that this is a linked command.
+ // Linked commands are not supported.
+ //
+
+ if (TRUE) {
+
+ //
+ // Something is messed up. Reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ NcrProcessRequestCompletion(DeviceExtension);
+
+ DeviceExtension->ActiveLuRequest = srb->NextSrb;
+
+ //
+ // Complete the request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ srb
+ );
+
+ //
+ // Everything is ok with the message, so do not send one and set the
+ // state to MessageAccepted.
+ //
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_MESSAGE_REJECT:
+
+ //
+ // The last message we sent was rejected. If this was a send
+ // message request, then set the proper status and complete the
+ // request. Set the state to message accepted.
+ //
+
+ /* TODO: Handle message reject correctly. */
+ if (DeviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
+
+ //
+ // Complete the request with message rejected status.
+ //
+
+ NcrCompleteSendMessage(
+ DeviceExtension,
+ SRB_STATUS_MESSAGE_REJECTED
+ );
+ }
+
+ //
+ // Check to see if a synchronous negotiation is in progress.
+ //
+
+ if (savedAdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT|
+ PD_SYNCHRONOUS_TRANSFER_SENT)) {
+
+ //
+ // The negotiation failed so use asynchronous data transfers.
+ // Indicate that the negotiation has been attempted and set
+ // the transfer for asynchronous. Clear the negotiation flags.
+ //
+
+ targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ targetState->Configuration3.FastScsi = 0;
+ DeviceExtension->AdapterFlags &= ~(PD_SYNCHRONOUS_RESPONSE_SENT|
+ PD_SYNCHRONOUS_TRANSFER_SENT);
+
+ //
+ // Even though the negotiation appeared to go ok, there is no reason
+ // to try again, and some targets get messed up later, so do not try
+ // synchronous negotiation again.
+ //
+
+ targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE;
+
+ }
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_SIMPLE_QUEUE_TAG:
+ case SCSIMESS_ORDERED_QUEUE_TAG:
+ case SCSIMESS_HEAD_OF_QUEUE_TAG:
+
+ //
+ // A queue tag message was recieve. If this is the first byte just
+ // accept the message and wait for the next one.
+ //
+
+ if (DeviceExtension->MessageCount < 2) {
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ return(FALSE);
+
+ }
+
+ //
+ // Make sure that a queue tag message is expected.
+ //
+
+ if (!(DeviceExtension->AdapterFlags & PD_EXPECTING_QUEUE_TAG) ||
+ luExtension == NULL) {
+
+ NcrPrint((1, "NcrMessageDecode: Unexpected queue tag message recieved\n"));
+
+ //
+ // Something is messed up. Reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
+ DeviceExtension->AdapterState = MessageOut;
+ NcrLogError( DeviceExtension, SP_PROTOCOL_ERROR, 17);
+ return(TRUE);
+
+ }
+
+ //
+ // The second byte contains the tag used to locate the srb.
+ //
+
+ srb = ScsiPortGetSrb(
+ DeviceExtension,
+ 0,
+ DeviceExtension->TargetId,
+ DeviceExtension->Lun,
+ DeviceExtension->MessageBuffer[1]
+ );
+
+ if (srb == NULL) {
+
+ NcrPrint((1, "NcrMessageDecode: Invalid queue tag recieved\n"));
+
+ //
+ // Something is messed up. Reject the message.
+ //
+
+ DeviceExtension->AdapterFlags &= ~PD_EXPECTING_QUEUE_TAG;
+ DeviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ NcrLogError( DeviceExtension, SP_PROTOCOL_ERROR, 16);
+
+ return(TRUE);
+
+ }
+
+ //
+ // Everthing is ok. Set up the device extension and accept the message.
+ // Restore the data pointers.
+ //
+
+ DeviceExtension->ActiveLuRequest = srb;
+ DeviceExtension->ActiveDataPointer = SRB_EXT(srb)->SavedDataPointer;
+ DeviceExtension->ActiveDataLength = SRB_EXT(srb)->SavedDataLength;
+ DeviceExtension->AdapterFlags &= ~PD_EXPECTING_QUEUE_TAG;
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_RESTORE_POINTERS:
+
+ //
+ // Restore data pointer message. Just copy the saved data pointer
+ // and the length to the active data pointers.
+ //
+
+ DeviceExtension->ActiveDataPointer = SRB_EXT(srb)->SavedDataPointer;
+ DeviceExtension->ActiveDataLength = SRB_EXT(srb)->SavedDataLength;
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_SAVE_DATA_POINTER:
+
+ //
+ // SAVE DATA POINTER message request that the active data pointer and
+ // length be copied to the saved location.
+ //
+
+ SRB_EXT(srb)->SavedDataPointer = DeviceExtension->ActiveDataPointer;
+ SRB_EXT(srb)->SavedDataLength = DeviceExtension->ActiveDataLength;
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ default:
+
+ //
+ // An unrecognized or unsupported message. send-message reject.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+}
+
+BOOLEAN
+NcrDecodeSynchronousRequest(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PSPECIFIC_TARGET_EXTENSION TargetState,
+ IN BOOLEAN ResponseExpected
+ )
+/*++
+
+Routine Description:
+
+ This function decodes the synchronous data transfer request message from
+ the target. It will update the synchronous message-in the buffer and the
+ synchronous transfer parameters in the logical unit extension. These
+ parameters are specific for the NCR 53C9X protocol chip. The updated
+ message-in the device extension message buffer might be returned to the
+ target.
+
+ This function should be called before the final byte of the message is
+ accepted from the SCSI bus.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the adapter specific device
+ extension.
+
+ TargetState - Supplies a pointer to the target controller's state.
+ The synchronous transfer fields are updated in this structure to
+ reflect the new parameter in the message.
+
+ ResponseExpected - When set, indicates that the target initiated the
+ negotiation and that it expects a response.
+
+Return Value:
+
+ TRUE - Returned if the request is acceptable.
+
+ FALSE - Returned if the request should be rejected and asynchronous
+ transfer should be used.
+
+--*/
+
+{
+ PSCSI_EXTENDED_MESSAGE extendedMessage;
+ CHIP_TYPES chipType;
+ LONG period;
+ ULONG localPeriod;
+ ULONG step;
+ LONG i;
+
+ extendedMessage = (PSCSI_EXTENDED_MESSAGE) DeviceExtension->MessageBuffer;
+
+ //
+ // Determine the transfer offset. It is the minimum of the SCSI protocol
+ // chip's maximum offset and the requested offset.
+ //
+
+ if (extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset >
+ SYNCHRONOUS_OFFSET) {
+
+ if (!ResponseExpected) {
+
+ //
+ // The negotiation failed for some reason; fall back to
+ // asynchronous data transfer.
+ //
+
+ TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ TargetState->Configuration3.FastScsi = 0;
+ return(FALSE);
+ }
+
+ extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset = SYNCHRONOUS_OFFSET;
+ TargetState->SynchronousOffset = SYNCHRONOUS_OFFSET;
+
+ } else {
+
+ TargetState->SynchronousOffset =
+ extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset;
+
+ }
+
+ //
+ // If the offset requests asynchronous transfers then set the default
+ // period and return.
+ //
+
+ if (extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset ==
+ ASYNCHRONOUS_OFFSET) {
+ TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ TargetState->Configuration3.FastScsi = 0;
+ return(TRUE);
+ }
+
+ //
+ // Calculate the period in nanoseconds from the message.
+ //
+
+ period = extendedMessage->ExtendedArguments.Synchronous.TransferPeriod;
+
+ NcrPrint((1, "NcrDecodeSynchronousRequest: Requested period %d, ", period));
+
+ //
+ // If the chip supports fast SCSI and the requested period is faster than
+ // 200 ns then assume fast SCSI.
+ //
+
+ if (DeviceExtension->ChipType == Fas216 && period < 200 / 4) {
+
+ chipType = Fas216Fast;
+
+ //
+ // Set the fast SCSI bit in the configuration register.
+ //
+
+ TargetState->Configuration3.FastScsi = 1;
+
+ } else {
+ chipType = DeviceExtension->ChipType;
+ }
+
+ //
+ // The initial sychronous transfer period is:
+ //
+ // SynchronousPeriodCyles * 1000
+ // -----------------------------
+ // ClockSpeed * 4
+ //
+ // Note the result of the divide by four must be rounded up.
+ //
+
+ localPeriod = ((SynchronousTransferTypes[chipType].SynchronousPeriodCyles
+ * 1000) / DeviceExtension->ClockSpeed + 3) / 4;
+
+ //
+ // Check to see if the period is less than the SCSI protocol chip can
+ // use. If it is then update the message with our minimum and return.
+ //
+
+ if ((ULONG) period < localPeriod ) {
+
+ if (!ResponseExpected) {
+
+ //
+ // The negotiation failed for some reason; fall back to
+ // asynchronous data transfer.
+ //
+
+ TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ TargetState->Configuration3.FastScsi = 0;
+ NcrPrint((1, "Too fast. Local period %d\n", localPeriod));
+ return(FALSE);
+ }
+
+ extendedMessage->ExtendedArguments.Synchronous.TransferPeriod =
+ (UCHAR) localPeriod;
+ period = localPeriod;
+ }
+
+ //
+ // The synchronous transfer cycle count is calculated by:
+ //
+ // (RequestedPeriod - BasePeriod) * 1000
+ // ------------------------------------- + InitialRegisterValue
+ // ClockSpeed * 4
+ //
+ // Note the divide must be rounded up.
+ //
+
+ step = (1000 / 4) / DeviceExtension->ClockSpeed;
+ period -= localPeriod;
+ for (i = SynchronousTransferTypes[chipType].InitialRegisterValue;
+ i < SynchronousTransferTypes[chipType].MaximumPeriodCyles;
+ i++) {
+
+ if (period <= 0) {
+ break;
+ }
+
+ period -= step;
+ localPeriod += step;
+ }
+
+ NcrPrint((1, "Local period: %d, Register value: %d\n", localPeriod, i));
+
+ if (i >= SynchronousTransferTypes[chipType].MaximumPeriodCyles) {
+
+ //
+ // The requested transfer period is too long for the SCSI protocol
+ // chip. Fall back to synchronous and reject the request.
+ //
+
+ TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ TargetState->Configuration3.FastScsi = 0;
+
+ return(FALSE);
+ }
+
+ TargetState->SynchronousPeriod = (UCHAR) i;
+
+ //
+ // If no response was expected then the negotation has completed
+ // successfully. Set the synchronous data transfer parameter registers
+ // to the new values. These must be set before a data transfer
+ // is started.
+ //
+
+ SCSI_WRITE( DeviceExtension->Adapter,
+ SynchronousPeriod,
+ TargetState->SynchronousPeriod
+ );
+ SCSI_WRITE( DeviceExtension->Adapter,
+ SynchronousOffset,
+ TargetState->SynchronousOffset
+ );
+ SCSI_WRITE( DeviceExtension->Adapter,
+ Configuration3,
+ *((PUCHAR) &TargetState->Configuration3)
+ );
+
+ return(TRUE);
+
+}
+
+VOID
+NcrDumpState(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This function prints the interesting state information about the requested
+ SCSI bus adapter.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to device extension for the SCSI
+ bus adapter that should be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NcrPrint((0, "NcrDumpState: Specific device extension: %8x; Active Logical Unit: %8x;\n",
+ DeviceExtension,
+ DeviceExtension->ActiveLogicalUnit
+ ));
+ NcrPrint((0, "NcrDumpState: Adapter Status: %2x; Adapter Interrupt: %2x; Adapter Step: %2x;\n",
+ *((PUCHAR) &DeviceExtension->AdapterStatus),
+ *((PUCHAR) &DeviceExtension->AdapterInterrupt),
+ *((PUCHAR) &DeviceExtension->SequenceStep)
+ ));
+ NcrPrint((0, "NcrDumpState: Adapter flags: %4x; Adapter state: %d;\n",
+ DeviceExtension->AdapterFlags,
+ DeviceExtension->AdapterState
+ ));
+
+}
+
+
+BOOLEAN
+NcrInitializeAdapter(
+ IN PVOID ServiceContext
+ )
+/*++
+
+Routine Description:
+
+ This function initializes the NCR 53c9x SCSI host adpater and protocol
+ chip. This function must be called before any other operations are
+ performed. It should also be called after a power failure. This
+ function does not cause any interrupts; however, after it completes
+ interrupts can occur.
+
+Arguments:
+
+ ServiceContext - Pointer to the specific device extension for this SCSI
+ bus.
+
+Return Value:
+
+ TRUE - Returns true indicating that the initialization of the chip is
+ complete.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ UCHAR dataByte;
+
+ //
+ // Clear the adapter flags, but preserve the NCR adapter flag.
+ //
+
+ deviceExtension->AdapterFlags =
+ deviceExtension->AdapterFlags & PD_NCR_ADAPTER;
+
+ //
+ // Initialize the NCR 53c9x SCSI protocol chip.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
+ SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
+
+ //
+ // Set the configuration register for slow cable mode, parity enable,
+ // and allow reset interrupts, also set the host adapter SCSI bus id.
+ // Configuration registers 2 and 3 are cleared by the chip reset and
+ // do not need to be changed.
+ //
+
+ dataByte = deviceExtension->AdapterBusId;
+ ((PSCSI_CONFIGURATION1)(&dataByte))->ParityEnable = 1;
+
+ SCSI_WRITE(deviceExtension->Adapter, Configuration1, dataByte);
+
+ //
+ // Configuration registers 2 and 3 are cleared by a chip reset and do
+ // need to be initialized. Note these registers do not exist on the
+ // Ncr53c90, but the writes will do no harm. Set configuration register 3
+ // with the value determined by the find adapter routine.
+ //
+
+ SCSI_WRITE(
+ deviceExtension->Adapter,
+ Configuration3,
+ *((PUCHAR)&deviceExtension->Configuration3)
+ );
+
+ //
+ // Enable the SCSI-2 features.
+ //
+
+ dataByte = 0;
+ ((PSCSI_CONFIGURATION2)(&dataByte))->Scsi2 = 1;
+ ((PSCSI_CONFIGURATION2)(&dataByte))->EnablePhaseLatch = 1;
+
+ SCSI_WRITE(deviceExtension->Adapter, Configuration2, dataByte);
+
+ //
+ // Set the clock conversion register. The clock convertion factor is the
+ // clock speed divided by 5 rounded up. Only the low three bits are used.
+ //
+
+ dataByte = (deviceExtension->ClockSpeed + 4) / 5;
+ SCSI_WRITE(
+ deviceExtension->Adapter,
+ ClockConversionFactor,
+ (UCHAR)(dataByte & 0x07)
+ );
+
+ //
+ // Set the SelectTimeOut Register to 250ms. This value is based on the
+ // clock conversion factor and the clock speed.
+ //
+
+ dataByte = SELECT_TIMEOUT_FACTOR * deviceExtension->ClockSpeed / dataByte;
+
+ SCSI_WRITE( deviceExtension->Adapter, SelectTimeOut, dataByte);
+
+ //
+ // NOTE: Reselection does not need to be enabled until a request is sent
+ // to a target. The process of sending a target a request will cause a
+ // disconnect interrupt so that an ENABLE_SELECTION_RESELECTION request
+ // will be performed.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_NCR_ADAPTER) {
+
+ //
+ // Enable Adapter Interrupts
+ //
+
+ dataByte = SCSI_READ(deviceExtension->AdapterBase, OptionSelect1);
+ ((PPOS_DATA_1)(&dataByte))->InterruptEnable = 1;
+ SCSI_WRITE(deviceExtension->AdapterBase, OptionSelect1, dataByte);
+
+ }
+
+ return( TRUE );
+}
+
+BOOLEAN
+NcrInterruptServiceRoutine(
+ PVOID ServiceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is the interrupt service routine for the NCR 53c9x SCSI
+ host adapter. It is the main SCSI protocol engine of the driver and
+ is driven by service requests from targets on the SCSI bus. This routine
+ also detects errors and performs error recovery. Generally, this routine
+ handles one interrupt per invokation.
+
+ The general flow of this routine is as follows:
+
+ Check for an interrupt.
+
+ Determine if there are any pending errors.
+
+ Check to see if the bus disconnected.
+
+ Check that the previous function completed normally.
+
+ Determine what the target wants to do next and program the chip
+ appropriately.
+
+ Check for the next interrupt.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ TRUE - Indicates that an interrupt was found.
+
+ FALSE - Indicates the device was not interrupting.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ LONG i;
+ SCSI_DMA_STATUS DmaStatus;
+ BOOLEAN setAttention;
+
+ /* POWERFAIL */
+
+ //
+ // Make sure there is really an interrupt before reading the other
+ // registers, particularly, the interrupt register.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_NCR_ADAPTER) {
+
+ *((PUCHAR) &DmaStatus) = SCSI_READ( deviceExtension->AdapterBase, DmaStatus );
+ if (DmaStatus.Interrupt != deviceExtension->InterruptPending ) {
+ return(FALSE);
+ }
+
+ *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ ( deviceExtension->Adapter, ScsiStatus );
+
+ } else {
+
+ *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ ( deviceExtension->Adapter, ScsiStatus );
+ if (!deviceExtension->AdapterStatus.Interrupt) {
+ return(FALSE);
+ }
+ }
+
+NextInterrupt:
+
+ //
+ // Get the current chip state which includes the status register, the
+ // sequence step register and the interrupt register. These registers are
+ // frozen until the interrupt register is read.
+ //
+
+ *((PUCHAR) &deviceExtension->SequenceStep) = SCSI_READ(
+ deviceExtension->Adapter,
+ SequenceStep
+ );
+ //
+ // This read will dismiss the interrupt.
+ //
+
+ *((PUCHAR) &deviceExtension->AdapterInterrupt) = SCSI_READ(
+ deviceExtension->Adapter,
+ ScsiInterrupt
+ );
+
+#if DBG
+ if (!deviceExtension->AdapterInterrupt.Disconnect && NcrDebug) {
+ NcrPrint((0, "NcrInterrupt: Adapter Status: %2x; Adapter Interrupt: %2x; Adapter Step: %2x;\n",
+ *((PUCHAR) &deviceExtension->AdapterStatus),
+ *((PUCHAR) &deviceExtension->AdapterInterrupt),
+ *((PUCHAR) &deviceExtension->SequenceStep)
+ ));
+ }
+#endif
+
+ deviceExtension->InterruptCount++;
+
+ if (deviceExtension->AdapterInterrupt.IllegalCommand) {
+ NcrPrint((1, "NcrInterrupt: IllegalCommand\n" ));
+
+#if DBG
+ if ( NcrDebug != 0) {
+ NcrDumpState(deviceExtension);
+ }
+#endif
+
+ if (deviceExtension->AdapterState == AttemptingSelect ||
+ deviceExtension->AdapterState == Reselected) {
+
+ //
+ // If an IllegalCommand interrupt has occurred and a select
+ // is being attempted, flush the FIFO and exit. This occurs
+ // when the fifo is being filled for a new command at the
+ // same time time a reselection occurs.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
+
+ } else {
+
+ //
+ // An illegal command occured at an unexpected time. Reset the
+ // bus and log an error.
+ //
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+#ifdef MIPS
+ //
+ // There is a chip bug with the Emulex 216 part which causes
+ // illegal commands interrupts to be generated. This problem
+ // can be prevented on the mips systems by setting a bit in the
+ // DMA controller to provide better DMA service to the adapter.
+ //
+
+ if (deviceExtension->ErrorCount++ == 1) {
+
+ //
+ // Clear on board DMA
+ //
+
+ i = ScsiPortReadRegisterUlong(
+ (PULONG) &DMA_CONTROL->Channel[SCSI_CHANNEL].Enable.Long
+ );
+
+ ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 0;
+ ScsiPortWriteRegisterUlong(
+ (PULONG) &DMA_CONTROL->Channel[SCSI_CHANNEL].Enable.Long,
+ i
+ );
+
+
+ //
+ // Enable brust mode in the DMA controller.
+ //
+
+ i = ScsiPortReadRegisterUlong(
+ (PULONG) &DMA_CONTROL->Channel[SCSI_CHANNEL].Mode.Long
+ );
+
+
+ ((PDMA_CHANNEL_MODE) &i)->BurstMode = 1;
+
+ ScsiPortWriteRegisterUlong(
+ (PULONG) &DMA_CONTROL->Channel[SCSI_CHANNEL].Mode.Long,
+ i
+ );
+
+ NcrLogError(deviceExtension, SP_BAD_FW_WARNING, 15);
+
+ }
+#endif
+ NcrLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 14);
+
+ }
+
+ return(TRUE);
+ }
+
+ //
+ // Check for major errors these should never occur.
+ //
+
+ if ( deviceExtension->AdapterInterrupt.Selected ||
+ deviceExtension->AdapterInterrupt.SelectedWithAttention ||
+ deviceExtension->AdapterStatus.GrossError ||
+ deviceExtension->InterruptCount > MAX_INTERRUPT_COUNT) {
+
+ //
+ // Things are really messed up. Reset the bus, the chip and
+ // bail out.
+ //
+
+ NcrPrint((0,
+ "NcrInterruptServiceRoutine: Unexpected error. Interrupt Count=%d\n",
+ deviceExtension->InterruptCount
+ ));
+
+ NcrDumpState(deviceExtension);
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+ NcrLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 1);
+ return(TRUE);
+ }
+
+ //
+ // Check for a bus reset.
+ //
+
+ if (deviceExtension->AdapterInterrupt.ScsiReset) {
+
+ //
+ // Check if this was an expected reset.
+ //
+
+ if (!(deviceExtension->AdapterFlags & PD_EXPECTING_RESET_INTERRUPT)) {
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: SCSI bus reset detected\n"));
+
+ //
+ // Cleanup the logical units and notify the port driver,
+ // then return.
+ //
+
+ NcrCleanupAfterReset(deviceExtension, TRUE);
+ ScsiPortNotification(
+ ResetDetected,
+ deviceExtension,
+ NULL
+ );
+
+ } else {
+ deviceExtension->AdapterFlags &= ~PD_EXPECTING_RESET_INTERRUPT;
+ }
+
+ //
+ // Stall for a short time. This allows interrupt to clear.
+ //
+
+ ScsiPortStallExecution(INTERRUPT_STALL_TIME);
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
+
+ //
+ // Note that this should only happen in firmware where the interrupts
+ // are polled.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ //
+ // Call NcrStartIo to start the pending request.
+ // Note that NcrStartIo is idempotent when called with
+ // the same arguments.
+ //
+
+ NcrStartIo(
+ deviceExtension,
+ deviceExtension->NextSrbRequest
+ );
+
+ }
+
+ return(TRUE);
+ }
+
+ //
+ // Check for parity errors.
+ //
+
+ if (deviceExtension->AdapterStatus.ParityError) {
+
+ //
+ // The SCSI protocol chip has set ATN: we expect the target to
+ // go into message-out so that a error message can be sent and the
+ // operation retried. After the error has been noted, continue
+ // processing the interrupt. The message sent depends on whether a
+ // message was being received or something else. If the status
+ // is currently message-in then send-message PARITY ERROR;
+ // otherwise, send INITIATOR DETECTED ERROR.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Parity error detected.\n"));
+ NcrDumpState(deviceExtension);
+
+ //
+ // If the current phase is MESSAGE_IN then special handling is requred.
+ //
+
+ if (deviceExtension->AdapterStatus.Phase == MESSAGE_IN) {
+
+ //
+ // If the current state is CommandComplete, then the fifo contains
+ // a good status byte. Save the status byte before handling the
+ // message parity error.
+ //
+
+ if (deviceExtension->AdapterState == CommandComplete) {
+
+ srb = deviceExtension->ActiveLuRequest;
+
+ srb->ScsiStatus = SCSI_READ(
+ deviceExtension->Adapter,
+ Fifo
+ );
+
+ SRB_EXT(srb)->SrbExtensionFlags |= PD_STATUS_VALID;
+
+ }
+
+ //
+ // Set the message to indicate a message parity error, flush the
+ // fifo and accept the message.
+ //
+
+ deviceExtension->MessageBuffer[0] = SCSIMESS_MESS_PARITY_ERROR;
+ SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
+ NcrAcceptMessage(deviceExtension, TRUE, TRUE);
+
+ //
+ // Since the message which was in the fifo is no good. Clear the
+ // function complete interrupt which indicates that a message byte
+ // has been recieved. If this is a reselection, then this will
+ // a bus reset to occur. This cause is not handled well in this
+ // code, because it is not setup to deal with a target id and no
+ // logical unit.
+ //
+
+ deviceExtension->AdapterInterrupt.FunctionComplete = FALSE;
+
+ } else {
+
+ deviceExtension->MessageBuffer[0] = SCSIMESS_INIT_DETECTED_ERROR;
+
+ }
+
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageSent = 0;
+ deviceExtension->AdapterState = MessageOut;
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+
+ if (!(deviceExtension->AdapterFlags & PD_PARITY_ERROR_LOGGED)) {
+ NcrLogError(deviceExtension, SP_BUS_PARITY_ERROR, 2);
+ deviceExtension->AdapterFlags |= PD_PARITY_ERROR_LOGGED;
+ }
+
+ }
+
+
+ //
+ // Check for bus disconnection. If this was expected, then the next request
+ // can be processed. If a selection was being attempted, then perhaps the
+ // logical unit is not there or has gone away. Otherwise, this is an
+ // unexpected disconnect and should be reported as an error.
+ //
+
+ if (deviceExtension->AdapterInterrupt.Disconnect) {
+
+ srb = deviceExtension->NextSrbRequest;
+
+ //
+ // Check for an unexpected disconnect. This occurs if the state is
+ // not ExpectingDisconnect and a selection did not fail. A selection
+ // failure is indicated by state of AttemptingSelect and a sequence
+ // step of 0.
+ //
+
+ if (deviceExtension->AdapterState == AttemptingSelect &&
+ deviceExtension->SequenceStep.Step == 0) {
+
+ //
+ // The target selection failed. Log the error. If the retry
+ // count is not exceeded then retry the selection; otherwise
+ // fail the request.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(
+ deviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun
+ );
+
+ if (luExtension->RetryCount++ >= RETRY_SELECTION_LIMIT) {
+
+ //
+ // Clear the Active request in the logical unit.
+ //
+
+ luExtension->RetryCount = 0;
+
+ if (deviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
+
+ //
+ // Process the completion of the send message request.
+ // Set the ActiveLogicalUnit for NcrCompleteSendMessage.
+ // ActiveLogicalUnit is cleared after it returns.
+ //
+
+ deviceExtension->ActiveLogicalUnit = luExtension;
+
+ NcrCompleteSendMessage(
+ deviceExtension,
+ SRB_STATUS_SELECTION_TIMEOUT
+ );
+
+ deviceExtension->ActiveLogicalUnit = NULL;
+
+ } else {
+
+ srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+
+ ScsiPortNotification(
+ RequestComplete,
+ deviceExtension,
+ srb
+ );
+
+ luExtension->ActiveLuRequest = NULL;
+ }
+
+ deviceExtension->NextSrbRequest = NULL;
+ deviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
+
+ ScsiPortNotification(
+ NextRequest,
+ deviceExtension,
+ NULL
+ );
+
+ }
+
+ //
+ // If the request needs to be retried, it will be automatically
+ // because the PD_PENDING_START_IO flag is still set, and the
+ // following code will cause it to be restarted.
+ //
+
+ //
+ // The chip leaves some of the command in the FIFO, so clear the
+ // FIFO so there is no garbage left in it.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
+
+ } else if ( deviceExtension->AdapterState == DisconnectExpected ||
+ deviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED) {
+
+ //
+ // Check to see if this was a send-message request which is
+ // completed when the disconnect occurs.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
+
+ //
+ // Complete the request.
+ //
+
+ NcrCompleteSendMessage( deviceExtension,
+ SRB_STATUS_SUCCESS
+ );
+ }
+
+ } else {
+
+ //
+ // The disconnect was unexpected treat it as an error.
+ // Check to see if a data transfer was in progress, if so flush
+ // the DMA.
+ //
+
+ if (deviceExtension->AdapterState == DataTransfer) {
+ ScsiPortFlushDma(deviceExtension);
+ }
+
+ //
+ // NOTE: If the state is AttemptingSelect, then ActiveLogicalUnit
+ // is NULL!
+ //
+
+ //
+ // The chip leaves some of the command in the FIFO, so clear the
+ // FIFO so there is not garbage left in it.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
+
+ //
+ // An unexpected disconnect has occurred. Log the error. It is
+ // not clear if the device will respond again, so let the time-out
+ // code clean up the request if necessary.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected bus disconnect\n"));
+
+ NcrLogError(deviceExtension, SP_UNEXPECTED_DISCONNECT, 3);
+ }
+
+ //
+ // Clean up the adapter state to indicate the bus is now free, enable
+ // reselection, and start any pending request.
+ //
+
+ deviceExtension->AdapterState = BusFree;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->ActiveLuRequest = NULL;
+ SCSI_WRITE(deviceExtension->Adapter, Command, ENABLE_SELECTION_RESELECTION);
+
+#if DBG
+ if (NcrDebug) {
+ NcrPrint((0, "NcrInterruptServiceRoutine: DisconnectComplete.\n"));
+ }
+#endif
+
+ if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ ASSERT(deviceExtension->NextSrbRequest->SrbExtension != NULL);
+
+ //
+ // Check that the next request is still active. This should not
+ // be necessary, but it appears there is a hole somewhere.
+ //
+
+ srb = deviceExtension->NextSrbRequest;
+ srb = ScsiPortGetSrb(
+ deviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun,
+ srb->QueueTag
+ );
+
+ ASSERT(srb == deviceExtension->NextSrbRequest ||
+ deviceExtension->NextSrbRequest->Function != SRB_FUNCTION_EXECUTE_SCSI);
+
+ if (srb != deviceExtension->NextSrbRequest &&
+ deviceExtension->NextSrbRequest->Function == SRB_FUNCTION_EXECUTE_SCSI) {
+
+ NcrPrint((1, "NcrInterruptServiceRoutine: Found in active SRB in next request field.\n"));
+ NcrDumpState(deviceExtension);
+
+ //
+ // Dump it on the floor.
+ //
+
+ deviceExtension->NextSrbRequest = NULL;
+ deviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
+
+ NcrLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 18);
+
+ ScsiPortNotification(
+ NextRequest,
+ deviceExtension,
+ NULL
+ );
+
+ } else {
+
+ //
+ // Call NcrStartIo to start the pending request.
+ // Note that NcrStartIo is idempotent when called with
+ // the same arguments.
+ //
+
+ NcrStartIo(
+ deviceExtension,
+ deviceExtension->NextSrbRequest
+ );
+
+ }
+ }
+ }
+
+
+ //
+ // Check for a reselection interrupt.
+ //
+
+ if (deviceExtension->AdapterInterrupt.Reselected) {
+ UCHAR targetId;
+ UCHAR luId;
+
+ //
+ // The usual case is not to set attention so initialize the
+ // varible to FALSE.
+ //
+
+ setAttention = FALSE;
+
+ //
+ // If the FunctionComplete interrupt is not set then the target did
+ // not send an IDENTFY message. This is a fatal protocol violation.
+ // Reset the bus to get rid of this target.
+ //
+
+ if (!deviceExtension->AdapterInterrupt.FunctionComplete) {
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Reselection Failed.\n"));
+ NcrDumpState(deviceExtension);
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+ NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 4);
+
+ return(TRUE);
+ }
+
+ //
+ // The target Id and the logical unit id are in the FIFO. Use them to
+ // get the connected active logical unit.
+ //
+
+ luId = SCSI_READ(deviceExtension->Adapter, Fifo);
+
+ //
+ // The select id has two bits set. One is the SCSI bus id of the
+ // initiator and the other is the reselecting target id. The initiator
+ // id must be stripped and the remaining bit converted to a bit number
+ // to get the target id.
+ //
+
+ luId &= ~deviceExtension->AdapterBusIdMask;
+ WHICH_BIT(luId, targetId);
+
+ luId = SCSI_READ(deviceExtension->Adapter, Fifo);
+
+ //
+ // The logical unit id is stored in the low-order 3 bits of the
+ // IDENTIFY message, so the upper bits must be stripped off the
+ // byte read from the FIFO to get the logical unit number.
+ //
+
+ luId &= SCSI_MAXIMUM_LOGICAL_UNITS - 1;
+
+ luExtension = ScsiPortGetLogicalUnit( deviceExtension,
+ 0,
+ targetId,
+ luId
+ );
+
+ //
+ // Check to that this is a valid logical unit.
+ //
+
+ if (luExtension == NULL) {
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Reselection Failed.\n"));
+ NcrDumpState(deviceExtension);
+
+
+ ScsiPortLogError(
+ deviceExtension, // HwDeviceExtension,
+ NULL, // Srb
+ 0, // PathId,
+ targetId, // TargetId,
+ luId, // Lun,
+ SP_INVALID_RESELECTION, // ErrorCode,
+ 4 // UniqueId
+ );
+
+ //
+ // Send an abort message. Put the message in the buffer, set the
+ // state, indicate that a disconnect is expected after this, and
+ // set the attention signal.
+ //
+
+ deviceExtension->MessageBuffer[0] = SCSIMESS_ABORT;
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageSent = 0;
+ deviceExtension->AdapterState = MessageOut;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID |
+ PD_DISCONNECT_EXPECTED;
+
+ setAttention = TRUE;
+
+ } else {
+
+ //
+ // Everything looks ok.
+ //
+
+ //
+ // A reselection has been completed. Set the active logical
+ // unit, restore the active data pointer, and set the state.
+ // In addition, any adpater flags set by a pending select
+ // must be cleared using the disconnect mask.
+ //
+
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->ActiveLogicalUnit = luExtension;
+ deviceExtension->AdapterState = Reselected;
+ deviceExtension->MessageCount = 0;
+
+ srb = luExtension->ActiveLuRequest;
+ deviceExtension->ActiveLuRequest = srb;
+
+ if (srb == NULL) {
+
+ //
+ // This must be a reconnect for a tagged request.
+ // Indicate a queue tag message is expected next and save
+ // the target and logical unit ids.
+ //
+
+ deviceExtension->AdapterFlags |= PD_EXPECTING_QUEUE_TAG;
+ deviceExtension->Lun = luId;
+ } else {
+
+ deviceExtension->ActiveDataPointer = SRB_EXT(srb)->SavedDataPointer;
+ deviceExtension->ActiveDataLength = SRB_EXT(srb)->SavedDataLength;
+
+ }
+ }
+
+ //
+ // The bus is waiting for the message to be accepted. The attention
+ // signal will be set if this is not a valid reselection. Finally,
+ // the synchronous data tranfer parameters need to be set in case a
+ // data transfer is done.
+ //
+
+ deviceExtension->TargetId = targetId;
+ NcrAcceptMessage(deviceExtension, setAttention, TRUE);
+ deviceExtension->InterruptCount = 0;
+
+ } else if (deviceExtension->AdapterInterrupt.FunctionComplete) {
+
+ //
+ // Check for function complete interrupt if there was not a reselected
+ // interrupt. The function complete interrupt has already been checked
+ // in the previous case.
+ //
+ // The function complete interrupt occurs after the following cases:
+ // A select succeeded
+ // A message byte has been read
+ // A status byte and message byte have been read when in the
+ // command complete state.
+ // A reselection (handled above)
+ //
+ // Switch on the state current state of the bus to determine what
+ // action should be taken now the function has completed.
+ //
+
+ switch (deviceExtension->AdapterState) {
+ case AttemptingSelect:
+
+ //
+ // The target was successfully selected. Set the active
+ // logical unit field, clear the next logical unit, and
+ // notify the OS-dependent driver that a new request can
+ // be accepted. The state is set to MessageOut since is
+ // the next thing done after a selection.
+ //
+
+ deviceExtension->ActiveLogicalUnit = ScsiPortGetLogicalUnit(
+ deviceExtension,
+ deviceExtension->NextSrbRequest->PathId,
+ deviceExtension->NextSrbRequest->TargetId,
+ deviceExtension->NextSrbRequest->Lun
+ );
+
+ srb = deviceExtension->NextSrbRequest;
+ deviceExtension->ActiveLuRequest = srb;
+
+ //
+ // Restore the data pointers.
+ //
+
+ deviceExtension->ActiveDataPointer = SRB_EXT(srb)->SavedDataPointer;
+ deviceExtension->ActiveDataLength = SRB_EXT(srb)->SavedDataLength;
+
+ //
+ // The next request has now become the active request.
+ // Clear the state associated with the next request and ask for
+ // another one to start.
+ //
+
+ deviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
+ deviceExtension->NextSrbRequest = NULL;
+ deviceExtension->AdapterState = MessageOut;
+
+ //
+ // If this was a tagged request then indicate that the next
+ // request for this lu may be sent.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_TAGGED_SELECT) {
+
+ ScsiPortNotification(
+ NextLuRequest,
+ deviceExtension,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun
+ );
+
+ } else {
+
+ ScsiPortNotification(
+ NextRequest,
+ deviceExtension,
+ NULL
+ );
+
+ }
+
+ break;
+
+ case CommandComplete:
+
+ //
+ // The FIFO contains the status byte and a message byte. Save the
+ // status byte and set the state to look like MessageIn, then fall
+ // through to the message-in state.
+ //
+
+ srb = deviceExtension->ActiveLuRequest;
+
+ ASSERT(deviceExtension->NextSrbRequest != srb);
+
+ srb->ScsiStatus = SCSI_READ(
+ deviceExtension->Adapter,
+ Fifo
+ );
+
+ SRB_EXT(srb)->SrbExtensionFlags |= PD_STATUS_VALID;
+
+ deviceExtension->AdapterState = MessageIn;
+ deviceExtension->MessageCount = 0;
+ deviceExtension->AdapterFlags &= ~PD_MESSAGE_OUT_VALID;
+
+ //
+ // Fall through and process the message byte in the FIFO.
+ //
+
+ case MessageIn:
+
+ //
+ // A message byte has been received. Store it in the message buffer
+ // and call message decode to determine what to do. The message
+ // byte will either be accepted, or cause a message to be sent.
+ // A message-out is indicated to the target by setting the ATN
+ // line before sending the SCSI protocol chip the MESSAGE_ACCEPTED
+ // command.
+ //
+
+ deviceExtension->MessageBuffer[deviceExtension->MessageCount++] =
+ SCSI_READ( deviceExtension->Adapter, Fifo );
+
+ if (NcrMessageDecode( deviceExtension )) {
+
+ //
+ // NcrMessageDecode returns TRUE if there is a message to be
+ // sent out. This message will normally be a MESSAGE REJECT
+ // or a SYNCHRONOUS DATA TRANSFER REQUEST. In any case, the
+ // message has been set by NcrMessageDecode. All that needs
+ // to be done here is set the ATN signal and set
+ // PD_MESSAGE_OUT_VALID in the adapter flags.
+ //
+
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+ setAttention = TRUE;
+ } else {
+ setAttention = FALSE;
+ }
+
+ //
+ // In either case, tell the SCSI protocol chip to acknowlege or
+ // accept the message. The synchronous data transfer parameters
+ // do not need to be set.
+ //
+
+ NcrAcceptMessage( deviceExtension, setAttention, FALSE);
+ break;
+
+ default:
+
+ //
+ // A function complete should not occur while in any other states.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected function complete interrupt.\n"));
+ NcrDumpState(deviceExtension);
+
+ }
+ }
+
+
+ //
+ // Check for a bus service interrupt. This interrupt indicates the target
+ // is requesting some form of bus transfer. The bus transfer type is
+ // determined by the bus phase.
+ //
+
+ if (deviceExtension->AdapterInterrupt.BusService) {
+
+ luExtension = deviceExtension->ActiveLogicalUnit;
+
+ if (luExtension == NULL) {
+
+ //
+ // There should never be an bus service interrupt without an
+ // active locgial unit. The bus or the chip is really messed up.
+ // Reset the bus and return.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected Bus service interrupt.\n"));
+ NcrDumpState(deviceExtension);
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+ NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 6);
+
+ return(TRUE);
+ }
+
+ srb = deviceExtension->ActiveLuRequest;
+
+ //
+ // If there is no current srb request then the bus service interrupt
+ // must be a message in with a tag.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_EXPECTING_QUEUE_TAG &&
+ deviceExtension->AdapterStatus.Phase != MESSAGE_IN ) {
+
+ //
+ // A bus service interrupt occured when a queue tag message
+ // was exepected. Is a protocol error by the target reset the
+ // bus.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected Bus service interrupt when queue tag expected.\n"));
+ NcrDumpState(deviceExtension);
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+ NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 13);
+
+ return(TRUE);
+
+ }
+
+ //
+ // The bus is changing phases or needs more data. Generally, the target
+ // can change bus phase at any time: in particular, in the middle of
+ // a data transfer. The initiator must be able to restart a transfer
+ // where it left off. To do this it must know how much data was
+ // transferred. If the previous state was a data transfer, then the
+ // amount of data transferred needs to be determined, saved and
+ // the DMA flushed.
+ //
+
+ if (deviceExtension->AdapterState == DataTransfer) {
+ SCSI_FIFO_FLAGS fifoFlags;
+
+ //
+ // Figure out how many bytes have been transferred based on the
+ // original transfer count stored in the ActiveLengthField,
+ // SCSI protocol chip transfer counters, and
+ // the number of bytes in the FIFO. The normal case is when all
+ // the bytes have been transferred so check for that using the
+ // TerminalCount bit in the status field.
+ //
+
+ i = 0;
+
+ if (!deviceExtension->AdapterStatus.TerminalCount) {
+
+ //
+ // Read bits 23-16 if this chip has that register.
+ //
+
+ if (deviceExtension->ChipType == Fas216) {
+
+ i = (SCSI_READ(deviceExtension->Adapter,
+ TransferCountPage
+ )) << 16;
+
+ }
+
+ //
+ // Read the current value of the tranfer count registers;
+ //
+
+ i |= (SCSI_READ(deviceExtension->Adapter, TransferCountHigh)) << 8;
+ i |= SCSI_READ(deviceExtension->Adapter, TransferCountLow );
+
+ //
+ // A value of zero in i and TerminalCount clear indicates
+ // that the transfer length was 64K and that no bytes were
+ // transferred. Set i to 64K.
+ //
+
+ if (i == 0) {
+ i = 0x10000;
+ }
+
+ }
+
+ //
+ // If this is a write then there may still be some bytes in the
+ // FIFO which have yet to be transferred to the target.
+ //
+
+ if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+ *((PUCHAR) &fifoFlags) = SCSI_READ(deviceExtension->Adapter,
+ FifoFlags
+ );
+ i += fifoFlags.ByteCount;
+
+
+ if (i == 1 && deviceExtension->ChipType == Fas216) {
+
+ //
+ // This is a chip bug. If the bus state is still data
+ // out then tell the chip to transfer one more byte.
+ //
+
+ NcrPrint((1, "NcrInterruptServiceRoutine: One byte left!\n"));
+
+ //
+ // Set the transfer count.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter,
+ TransferCountLow,
+ 1
+ );
+ SCSI_WRITE( deviceExtension->Adapter,
+ TransferCountHigh,
+ 0
+ );
+
+ SCSI_WRITE(deviceExtension->Adapter,
+ TransferCountPage,
+ 0
+ );
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, TRANSFER_INFORMATION);
+
+ return(TRUE);
+ }
+
+ //
+ // The chip leaves some data in the FIFO, so clear the
+ // FIFO so there is not garbage left in it.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
+ }
+
+ //
+ // i now contains the number of bytes to be transferred.
+ // Check to see if this the maximum that has be transferred so far,
+ // and update the active data pointer and the active length.
+ //
+
+ if (srb->DataTransferLength - i >
+ SRB_EXT(srb)->MaximumTransferLength) {
+ SRB_EXT(srb)->MaximumTransferLength = srb->DataTransferLength -
+ i;
+ }
+
+ deviceExtension->ActiveDataPointer +=
+ deviceExtension->ActiveDataLength - i;
+ deviceExtension->ActiveDataLength = i;
+
+ //
+ // Flush the DMA to ensure all the bytes are transferred.
+ //
+
+ deviceExtension->AdapterFlags &= ~PD_PENDING_DATA_TRANSFER;
+ ScsiPortFlushDma(deviceExtension);
+
+ } else if (deviceExtension->AdapterState == DisconnectExpected) {
+
+ //
+ // This is an error; however, some contollers attempt to read more
+ // message bytes even after a message indicating a disconnect.
+ // If the request is for a message transfer and extra bytes
+ // are expected, then allow the transfer; otherwise, reset the bus.
+ //
+
+ if (!(deviceExtension->AdapterFlags & PD_POSSIBLE_EXTRA_MESSAGE_OUT)
+ || (deviceExtension->AdapterStatus.Phase != MESSAGE_OUT &&
+ deviceExtension->AdapterStatus.Phase != MESSAGE_IN)) {
+
+ //
+ // If a disconnect was expected and a bus service interrupt was
+ // detected, then a SCSI protocol error has been detected and the
+ // SCSI bus should be reset to clear the condition.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Bus request while disconnect expected.\n"));
+ NcrDumpState(deviceExtension);
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+ NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 7);
+
+ return(TRUE);
+ } else {
+
+ //
+ // Make sure the disconnect-expected flag is set.
+ //
+
+ deviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
+ }
+ } else if (deviceExtension->AdapterState == MessageOut) {
+
+ //
+ // The SCSI protocol chip indicates that the message has been sent;
+ // however, the target may need to reread the message or there
+ // may be more messages to send. This condition is indicated by a
+ // message-out bus phase; otherwise, the message has been accepted
+ // by the target. If message has been accepted then check to see
+ // if any special processing is necessary. Note that the driver
+ // state is set to MessageOut after the PD_DISCONNECT_EXPECTED is
+ // set, or after a selection. So it is only necessary to check for
+ // PD_DISCONNECT_EXPECTED when the driver state is currently in
+ // MessageOut.
+ //
+
+ if (deviceExtension->AdapterFlags & (PD_DISCONNECT_EXPECTED |
+ PD_SYNCHRONOUS_TRANSFER_SENT | PD_SYNCHRONOUS_RESPONSE_SENT) &&
+ deviceExtension->AdapterStatus.Phase != MESSAGE_OUT &&
+ deviceExtension->AdapterStatus.Phase != MESSAGE_IN) {
+
+ if (deviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED) {
+
+ //
+ // If a disconnect was expected and a bus service interrupt was
+ // detected, then a SCSI protocol error has been detected and the
+ // SCSI bus should be reset to clear the condition.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Bus request while disconnect expected after message-out.\n"));
+ NcrDumpState(deviceExtension);
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+ NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 8);
+
+ return(TRUE);
+
+ } else if (deviceExtension->AdapterFlags &
+ PD_SYNCHRONOUS_TRANSFER_SENT) {
+
+ //
+ // The controller ignored the synchronous transfer message.
+ // Treat it as a rejection and clear the necessary state.
+ //
+
+ deviceExtension->TargetState[deviceExtension->TargetId]
+ .TargetFlags |=
+ PD_SYNCHRONOUS_NEGOTIATION_DONE | PD_DO_NOT_NEGOTIATE;
+ deviceExtension->AdapterFlags &=
+ ~(PD_SYNCHRONOUS_RESPONSE_SENT |
+ PD_SYNCHRONOUS_TRANSFER_SENT);
+ } else if (deviceExtension->AdapterFlags &
+ PD_SYNCHRONOUS_RESPONSE_SENT) {
+
+ //
+ // The target controller accepted the negotiation. Set
+ // the done flag in the logical unit and clear the
+ // negotiation flags in the adapter.
+ //
+
+ deviceExtension->TargetState[deviceExtension->TargetId].TargetFlags |=
+ PD_SYNCHRONOUS_NEGOTIATION_DONE | PD_DO_NOT_NEGOTIATE;
+ deviceExtension->AdapterFlags &=
+ ~(PD_SYNCHRONOUS_RESPONSE_SENT |
+ PD_SYNCHRONOUS_TRANSFER_SENT);
+
+ }
+ }
+ }
+
+ //
+ // If the bus phase is not DATA_IN then the FIFO may need to be
+ // flushed. The FIFO cannot be flushed while the bus is in the
+ // DATA_IN phase because the FIFO already has data bytes in it.
+ // The only case where a target can legally switch phases while
+ // there are message bytes in the FIFO to the MESSAGE_OUT bus
+ // phase. If the target leaves message bytes and attempts to
+ // goto a DATA_IN phase, then the transfer will appear to overrun
+ // and be detected as an error.
+ //
+
+ if (deviceExtension->AdapterStatus.Phase != DATA_IN) {
+ SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
+ }
+
+ //
+ // Decode the current bus phase.
+ //
+
+ switch (deviceExtension->AdapterStatus.Phase) {
+
+ case COMMAND_OUT:
+
+ //
+ // Fill the FIFO with the commnad and tell the SCSI protocol chip
+ // to go.
+ //
+
+ for (i = 0; i < srb->CdbLength; i++) {
+ SCSI_WRITE( deviceExtension->Adapter,
+ Fifo,
+ srb->Cdb[i]
+ );
+ }
+
+ SCSI_WRITE( deviceExtension->Adapter,
+ Command,
+ TRANSFER_INFORMATION
+ );
+
+ deviceExtension->AdapterState = CommandOut;
+
+ break;
+
+ case STATUS_IN:
+
+ //
+ // Setup of the SCSI protocol chip to read in the status and the
+ // following message byte, and set the adapter state.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, COMMAND_COMPLETE );
+ deviceExtension->AdapterState = CommandComplete;
+
+ break;
+
+ case MESSAGE_OUT:
+
+ //
+ // The target is requesting a message-out. There are three
+ // possible cases. First, the target is improperly requesting
+ // a message. Second, a message has been sent, but the target
+ // could not read it properly. Third, a message has been
+ // partially sent and the target is requesting the remainder
+ // of the message.
+ //
+ // The first case is indicated when the MessageCount is zero or
+ // the message-out flag is not set.
+ //
+
+ if ( deviceExtension->MessageCount == 0 ||
+ !(deviceExtension->AdapterFlags & PD_MESSAGE_OUT_VALID)) {
+
+ //
+ // If extra message-outs are possible then just send a NOP
+ // message.
+
+ if (deviceExtension->AdapterFlags &
+ PD_POSSIBLE_EXTRA_MESSAGE_OUT) {
+
+ //
+ // Set the message to NOP and clear the extra message
+ // flag. This is a hack for controllers that do not
+ // properly read the entire message.
+ //
+
+ deviceExtension->MessageBuffer[0] = SCSIMESS_NO_OPERATION;
+ deviceExtension->AdapterFlags &=
+ ~PD_POSSIBLE_EXTRA_MESSAGE_OUT;
+ } else {
+
+ //
+ // Send an INITIATOR DETECTED ERROR message.
+ //
+
+ deviceExtension->MessageBuffer[0] =
+ SCSIMESS_INIT_DETECTED_ERROR;
+ NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 9);
+ NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected message-out request\n"));
+ NcrDumpState(deviceExtension);
+
+ }
+
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageSent = 0;
+ deviceExtension->AdapterState = MessageOut;
+
+ }
+
+ //
+ // The second case is indicated when MessageCount and MessageSent
+ // are equal and nonzero.
+ //
+
+ if (deviceExtension->MessageCount == deviceExtension->MessageSent){
+
+ //
+ // The message needs to be resent, so set ATN, clear MessageSent
+ // and fall through to the next case.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, SET_ATTENTION);
+ deviceExtension->MessageSent = 0;
+ }
+
+ if (deviceExtension->MessageCount != deviceExtension->MessageSent){
+
+ //
+ // The ATTENTION signal needs to be set if the current state
+ // is not MessageOut.
+ //
+
+ if (deviceExtension->AdapterState != MessageOut) {
+
+ SCSI_WRITE(
+ deviceExtension->Adapter,
+ Command,
+ SET_ATTENTION
+ );
+ }
+
+ //
+ // There is more message to send. Fill the FIFO with the
+ // message and tell the SCSI protocol chip to transfer the
+ // message.
+ //
+
+ for (;
+ deviceExtension->MessageSent <
+ deviceExtension->MessageCount;
+ deviceExtension->MessageSent++ ) {
+
+ SCSI_WRITE(deviceExtension->Adapter,
+ Fifo,
+ deviceExtension->
+ MessageBuffer[deviceExtension->MessageSent]
+ );
+
+ }
+
+ SCSI_WRITE(deviceExtension->Adapter,
+ Command,
+ TRANSFER_INFORMATION
+ );
+
+ }
+
+ break;
+
+ case MESSAGE_IN:
+
+ //
+ // If this is the first byte of the message then initialize
+ // MessageCount and the adapter state. The message buffer
+ // cannot overflow because the message decode function will
+ // take care of the message before the buffer is full.
+ // The SCSI protocol chip will interrupt for each message
+ // byte.
+ //
+
+ if ( deviceExtension->AdapterState != MessageIn &&
+ deviceExtension->AdapterState != MessageAccepted ) {
+
+ deviceExtension->AdapterFlags &= ~PD_MESSAGE_OUT_VALID;
+ deviceExtension->MessageCount = 0;
+ }
+
+ deviceExtension->AdapterState = MessageIn;
+
+ SCSI_WRITE( deviceExtension->Adapter,
+ Command,
+ TRANSFER_INFORMATION
+ );
+
+ break;
+
+ case DATA_OUT:
+ case DATA_IN:
+
+ //
+ // Check that the transfer direction is ok, setup the DMA, set
+ // the synchronous transfer parameter, and tell the chip to go.
+ // Also check that there is still data to be transferred.
+ //
+
+ if ((!(srb->SrbFlags & SRB_FLAGS_DATA_IN) &&
+ deviceExtension->AdapterStatus.Phase == DATA_IN) ||
+
+ (!(srb->SrbFlags & SRB_FLAGS_DATA_OUT) &&
+ deviceExtension->AdapterStatus.Phase == DATA_OUT) ||
+
+ deviceExtension->ActiveDataLength == 0 ) {
+
+ //
+ // The data direction is incorrect. Reset the bus to clear
+ // things up.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Illegal transfer direction.\n"));
+ NcrDumpState(deviceExtension);
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+ NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 10);
+
+ return(TRUE);
+ }
+
+ //
+ // Set the transfer count.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter,
+ TransferCountLow,
+ (UCHAR) deviceExtension->ActiveDataLength
+ );
+ SCSI_WRITE( deviceExtension->Adapter,
+ TransferCountHigh,
+ (UCHAR) (deviceExtension->ActiveDataLength >> 8)
+ );
+
+ //
+ // Write bits 23-16 if this chip has that register.
+ //
+
+ if (deviceExtension->ChipType == Fas216) {
+
+ SCSI_WRITE(deviceExtension->Adapter,
+ TransferCountPage,
+ (UCHAR) (deviceExtension->ActiveDataLength >> 16)
+ );
+
+ }
+
+ //
+ // Clear the extra data transfer flags correctly.
+ //
+
+ if (deviceExtension->AdapterStatus.Phase == DATA_IN) {
+ srb->SrbFlags &= ~SRB_FLAGS_DATA_OUT;
+ } else {
+ srb->SrbFlags &= ~SRB_FLAGS_DATA_IN;
+ }
+
+ //
+ // Set up the DMA controller.
+ //
+
+ deviceExtension->AdapterState = DataTransfer;
+ deviceExtension->AdapterFlags |= PD_PENDING_DATA_TRANSFER;
+
+ ScsiPortIoMapTransfer( deviceExtension,
+ srb,
+ (PVOID) deviceExtension->ActiveDataPointer,
+ deviceExtension->ActiveDataLength
+ );
+
+ break;
+
+ default:
+
+ //
+ // This phase is illegal and indicates a serious error. Reset the
+ // bus to clear the problem.
+ //
+
+ NcrPrint((0, "NcrInterruptServiceRoutine: Illegal bus state detected.\n"));
+ NcrDumpState(deviceExtension);
+
+ NcrResetScsiBusInternal(deviceExtension, 0);
+ NcrInitializeAdapter(deviceExtension);
+
+ NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 11);
+
+ return(TRUE);
+ }
+ }
+
+ //
+ // Stall for a short time. This allows interrupt to clear and gives new
+ // interrupts a chance to fire.
+ //
+
+ ScsiPortStallExecution(INTERRUPT_STALL_TIME);
+
+ //
+ // Make sure there is really an interrupt before reading the other
+ // registers, particularly, the interrupt register.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_NCR_ADAPTER) {
+
+ *((PUCHAR) &DmaStatus) = SCSI_READ( deviceExtension->AdapterBase, DmaStatus );
+
+ if (DmaStatus.Interrupt == deviceExtension->InterruptPending) {
+ *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ( deviceExtension->Adapter, ScsiStatus );
+ deviceExtension->InterruptCount++;
+ goto NextInterrupt;
+
+ }
+ } else {
+
+ *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ ( deviceExtension->Adapter, ScsiStatus );
+
+ if (deviceExtension->AdapterStatus.Interrupt) {
+ deviceExtension->InterruptCount++;
+ goto NextInterrupt;
+
+ }
+ }
+
+ return(TRUE);
+}
+
+VOID
+NcrLogError(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG ErrorCode,
+ IN ULONG UniqueId
+ )
+/*++
+
+Routine Description:
+
+ This routine logs an error.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension for the
+ port adapter to which the completing target controller is connected.
+
+ ErrorCode - Supplies the error code to log with the error.
+
+ UniqueId - Supplies the unique error identifier.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PSCSI_REQUEST_BLOCK srb;
+
+ //
+ // Look for a current request in the device extension.
+ //
+
+ if (DeviceExtension->ActiveLogicalUnit != NULL) {
+
+ if (DeviceExtension->ActiveLuRequest != NULL) {
+
+ srb = DeviceExtension->ActiveLuRequest;
+
+ } else {
+
+ srb = DeviceExtension->ActiveLogicalUnit->ActiveSendRequest;
+
+ }
+
+ } else {
+
+ srb = DeviceExtension->NextSrbRequest;
+
+ }
+
+ //
+ // If the srb is NULL, then log the error against the host adapter address.
+ //
+
+ if (srb == NULL) {
+
+ ScsiPortLogError(
+ DeviceExtension, // HwDeviceExtension,
+ NULL, // Srb
+ 0, // PathId,
+ DeviceExtension->AdapterBusId, // TargetId,
+ 0, // Lun,
+ ErrorCode, // ErrorCode,
+ UniqueId // UniqueId
+ );
+
+ } else {
+
+ ScsiPortLogError(
+ DeviceExtension, // HwDeviceExtension,
+ srb, // Srb
+ srb->PathId, // PathId,
+ srb->TargetId, // TargetId,
+ srb->Lun, // Lun,
+ ErrorCode, // ErrorCode,
+ UniqueId // UniqueId
+ );
+
+ }
+
+}
+
+
+VOID
+NcrProcessRequestCompletion(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ This routine does all of checking and state updating necessary when a
+ request terminates normally. It determines what the SrbStatus
+ should be and updates the state in the DeviceExtension, the
+ logicalUnitExtension and the srb.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension for the
+ port adapter on to which the completing target controller is connected.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ PSCSI_REQUEST_BLOCK srb;
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+ srb = DeviceExtension->ActiveLuRequest;
+
+ ASSERT(DeviceExtension->NextSrbRequest != srb);
+
+ if ( srb->ScsiStatus != SCSISTAT_GOOD &&
+ srb->ScsiStatus != SCSISTAT_CONDITION_MET &&
+ srb->ScsiStatus != SCSISTAT_INTERMEDIATE &&
+ srb->ScsiStatus != SCSISTAT_INTERMEDIATE_COND_MET ) {
+
+ //
+ // Indicate an abnormal status code.
+ //
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+
+ //
+ // Indicate that a INITIATE RECOVERY message was received. This
+ // indicates to the class driver that it must send a TERMINATE
+ // RECOVERY message before the logical unit will resume normal
+ // operation.
+ //
+
+ if (SRB_EXT(srb)->SrbExtensionFlags & PD_INITIATE_RECOVERY) {
+
+ //
+ // Modify the SrbStatus.
+ //
+
+ srb->SrbStatus = SRB_STATUS_ERROR_RECOVERY;
+ }
+
+ //
+ // If this is a check condition, then clear the synchronous negotiation
+ // done flag. This is done in case the controller was power cycled.
+ //
+
+ if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) {
+
+ DeviceExtension->TargetState[srb->TargetId].TargetFlags
+ &= ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
+
+ }
+
+ //
+ // If there is a pending request for this logical unit then return
+ // that request with a busy status. This situation only occurs when
+ // command queuing is enabled an a command pending for a logical unit
+ // at the same time that an error has occured. This may be a BUSY,
+ // QUEUE FULL or CHECK CONDITION. The important case is CHECK CONDITION
+ // because a contingatent aligance condition has be established and the
+ // port driver needs a chance to send a Reqeust Sense before the
+ // pending command is started.
+ //
+
+ if (DeviceExtension->AdapterFlags & PD_PENDING_START_IO &&
+ DeviceExtension->NextSrbRequest->PathId == srb->PathId &&
+ DeviceExtension->NextSrbRequest->TargetId == srb->TargetId &&
+ DeviceExtension->NextSrbRequest->Lun == srb->Lun) {
+
+ NcrPrint((1, "NcrProcessRequestCompletion: Failing request with busy status due to check condition\n"));
+ DeviceExtension->NextSrbRequest->SrbStatus =
+ SCSISTAT_CHECK_CONDITION;
+
+ DeviceExtension->NextSrbRequest->ScsiStatus = SCSISTAT_BUSY;
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ DeviceExtension->NextSrbRequest
+ );
+
+ //
+ // Make sure the request is not sitting in the logical unit.
+ //
+
+ if (DeviceExtension->NextSrbRequest == luExtension->ActiveLuRequest) {
+
+ luExtension->ActiveLuRequest = NULL;
+
+ } else if (DeviceExtension->NextSrbRequest ==
+ luExtension->ActiveSendRequest) {
+
+ luExtension->ActiveSendRequest = NULL;
+ }
+
+ DeviceExtension->NextSrbRequest = NULL;
+ DeviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
+
+ ScsiPortNotification(
+ NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ }
+
+ } else {
+
+ //
+ // Everything looks correct so far.
+ //
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ //
+ // Make sure that status is valid.
+ //
+
+ if (!(SRB_EXT(srb)->SrbExtensionFlags & PD_STATUS_VALID)) {
+
+ //
+ // The status byte is not valid.
+ //
+
+ srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+
+ //
+ // Log the error.
+ //
+
+ NcrLogError(DeviceExtension, SP_PROTOCOL_ERROR, 12);
+
+ }
+
+
+ }
+
+ //
+ // Check that data was transferred to the end of the buffer.
+ //
+
+ if ( SRB_EXT(srb)->MaximumTransferLength != srb->DataTransferLength ){
+
+ //
+ // The entire buffer was not transferred. Update the length
+ // and update the status code.
+ //
+
+ if (srb->SrbStatus == SRB_STATUS_SUCCESS) {
+
+ NcrPrint((1, "NcrProcessRequestCompletion: Short transfer, Actual: %x; Expected: %x;\n",
+ SRB_EXT(srb)->MaximumTransferLength,
+ srb->DataTransferLength
+ ));
+
+ //
+ // If no data was transferred then indicated this was a
+ // protocol error rather than a data under/over run.
+ //
+
+ if (srb->DataTransferLength == 0) {
+ srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ } else {
+ srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+ }
+
+ srb->DataTransferLength = SRB_EXT(srb)->MaximumTransferLength;
+ } else {
+
+ //
+ // Update the length if a check condition was returned.
+ //
+
+ if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) {
+ srb->DataTransferLength = SRB_EXT(srb)->MaximumTransferLength;
+ }
+ }
+ }
+
+ if (srb->SrbStatus != SRB_STATUS_SUCCESS) {
+ NcrPrint((1, "NcrProcessRequestCompletion: Request failed. ScsiStatus: %x, SrbStatus: %x\n",
+ srb->ScsiStatus,
+ srb->SrbStatus
+ ));
+ }
+
+ //
+ // Clear the request but not the ActiveLogicalUnit since the target has
+ // not disconnected from the SCSI bus yet.
+ //
+
+ DeviceExtension->ActiveLuRequest = NULL;
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->RetryCount = 0;
+ luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
+}
+
+BOOLEAN
+NcrResetScsiBus(
+ IN PVOID ServiceContext,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ This function resets the SCSI bus and calls the reset cleanup function.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the specific device extension.
+
+ PathId - Supplies the path id of the bus.
+
+Return Value:
+
+ TRUE - Indicating the reset is complete.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+
+ NcrPrint((1, "NcrResetScsiBus: Resetting the SCSI bus.\n"));
+
+ //
+ // The bus should be reset regardless of what is occurring on the bus or in
+ // the chip. The reset SCSI bus command executes immediately.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, RESET_SCSI_BUS);
+
+ //
+ // Delay the minimum assertion time for a SCSI bus reset to make sure a
+ // valid reset signal is sent.
+ //
+
+ ScsiPortStallExecution( RESET_STALL_TIME );
+
+ NcrCleanupAfterReset(deviceExtension, FALSE);
+ deviceExtension->AdapterFlags |= PD_EXPECTING_RESET_INTERRUPT;
+
+ return(TRUE);
+}
+
+VOID
+NcrResetScsiBusInternal(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG PathId
+ )
+/*++
+
+Routine Description:
+
+ This function resets the SCSI bus and notifies the port driver.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+ PathId - Supplies the path id of the bus.
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ ScsiPortNotification(
+ ResetDetected,
+ DeviceExtension,
+ NULL
+ );
+
+ NcrResetScsiBus(DeviceExtension, 0);
+}
+
+VOID
+NcrSelectTarget(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the hardware to select a target. If a valid message
+ is in the message buffer, it will be sent to the target. If the request
+ includes a SCSI command descriptor block, it will also be passed to the
+ target.
+
+Arguments:
+
+ DeviceExtension - Supplies the device extension for this HBA adapter.
+
+ LuExtension - Supplies the logical unit extension for the target being
+ selected.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK srb;
+ PSPECIFIC_TARGET_EXTENSION targetState;
+ SCSI_DMA_STATUS DmaStatus;
+ LONG i;
+
+ srb = DeviceExtension->NextSrbRequest;
+
+ targetState = &DeviceExtension->TargetState[srb->TargetId];
+
+#if DBG
+ if (NcrDebug) {
+ NcrPrint((0, "NcrSelectTarget: Attempting target select.\n"));
+ }
+#endif
+ /* Powerfail Start */
+
+ //
+ // Set up the SCSI protocol chip to select the target, transfer the
+ // IDENTIFY message and the CDB. This can be done by following steps:
+ //
+ // setting the destination register,
+ // filling the FIFO with the IDENTIFY message and the CDB
+ // setting the command register
+ //
+ // If the chip is not interrupting, then set up for selection. If the
+ // chip is interrupting then return. The interrupt will process the
+ // request. Note that if we get reselected after this point the chip
+ // will ignore the bytes written until the interrupt register is read.
+ // The commands that handle a message and a CDB can only be used if the
+ // message is one byte or 3 bytes long; otherwise only a one-byte message
+ // is transferred on the select and the remaining bytes are handled in the
+ // interrupt routine.
+ //
+
+ if (DeviceExtension->AdapterFlags & PD_NCR_ADAPTER) {
+
+ *((PUCHAR) &DmaStatus) = SCSI_READ( DeviceExtension->AdapterBase, DmaStatus );
+ if (DmaStatus.Interrupt == DeviceExtension->InterruptPending) {
+ return;
+ }
+
+ } else {
+
+ *((PUCHAR) &DeviceExtension->AdapterStatus) = SCSI_READ( DeviceExtension->Adapter, ScsiStatus );
+ if (DeviceExtension->AdapterStatus.Interrupt) {
+ return;
+ }
+
+ }
+
+ //
+ // Set the destination ID. Put the first byte of the message-in
+ // the fifo and set the command to select with ATN. This command
+ // selects the target, sends one message byte and interrupts. The
+ // ATN line remains set. The succeeding bytes are loaded into the
+ // FIFO and sent to the target by the interrupt service routine.
+ //
+
+ SCSI_WRITE(DeviceExtension->Adapter, DestinationId, srb->TargetId);
+ SCSI_WRITE( DeviceExtension->Adapter,
+ Fifo,
+ DeviceExtension->MessageBuffer[DeviceExtension->MessageSent++]
+ );
+
+ //
+ // Set the synchronous data transfer parameter registers in case a
+ // data transfer is done. These must be set before a data transfer
+ // is started.
+ //
+
+ SCSI_WRITE( DeviceExtension->Adapter,
+ SynchronousPeriod,
+ targetState->SynchronousPeriod
+ );
+ SCSI_WRITE( DeviceExtension->Adapter,
+ SynchronousOffset,
+ targetState->SynchronousOffset
+ );
+
+ SCSI_WRITE( DeviceExtension->Adapter,
+ Configuration3,
+ *((PCHAR) &targetState->Configuration3)
+ );
+
+
+ //
+ // Determine if this srb has a Cdb with it and whether the message is such that
+ // the message and the Cdb can be loaded into the fifo; otherwise, just
+ // load the first byte of the message.
+ //
+
+ if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI &&
+ (DeviceExtension->MessageCount == 1 ||
+ DeviceExtension->MessageCount == 3)) {
+
+ //
+ // Copy the entire message and Cdb into the fifo.
+ //
+
+ for (;
+ DeviceExtension->MessageSent <
+ DeviceExtension->MessageCount;
+ DeviceExtension->MessageSent++ ) {
+
+ SCSI_WRITE( DeviceExtension->Adapter,
+ Fifo,
+ DeviceExtension->
+ MessageBuffer[DeviceExtension->MessageSent]
+ );
+
+ }
+
+ for (i = 0; i < srb->CdbLength; i++) {
+ SCSI_WRITE(DeviceExtension->Adapter,
+ Fifo,
+ srb->Cdb[i]
+ );
+ }
+
+ if (DeviceExtension->MessageCount == 1) {
+
+ //
+ // One message byte so use select with attention which uses one
+ // message byte.
+ //
+
+ SCSI_WRITE(
+ DeviceExtension->Adapter,
+ Command,
+ SELECT_WITH_ATTENTION
+ );
+
+ } else {
+
+ //
+ // Three byte message, so use the select with attention which uses
+ // three byte messages.
+ //
+
+ SCSI_WRITE(
+ DeviceExtension->Adapter,
+ Command,
+ SELECT_WITH_ATTENTION3
+ );
+
+ }
+
+ } else {
+
+ //
+ // Only the first byte of the message can be sent so select with
+ // ATTENTION and the target will request the rest.
+ //
+
+ SCSI_WRITE(
+ DeviceExtension->Adapter,
+ Command,
+ SELECT_WITH_ATTENTION_STOP
+ );
+
+ }
+
+ /* Powerfail release */
+
+ //
+ // Set the device state to message-out and indicate that a message
+ // is being sent.
+ //
+
+ DeviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+ DeviceExtension->AdapterState = AttemptingSelect;
+ DeviceExtension->InterruptCount = 0;
+
+}
+
+
+VOID
+NcrSendMessage(
+ PSCSI_REQUEST_BLOCK Srb,
+ PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to send the indicated message to the target
+ controller. There are three classes of messages:
+ Those which terminate a specific request and end in bus free.
+ Those which apply to a specific request and then proceed.
+ Those which end in bus free.
+
+ For those messages that apply to a specific request, check to see that
+ the request is currently being processed and an INDENTIFY message prefixed
+ to the message.
+
+ It is possible that the destination logical unit is the active logical unit;
+ however, it would difficult to jump in and send the requested message, so
+ just wait for the bus to become free.
+
+ In the case where the target is not currently active, then set up the SCSI
+ protocol chip to select the target controller and send the message.
+
+Arguments:
+
+ Srb - Supplies the request to be started.
+
+ DeviceExtension - Supplies the extended device extension for this SCSI bus.
+
+ LuExtension - Supplies the logical unit extension for this request.
+
+Notes:
+
+ This routine must be synchronized with the interrupt routine.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PSCSI_REQUEST_BLOCK linkedSrb;
+ BOOLEAN impliesDisconnect;
+ BOOLEAN useTag;
+ UCHAR message;
+
+ impliesDisconnect = FALSE;
+ useTag = FALSE;
+
+ //
+ // Decode the type of message.
+ //
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_TERMINATE_IO:
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ //
+ // Verify that the request is being processed by the logical unit.
+ //
+
+ linkedSrb = ScsiPortGetSrb(
+ DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag
+ );
+
+ if (linkedSrb != Srb->NextSrb) {
+
+ //
+ // The specified request is not here. Complete the request
+ // without error.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification(
+ NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ return;
+ }
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+ impliesDisconnect = TRUE;
+ message = SCSIMESS_ABORT;
+ } else {
+ message = SCSIMESS_TERMINATE_IO_PROCESS;
+ impliesDisconnect = FALSE;
+ }
+
+ //
+ // Use a tagged message if the original request was tagged.
+ //
+
+ useTag = linkedSrb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE ?
+ TRUE : FALSE;
+
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ //
+ // Because of the way the chip works it is easiest to send an IDENTIFY
+ // message along with the BUS DEVICE RESET message. That is because
+ // there is no way to select a target with ATN and send one message
+ // byte. This IDENTIFY message is not necessary for the SCSI protocol,
+ // but it is legal and should not cause any problem.
+ //
+
+ message = SCSIMESS_BUS_DEVICE_RESET;
+ impliesDisconnect = TRUE;
+ break;
+
+ case SRB_FUNCTION_RELEASE_RECOVERY:
+
+ //
+ // These messages require an IDENTIFY message and imply a disconnect.
+ //
+
+ impliesDisconnect = TRUE;
+ message = SCSIMESS_RELEASE_RECOVERY;
+ break;
+
+ case SCSIMESS_CLEAR_QUEUE:
+
+ //
+ // These messages require an IDENTIFY message and imply a disconnect.
+ //
+
+ message = SCSIMESS_CLEAR_QUEUE;
+ impliesDisconnect = TRUE;
+ break;
+
+ default:
+
+ //
+ // This is an unsupported message request. Fail the request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification(
+ NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ return;
+ }
+
+ //
+ // Save away the parameters in case nothing can be done now.
+ //
+
+ DeviceExtension->NextSrbRequest = Srb;
+ DeviceExtension->AdapterFlags |= PD_PENDING_START_IO;
+ LuExtension->ActiveSendRequest = Srb;
+
+ //
+ // Check to see if the bus is free. If it is not, then return. Since
+ // the request parameters have been saved, indicate that the request has
+ // been accepted. The request will be processed when the bus becomes free.
+ //
+
+ if (DeviceExtension->AdapterState != BusFree) {
+ return;
+ }
+
+ //
+ // Create the identify command and copy the message to the buffer.
+ //
+
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_IDENTIFY_WITH_DISCON |
+ Srb->Lun;
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+
+ if (useTag && Srb->QueueTag != SP_UNTAGGED) {
+ DeviceExtension->MessageBuffer[DeviceExtension->MessageCount++] = SCSIMESS_SIMPLE_QUEUE_TAG;
+ DeviceExtension->MessageBuffer[DeviceExtension->MessageCount++] = Srb->QueueTag;
+
+ if (message == SCSIMESS_ABORT) {
+ message = SCSIMESS_ABORT_WITH_TAG;
+ }
+ }
+
+ DeviceExtension->MessageBuffer[DeviceExtension->MessageCount++] = message;
+
+ //
+ // Attempt to select the target and update the adapter flags.
+ //
+
+ NcrSelectTarget( DeviceExtension, LuExtension );
+
+ DeviceExtension->AdapterFlags |= impliesDisconnect ?
+ PD_DISCONNECT_EXPECTED | PD_SEND_MESSAGE_REQUEST
+ : PD_SEND_MESSAGE_REQUEST;
+
+}
+
+VOID
+NcrStartExecution(
+ PSCSI_REQUEST_BLOCK Srb,
+ PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure sets up the chip to select the target and notify it that
+ a request is available. For the NCR chip, the chip is set up to select,
+ send the IDENTIFY message and send the command data block. A check is
+ made to determine if synchronous negotiation is necessary.
+
+Arguments:
+
+ Srb - Supplies the request to be started.
+
+ DeviceExtension - Supplies the extended device extension for this SCSI bus.
+
+ LuExtension - Supplies the logical unit extension for this requst.
+
+Notes:
+
+ This routine must be synchronized with the interrupt routine.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PSCSI_EXTENDED_MESSAGE extendedMessage;
+ CHIP_TYPES chipType;
+ PSPECIFIC_TARGET_EXTENSION targetState;
+
+ //
+ // Save away the parameters in case nothing can be done now.
+ //
+
+ SRB_EXT(Srb)->SavedDataPointer = (ULONG) Srb->DataBuffer;
+ SRB_EXT(Srb)->SavedDataLength = Srb->DataTransferLength;
+ SRB_EXT(Srb)->SrbExtensionFlags = 0;
+ SRB_EXT(Srb)->MaximumTransferLength = 0;
+ DeviceExtension->NextSrbRequest = Srb;
+ DeviceExtension->AdapterFlags |= PD_PENDING_START_IO;
+
+ //
+ // Check to see if the bus is free. If it is not, then return. Since
+ // the request parameters have been saved, indicate that the request has
+ // been accepted. The request will be processed when the bus becomes free.
+ //
+
+ if (DeviceExtension->AdapterState != BusFree) {
+ return;
+ }
+
+ //
+ // Create the identify command.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_IDENTIFY | Srb->Lun;
+
+ DeviceExtension->TargetId = Srb->TargetId;
+ targetState = &DeviceExtension->TargetState[Srb->TargetId];
+
+ //
+ // Check to see if disconnect is allowed. If not then don't do tagged
+ // queuing either.
+ //
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)) {
+
+ //
+ // Enable disconnects in the message.
+ //
+
+ DeviceExtension->MessageBuffer[0] |= SCSIMESS_IDENTIFY_WITH_DISCON;
+
+ //
+ // If this is a tagged command then create a tagged message.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
+
+ //
+ // The queue tag message is two bytes the first is the queue action
+ // and the second is the queue tag.
+ //
+
+ DeviceExtension->MessageBuffer[1] = Srb->QueueAction;
+ DeviceExtension->MessageBuffer[2] = Srb->QueueTag;
+ DeviceExtension->MessageCount += 2;
+ DeviceExtension->AdapterFlags |= PD_TAGGED_SELECT;
+
+ } else {
+ LuExtension->ActiveLuRequest = Srb;
+ }
+
+ } else {
+ LuExtension->ActiveLuRequest = Srb;
+ }
+
+ //
+ // Check to see if synchronous negotiation is necessary.
+ //
+
+ if (!(targetState->TargetFlags &
+ (PD_SYNCHRONOUS_NEGOTIATION_DONE | PD_DO_NOT_NEGOTIATE))) {
+
+ //
+ // Initialize the synchronous transfer register values to an
+ // asynchronous transfer, which is what will be used if anything
+ // goes wrong with the negotiation.
+ //
+
+ targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ targetState->Configuration3 = DeviceExtension->Configuration3;
+
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) {
+
+ //
+ // Synchronous transfers are disabled by the SRB.
+ //
+
+ NcrSelectTarget( DeviceExtension, LuExtension );
+ return;
+ }
+
+ if (DeviceExtension->ChipType == Fas216) {
+
+ //
+ // The Fas216 supports fast synchronous transfers.
+ //
+
+ chipType = Fas216Fast;
+
+ } else if (DeviceExtension->ChipType == Ncr53c90) {
+
+ //
+ // The 53c90 does not support synchronous transfers.
+ // Set the do not negotate flag in the logical unit structure.
+ //
+
+ targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE;
+ NcrSelectTarget( DeviceExtension, LuExtension );
+ return;
+
+ } else {
+
+ chipType = DeviceExtension->ChipType;
+
+ }
+
+ //
+ // Create the synchronous data transfer request message.
+ // The format of the message is:
+ //
+ // EXTENDED_MESSAGE op-code
+ // Length of message
+ // Synchronous transfer data request op-code
+ // Our Transfer period
+ // Our REQ/ACK offset
+ //
+ // The message is placed after the IDENTIFY message.
+ //
+
+ extendedMessage = (PSCSI_EXTENDED_MESSAGE)
+ &DeviceExtension->MessageBuffer[DeviceExtension->MessageCount];
+ DeviceExtension->MessageCount += 2 + SCSIMESS_SYNCH_DATA_LENGTH;
+
+ extendedMessage->InitialMessageCode = SCSIMESS_EXTENDED_MESSAGE;
+ extendedMessage->MessageLength = SCSIMESS_SYNCH_DATA_LENGTH;
+ extendedMessage->MessageType = SCSIMESS_SYNCHRONOUS_DATA_REQ;
+
+ //
+ // If this chips does not suport fast SCSI, just calculate the normal
+ // minimum transfer period; otherwise use the fast value.
+ //
+
+ //
+ // The initial sychronous transfer period is:
+ //
+ // SynchronousPeriodCyles * 1000
+ // -----------------------------
+ // ClockSpeed * 4
+ //
+ // Note the result of the divide by four must be rounded up.
+ //
+
+ extendedMessage->ExtendedArguments.Synchronous.TransferPeriod =
+ ((SynchronousTransferTypes[chipType].SynchronousPeriodCyles * 1000) /
+ DeviceExtension->ClockSpeed + 3) / 4;
+ extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset = SYNCHRONOUS_OFFSET;
+
+ //
+ // Attempt to select the target and update the adapter flags.
+ //
+
+ NcrSelectTarget( DeviceExtension, LuExtension );
+
+ //
+ // Many controllers reject the first byte of a synchronous
+ // negotiation message. Since this is a multibyte message the
+ // ATN signal remains set after the first byte is sent. Some
+ // controllers remember this attempt to do a message-out
+ // later. Setting the PD_POSSIBLE_EXTRA_MESSAGE_OUT flag allows
+ // this extra message transfer to occur without error.
+ //
+
+ DeviceExtension->AdapterFlags |= PD_POSSIBLE_EXTRA_MESSAGE_OUT |
+ PD_SYNCHRONOUS_TRANSFER_SENT;
+
+ return;
+ }
+
+ NcrSelectTarget( DeviceExtension, LuExtension );
+
+}
+
+BOOLEAN
+NcrStartIo(
+ IN PVOID ServiceContext,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+/*++
+
+Routine Description:
+
+ This function is used by the OS dependent port driver to pass requests to
+ the dependent driver. This function begins the execution of the request.
+ Requests to reset the SCSI bus are handled immediately. Requests to send
+ a message or start a SCSI command are handled when the bus is free.
+
+Arguments:
+
+ ServiceContext - Supplies the device Extension for the SCSI bus adapter.
+
+ Srb - Supplies the SCSI request block to be started.
+
+Return Value:
+
+ TRUE - If the request can be accepted at this time.
+
+ FALSE - If the request must be submitted later.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+
+ switch (Srb->Function) {
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Determine the logical unit that this request is for.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+
+ NcrStartExecution(
+ Srb,
+ deviceExtension,
+ luExtension
+ );
+
+ return(TRUE);
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+ case SRB_FUNCTION_RESET_DEVICE:
+ case SRB_FUNCTION_TERMINATE_IO:
+
+ //
+ // Determine the logical unit that this request is for.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+
+ NcrSendMessage(
+ Srb,
+ deviceExtension,
+ luExtension
+ );
+
+ return(TRUE);
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // There is no logical unit so just reset the bus.
+ //
+
+ NcrResetScsiBusInternal( deviceExtension, 0 );
+ return(TRUE);
+
+ default:
+
+ //
+ // Unknown function code in the request. Complete the request with
+ // an error and ask for the next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
+ ScsiPortNotification(
+ RequestComplete,
+ deviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification(
+ NextRequest,
+ deviceExtension,
+ NULL
+ );
+
+ return(TRUE);
+ }
+
+}
+
+VOID
+NcrStartDataTransfer(
+ IN PVOID ServiceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the scsi bus protocol chip to perform a data transfer.
+ It is called after the DMA has been initialized.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the specific device extension.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+
+ //
+ // If the data tranfer is no longer expected then ignore the notification.
+ //
+
+ if (!(deviceExtension->AdapterFlags & PD_PENDING_DATA_TRANSFER)) {
+
+ return;
+
+ }
+
+ //
+ // Set up the SCSI protocol chip for the data transfer with the
+ // command to start.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter,
+ Command,
+ TRANSFER_INFORMATION_DMA
+ );
+
+ deviceExtension->AdapterFlags &= ~PD_PENDING_DATA_TRANSFER;
+
+}
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Driver Object is passed to ScsiPortInitialize()
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ ULONG Status1;
+ ULONG Status2;
+ INIT_DATA InitData;
+
+ ScsiDebugPrint(1,"\n\nNCR 53c9x SCSI MiniPort Driver\n");
+
+ //
+ // Zero out hardware initialization data structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Fill in the hardware initialization data structure.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+ hwInitializationData.HwInitialize = NcrInitializeAdapter;
+ hwInitializationData.HwStartIo = NcrStartIo;
+ hwInitializationData.HwInterrupt = NcrInterruptServiceRoutine;
+ hwInitializationData.HwFindAdapter = NcrMcaFindAdapter;
+ hwInitializationData.HwResetBus = NcrResetScsiBus;
+ hwInitializationData.HwDmaStarted = NcrStartDataTransfer;
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = MicroChannel;
+ hwInitializationData.DeviceExtensionSize = sizeof(SPECIFIC_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize =
+ sizeof(SPECIFIC_LOGICAL_UNIT_EXTENSION);
+ hwInitializationData.SrbExtensionSize = sizeof(SRB_EXTENSION);
+
+ //
+ // Initialize configuration information.
+ //
+ // The following adapter search order should be observed:
+ // 1. Onboard 53c94 scsi host adapter
+ // 2. Onboard 53c90 scsi host adapter
+ // 3. Plug-in 53c90 scsi host adapter
+ //
+
+ InitData.AdapterId = 0;
+ InitData.CardSlot = 7;
+
+ Status1 = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &InitData);
+
+ //
+ // Look for internal mips adapter.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Internal;
+ hwInitializationData.HwFindAdapter = NcrMipsFindAdapter;
+
+ Status2 = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &InitData);
+
+ Status1 = Status2 < Status1 ? Status2 : Status1;
+
+ //
+ // Look for an Eisa adapter.
+ //
+
+ InitData.AdapterId = 0;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+ hwInitializationData.HwFindAdapter = NcrEisaFindAdapter;
+
+ Status2 = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &InitData);
+
+ return(Status2 < Status1 ? Status2 : Status1);
+
+} // end PortInitialize()
+
+ULONG
+NcrMcaFindAdapter(
+ IN PVOID ServiceContext,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function fills in the configuration information structure. This
+ routine is temporary until the configuration manager supplies similar
+ informtion. It also fills in the capabilities structure.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension.
+
+ Context - Unused.
+
+ BusInformation - Unused.
+
+ ArgumentString - Unused.
+
+ ConfigInfo - Pointer to the configuration information structure to be
+ filled in.
+
+ Again - Returns back a request to call this function again.
+
+Return Value:
+
+ Returns a status value for the initialazitaition.
+
+--*/
+
+{
+
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ PINIT_DATA InitData = Context;
+ LONG Slot;
+ LONG i;
+ ULONG Status = SP_RETURN_NOT_FOUND;
+
+ //
+ // Determine if bus information array needs to be filled in.
+ //
+
+ if ( InitData->AdapterId == 0 ) {
+
+ //
+ // Fill in the POS data structure.
+ //
+
+ for ( Slot = 0; Slot < 8; Slot++ ) {
+
+ i = ScsiPortGetBusData ( deviceExtension,
+ Pos,
+ 0,
+ Slot,
+ &InitData->PosData[Slot],
+ sizeof( POS_DATA )
+ );
+
+ //
+ // If less that the requested amount of data is returned, then
+ // insure that this adapter is ignored.
+ //
+
+ if ( i < (sizeof( POS_DATA ))) {
+ InitData->PosData[Slot].AdapterId = 0xffff;
+ }
+
+ }
+
+ }
+
+ for ( Slot = InitData->CardSlot; Slot >= 0; Slot-- ) {
+ if (( InitData->PosData[Slot].AdapterId == ONBOARD_C94_ADAPTER_ID ||
+ InitData->PosData[Slot].AdapterId == ONBOARD_C90_ADAPTER_ID ||
+ InitData->PosData[Slot].AdapterId == PLUGIN_C90_ADAPTER_ID ) &&
+ (*(PPOS_DATA_1)&InitData->PosData[Slot].OptionData1).AdapterEnable) {
+ InitData->CardSlot = Slot - 1;
+ Status = SP_RETURN_FOUND;
+ break;
+ }
+ }
+
+ if ( Status == SP_RETURN_FOUND ) {
+
+ *Again = TRUE;
+
+ deviceExtension->AdapterBase = (PVOID) AdapterBaseAddress[
+ (*(PPOS_DATA_1) &InitData->PosData[Slot].OptionData1).IoAddressSelects];
+ deviceExtension->Adapter = (PSCSI_REGISTERS)
+ ((PCHAR) deviceExtension->AdapterBase + sizeof(ADAPTER_REGISTERS));
+ if ( InitData->PosData[Slot].AdapterId == ONBOARD_C94_ADAPTER_ID ) {
+ deviceExtension->ChipType = Ncr53c94;
+
+ // RDR This isn't filled in before use in the new code!!!
+
+ deviceExtension->AdapterBusId = AdapterScsiIdC94[
+ (*(PPOS_DATA_3) &InitData->PosData[Slot].OptionData3).HostIdSelects];
+ deviceExtension->InterruptPending = FALSE;
+ } else {
+ deviceExtension->ChipType = Ncr53c90;
+ deviceExtension->AdapterBusId = AdapterScsiIdC90[
+ (*(PPOS_DATA_4) &InitData->PosData[Slot].OptionData4).HostIdSelects];
+ deviceExtension->InterruptPending = TRUE;
+ }
+
+ deviceExtension->AdapterBusIdMask = 1 << deviceExtension->AdapterBusId;
+
+ //
+ // Set configuration information
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = 16;
+ ConfigInfo->BusInterruptLevel = AdapterInterruptLevel[
+ (*(PPOS_DATA_1) &InitData->PosData[Slot].OptionData1).InterruptSelects];
+ ConfigInfo->InitiatorBusId[0] = deviceExtension->AdapterBusId;
+ ConfigInfo->DmaChannel = AdapterDmaLevel[
+ (*(PPOS_DATA_2) &InitData->PosData[Slot].OptionData2).DmaSelects];
+ ConfigInfo->DmaPort = (ULONG) deviceExtension->AdapterBase + (ULONG)
+ &((PADAPTER_WRITE_REGISTERS) 0)->DmaDecode;
+ if ( InitData->PosData[Slot].AdapterId == ONBOARD_C94_ADAPTER_ID ) {
+ ConfigInfo->DmaWidth = Width16Bits;
+ ConfigInfo->AlignmentMask = 1;
+ ConfigInfo->AdapterScansDown = TRUE;
+ ConfigInfo->TaggedQueuing = 1;
+ } else {
+ ConfigInfo->DmaWidth = Width8Bits;
+ }
+
+ ConfigInfo->DmaSpeed = Compatible;
+ ConfigInfo->MaximumTransferLength = 0xf000;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress((ULONG) deviceExtension->AdapterBase);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(ADAPTER_REGISTERS) +
+ sizeof(SCSI_REGISTERS);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ //
+ // Initialize hardware.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Command, RESET_SCSI_CHIP);
+ SCSI_WRITE(deviceExtension->Adapter, Command, NO_OPERATION_DMA);
+
+ deviceExtension->ClockSpeed = 14; // set clock speed at 14 Mhz.
+ deviceExtension->AdapterFlags |= PD_NCR_ADAPTER;
+
+ ScsiDebugPrint(1, " ScsiId = %x\n", ConfigInfo->InitiatorBusId[0]);
+ ScsiDebugPrint(1, " IoBase = %2x\n", deviceExtension->Adapter);
+ ScsiDebugPrint(1, " Irq = %x\n", ConfigInfo->BusInterruptLevel);
+ ScsiDebugPrint(1, " Dma = %x\n", ConfigInfo->DmaChannel);
+
+ } else {
+
+ *Again = FALSE;
+
+ }
+
+ return(Status);
+
+}
+
+ULONG
+NcrEisaFindAdapter(
+ IN PVOID ServiceContext,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function fills in the configuration information structure. This
+ routine is temporary until the configuration manager supplies similar
+ informtion. It also fills in the capabilities structure.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension.
+
+ Context - Unused.
+
+ BusInformation - Unused.
+
+ ArgumentString - Unused.
+
+ ConfigInfo - Pointer to the configuration information structure to be
+ filled in.
+
+ Again - Returns back a request to call this function again.
+
+Return Value:
+
+ Returns a status value for the initialazitaition.
+
+--*/
+
+{
+
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ PCM_EISA_FUNCTION_INFORMATION functionInformation;
+ PCM_EISA_SLOT_INFORMATION slotInformation;
+ UCHAR dataByte;
+ PUCHAR configurationRegister;
+ ULONG boardId;
+ ULONG numberOfFunctions;
+ ULONG slotNumber;
+
+ *Again = FALSE;
+
+ for (slotNumber = 0; slotNumber < 16; slotNumber++) {
+
+ boardId = ScsiPortGetBusData( deviceExtension,
+ EisaConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ slotNumber,
+ &slotInformation,
+ 0);
+
+ if (boardId == 0 || slotInformation == NULL) {
+ continue;
+ }
+
+ //
+ // Calculate the actual number of functions returned.
+ //
+
+ numberOfFunctions = (boardId - sizeof(CM_EISA_SLOT_INFORMATION)) /
+ sizeof(CM_EISA_FUNCTION_INFORMATION);
+
+ if (numberOfFunctions > (ULONG) slotInformation->NumberFunctions) {
+ numberOfFunctions = slotInformation->NumberFunctions;
+ }
+
+ functionInformation = (PCM_EISA_FUNCTION_INFORMATION) (slotInformation + 1);
+ for (; 0 < numberOfFunctions; numberOfFunctions--, functionInformation++) {
+
+ if (!(functionInformation->FunctionFlags & EISA_FUNCTION_ENABLED) &&
+ !strcmp(functionInformation->TypeString, "MSD,CDROM1")) {
+
+ DebugPrint((1, "NcrEisaFindAdapter: Found type string. Function information: %lx\n", functionInformation));
+ ConfigInfo->DmaWidth = Width8Bits;
+ ConfigInfo->DmaSpeed = Compatible;
+ deviceExtension->ChipType = Ncr53c90;
+ goto found;
+
+ } else if (!(functionInformation->FunctionFlags & EISA_FUNCTION_ENABLED) &&
+ !strcmp(functionInformation->TypeString, "MSD,SCSI,C94")) {
+
+ DebugPrint((1, "NcrEisaFindAdapter: Found type string. Function information: %lx\n", functionInformation));
+ ConfigInfo->DmaWidth = Width16Bits;
+ ConfigInfo->AlignmentMask = 1;
+ ConfigInfo->DmaSpeed = TypeB;
+ ConfigInfo->MaximumTransferLength = 0x10000;
+ deviceExtension->ChipType = Ncr53c94;
+ goto found;
+ }
+ }
+ }
+
+ //
+ // Determine if this is the correct Eisa board.
+ //
+
+ if (slotNumber >= 16) {
+
+ //
+ // The device was not found.
+ //
+
+ return(SP_RETURN_NOT_FOUND);
+ }
+
+found:
+
+ ConfigInfo->BusInterruptVector = 0;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Get the SCSI bus Id from the configuration information if there
+ // is any.
+ //
+
+ if (ConfigInfo->InitiatorBusId[0] == (CCHAR) SP_UNINITIALIZED_VALUE) {
+ deviceExtension->AdapterBusId = INITIATOR_BUS_ID;
+ deviceExtension->AdapterBusIdMask = 1 << INITIATOR_BUS_ID;
+ ConfigInfo->InitiatorBusId[0] = INITIATOR_BUS_ID;
+ } else {
+ deviceExtension->AdapterBusId = ConfigInfo->InitiatorBusId[0];
+ deviceExtension->AdapterBusIdMask = 1 << ConfigInfo->InitiatorBusId[0];
+ }
+
+ configurationRegister = ScsiPortGetDeviceBase(
+ deviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress(functionInformation->EisaPort->PortAddress),
+ functionInformation->EisaPort->Configuration.NumberPorts, // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+ if (configurationRegister == (PUCHAR) SP_UNINITIALIZED_VALUE) {
+ return(SP_RETURN_ERROR);
+ }
+
+ deviceExtension->ClockSpeed = 25; // Assume a 25 Mhz clock speed.
+ deviceExtension->Adapter = (PSCSI_REGISTERS) configurationRegister;
+
+ //
+ // The Emulex chip loads the TransferCountPage register with the chip id,
+ // if the EnablePhaseLatch is set and a NOP DMA command has been loaded.
+ //
+
+ if (deviceExtension->ChipType == Ncr53c94) {
+
+ //
+ // Now write to the command register with a reset.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
+
+ //
+ // A NOP command is required by the FAS218 to
+ // load the TransferCountPage register with the chip Id.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
+
+ dataByte = SCSI_READ( deviceExtension->Adapter, TransferCountPage);
+
+ if (((PNCR_PART_CODE) &dataByte)->ChipFamily == EMULEX_FAS_216) {
+
+ deviceExtension->ChipType = Fas216;
+ } else if (((PNCR_PART_CODE) &dataByte)->ChipFamily == NCR_53c96) {
+
+ NcrPrint((1, "NcrFindAdapter: NCR 53c96 chip detected.\n"));
+ deviceExtension->ChipType = Fas216;
+ }
+ }
+
+ //
+ // Set the parameters according to the chip type.
+ //
+
+ switch (deviceExtension->ChipType) {
+ case Ncr53c94:
+
+ NcrPrint((1, "NcrFindAdapter: Ncr 53C94 chip detected.\n"));
+ ConfigInfo->TaggedQueuing = 1;
+ ConfigInfo->MaximumTransferLength = 0x10000;
+ break;
+
+ case Fas216:
+ NcrPrint((1, "NcrFindAdapter: Emulex FAS 216 chip detected.\n"));
+ deviceExtension->ClockSpeed = EMULEX_SCSI_CLOCK_SPEED;
+ ConfigInfo->TaggedQueuing = 1;
+ ConfigInfo->MaximumTransferLength = 0x1000000-0x1000;
+ deviceExtension->Configuration3.CheckIdMessage = 1;
+ break;
+
+ case Ncr53c90:
+
+ NcrPrint((1, "NcrFindAdapter: Ncr 53C90 chip detected.\n"));
+ ConfigInfo->MaximumTransferLength = 0x10000 - 0x1000;
+ break;
+
+ default:
+ *Again = FALSE;
+ return(SP_RETURN_BAD_CONFIG);
+ }
+
+ //
+ // If the clock speed is greater than 25 Mhz then set the fast clock
+ // bit in configuration register.
+ //
+
+ if (deviceExtension->ClockSpeed > 25) {
+ deviceExtension->Configuration3.FastClock = 1;
+ }
+
+ ConfigInfo->DmaChannel =
+ functionInformation->EisaDma->ConfigurationByte0.Channel;
+ ConfigInfo->BusInterruptLevel =
+ functionInformation->EisaIrq->ConfigurationByte.Interrupt;
+ ConfigInfo->InterruptMode =
+ functionInformation->EisaIrq->ConfigurationByte.LevelTriggered ?
+ LevelSensitive : Latched;
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ functionInformation->EisaPort->PortAddress);
+ (*ConfigInfo->AccessRanges)[0].RangeLength =
+ functionInformation->EisaPort->Configuration.NumberPorts;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ //
+ // Make sure the interrupt and DMA channel are properly configured.
+ //
+
+ if (ConfigInfo->DmaChannel == (UCHAR) ~0 ||
+ ConfigInfo->BusInterruptLevel == (UCHAR) ~0) {
+
+ return(SP_RETURN_BAD_CONFIG);
+ }
+
+ //
+ // Test for the interrupt bit in the status register. Some chips do not
+ // implement this bit; however, this driver assumes that it exists.
+ // The itnerrupt bit is tested for by reseting the chip, giving an
+ // illegal command, and checking for an gross error interrupt.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
+ SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, COMMAND_COMPLETE );
+
+ *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ(
+ deviceExtension->Adapter,
+ ScsiStatus
+ );
+
+ dataByte = SCSI_READ( deviceExtension->Adapter, ScsiInterrupt );
+
+ //
+ // Test for the interrupt.
+ //
+
+ if (!deviceExtension->AdapterStatus.Interrupt) {
+
+ NcrPrint((0, "\nNcrEisaFindAdapter: Ncr53c90 chip without status register interrupt detected.\n"));
+ NcrPrint((0, "NcrInterrupt: Adapter Status: %2x; Adapter Interrupt: %2x\n",
+ *((PUCHAR) &deviceExtension->AdapterStatus),
+ dataByte
+ ));
+
+ ScsiPortFreeDeviceBase(deviceExtension, deviceExtension->Adapter);
+ return(SP_RETURN_BAD_CONFIG);
+ }
+
+ //
+ // Now write to the command register with a reset and a DMA nop.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
+ SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
+
+ return(SP_RETURN_FOUND);
+
+}
+
+ULONG
+NcrMipsFindAdapter(
+ IN PVOID ServiceContext,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function fills in the configuration information structure and mapes
+ the SCSI protocol chip for access. This routine is temporary until
+ the configuration manager supplies similar informtion.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension.
+
+ Context - Unused.
+
+ BusInformation - Unused.
+
+ ArgumentString - Unused.
+
+ ConfigInfo - Pointer to the configuration information structure to be
+ filled in.
+
+ Again - Returns back a request to call this function again.
+
+Return Value:
+
+ Returns a status value for the initialazitaition.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ UCHAR dataByte;
+ UCHAR commandSave;
+
+ if (ConfigInfo->DmaChannel == SP_UNINITIALIZED_VALUE
+ || ConfigInfo->BusInterruptLevel == 0 ||
+ (*ConfigInfo->AccessRanges)[0].RangeLength == 0) {
+ return(SP_RETURN_NOT_FOUND);
+ }
+
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Get the SCSI bus Id from the configuration information if there
+ // is any.
+ //
+
+ if (ConfigInfo->InitiatorBusId[0] == (CCHAR) SP_UNINITIALIZED_VALUE) {
+ deviceExtension->AdapterBusId = INITIATOR_BUS_ID;
+ deviceExtension->AdapterBusIdMask = 1 << INITIATOR_BUS_ID;
+ ConfigInfo->InitiatorBusId[0] = INITIATOR_BUS_ID;
+ } else {
+ deviceExtension->AdapterBusId = ConfigInfo->InitiatorBusId[0];
+ deviceExtension->AdapterBusIdMask = 1 << ConfigInfo->InitiatorBusId[0];
+ }
+
+ //
+ // Map the SCSI protocol chip into the virtual address space.
+ //
+
+ deviceExtension->Adapter = ScsiPortGetDeviceBase(
+ deviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ (*ConfigInfo->AccessRanges)[0].RangeStart,
+ (*ConfigInfo->AccessRanges)[0].RangeLength, // NumberOfBytes
+ FALSE // InIoSpace
+ );
+
+ if (deviceExtension->Adapter == NULL) {
+ NcrPrint((0, "\nScsiPortInitialize: Failed to map SCSI device registers into system space.\n"));
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // Check the iterrupt register. If it is not equal zero then read it
+ // agian it should now be zero.
+ //
+
+ dataByte = SCSI_READ( deviceExtension->Adapter, ScsiInterrupt );
+
+ if (dataByte != 0) {
+
+ ScsiPortStallExecution(INTERRUPT_STALL_TIME);
+ dataByte = SCSI_READ( deviceExtension->Adapter, ScsiInterrupt );
+
+ if (dataByte != 0 ) {
+ NcrPrint((1, "NcrMipsFindAdapter: No Ncr53c9x chip found! Interrupt will not clear.\n"));
+ ScsiPortFreeDeviceBase(deviceExtension, deviceExtension->Adapter);
+ return(SP_RETURN_NOT_FOUND);
+ }
+ }
+
+ //
+ // Test for the interrupt bit in the status register. Some chips do not
+ // implement this bit; however, this driver assumes that it exists.
+ // The itnerrupt bit is tested for by reseting the chip, giving an
+ // illegal command, and checking for an gross error interrupt.
+ //
+
+ commandSave = SCSI_READ(deviceExtension->Adapter, Command);
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
+ ScsiPortStallExecution(1);
+ SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
+ ScsiPortStallExecution(1);
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, COMMAND_COMPLETE );
+ ScsiPortStallExecution(1);
+
+ *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ(
+ deviceExtension->Adapter,
+ ScsiStatus
+ );
+
+ dataByte = SCSI_READ( deviceExtension->Adapter, ScsiInterrupt );
+
+ //
+ // Test for the interrupt.
+ //
+
+ if (!deviceExtension->AdapterStatus.Interrupt) {
+
+ NcrPrint((0, "\nNcrMipsFindAdapter: Ncr53c90 chip without status register interrupt detected.\n"));
+ NcrPrint((0, "NcrMipsFindAdapter: Adapter Status: %2x; Adapter Interrupt: %2x\n",
+ *((PUCHAR) &deviceExtension->AdapterStatus),
+ dataByte
+ ));
+
+ //
+ // Restore the command register.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, commandSave );
+
+ ScsiPortFreeDeviceBase(deviceExtension, deviceExtension->Adapter);
+ return(SP_RETURN_NOT_FOUND);
+ }
+
+ //
+ // Initialize the NCR SCSI Chip.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
+
+ //
+ // A NOP command is required to clear the chip reset command.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
+
+ //
+ // Determine the chip type.
+ //
+
+ //
+ // The Ncr53c90 is detected by the absense of configuration register 3.
+ // On the other to chips this register is zero after a reset and is read
+ // writable.
+ //
+
+ dataByte = SCSI_READ( deviceExtension->Adapter, Configuration2);
+
+ if (dataByte != 0) {
+
+ deviceExtension->ChipType = Ncr53c90;
+
+ } else {
+
+ //
+ // Set the Scsi2 and EnablePhaseLatch of the configuration regisiter.
+ //
+
+ ((PSCSI_CONFIGURATION2)(&dataByte))->Scsi2 = 1;
+ ((PSCSI_CONFIGURATION2)(&dataByte))->EnablePhaseLatch = 1;
+
+ SCSI_WRITE( deviceExtension->Adapter, Configuration2, dataByte);
+
+ //
+ // Read the register back if the value is not the same as was written,
+ // then this an Ncr53c90.
+ //
+
+ if (dataByte != SCSI_READ( deviceExtension->Adapter, Configuration2)) {
+
+ deviceExtension->ChipType = Ncr53c90;
+
+ } else {
+
+ deviceExtension->ChipType = Ncr53c94;
+
+ }
+ }
+
+ //
+ // The Emulex chip loads the TransferCountPage register with the chip id,
+ // if the EnablePhaseLatch is set and a NOP DMA command has been loaded.
+ //
+
+ if (deviceExtension->ChipType == Ncr53c94) {
+
+ //
+ // A NOP command is required by the FAS218 to
+ // load the TransferCountPage register with the chip Id.
+ //
+
+ SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
+
+ dataByte = SCSI_READ( deviceExtension->Adapter, TransferCountPage);
+
+ if (((PNCR_PART_CODE) &dataByte)->ChipFamily == EMULEX_FAS_216) {
+
+ deviceExtension->ChipType = Fas216;
+
+ } else if (((PNCR_PART_CODE) &dataByte)->ChipFamily == NCR_53c96) {
+
+ NcrPrint((1, "NcrFindAdapter: NCR 53c96 chip detected.\n"));
+ deviceExtension->ChipType = Fas216;
+ }
+ }
+
+ //
+ // Set the parameters according to the chip type.
+ //
+
+ switch (deviceExtension->ChipType) {
+ case Ncr53c94:
+
+ NcrPrint((1, "NcrFindAdapter: Ncr 53C94 chip detected.\n"));
+ deviceExtension->ClockSpeed = NCR_SCSI_CLOCK_SPEED;
+ ConfigInfo->TaggedQueuing = 1;
+ ConfigInfo->MaximumTransferLength = 0x10000;
+ break;
+
+ case Fas216:
+ NcrPrint((1, "NcrFindAdapter: Emulex FAS 216 chip detected.\n"));
+ deviceExtension->ClockSpeed = EMULEX_SCSI_CLOCK_SPEED;
+ ConfigInfo->TaggedQueuing = 1;
+ ConfigInfo->MaximumTransferLength = 0x1000000-0x1000;
+ deviceExtension->Configuration3.CheckIdMessage = 1;
+ break;
+
+ case Ncr53c90:
+
+ NcrPrint((1, "NcrFindAdapter: Ncr 53C90 chip detected.\n"));
+
+ default:
+ *Again = FALSE;
+ return(SP_RETURN_BAD_CONFIG);
+ }
+
+ //
+ // If the clock speed is greater than 25 Mhz then set the fast clock
+ // bit in configuration register.
+ //
+
+ if (deviceExtension->ClockSpeed > 25) {
+ deviceExtension->Configuration3.FastClock = 1;
+ }
+
+ *Again = FALSE;
+ return(SP_RETURN_FOUND);
+
+}
+
diff --git a/private/ntos/miniport/ncr53c94/ncr53c9x.h b/private/ntos/miniport/ncr53c94/ncr53c9x.h
new file mode 100644
index 000000000..69202083d
--- /dev/null
+++ b/private/ntos/miniport/ncr53c94/ncr53c9x.h
@@ -0,0 +1,430 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ncr53c9x.h
+
+Abstract:
+
+ The module defines the structures, defines and functions for the NCR 53c9x
+ family of host bus adapter chips.
+
+Author:
+
+ Jeff Havens (jhavens) 28-Feb-1991
+
+Revision History:
+
+--*/
+
+#ifndef _NCR53C9X_
+#define _NCR53C9X_
+
+
+//
+// Define SCSI Protocol Chip register format.
+//
+
+#if defined(DECSTATION)
+
+typedef struct _SCSI_REGISTER {
+ UCHAR Byte;
+ UCHAR Fill[3];
+} SCSI_REGISTER, *PSCSI_REGISTER;
+
+#else
+
+#define SCSI_REGISTER UCHAR
+
+#endif // DECSTATION
+
+//
+// SCSI Protocol Chip Definitions.
+//
+// Define SCSI Protocol Chip Read registers structure.
+//
+
+typedef struct _SCSI_READ_REGISTERS {
+ SCSI_REGISTER TransferCountLow;
+ SCSI_REGISTER TransferCountHigh;
+ SCSI_REGISTER Fifo;
+ SCSI_REGISTER Command;
+ SCSI_REGISTER ScsiStatus;
+ SCSI_REGISTER ScsiInterrupt;
+ SCSI_REGISTER SequenceStep;
+ SCSI_REGISTER FifoFlags;
+ SCSI_REGISTER Configuration1;
+ SCSI_REGISTER Reserved1;
+ SCSI_REGISTER Reserved2;
+ SCSI_REGISTER Configuration2;
+ SCSI_REGISTER Configuration3;
+ SCSI_REGISTER Configuration4;
+ SCSI_REGISTER TransferCountPage;
+ SCSI_REGISTER FifoBottem;
+} SCSI_READ_REGISTERS, *PSCSI_READ_REGISTERS;
+
+//
+// Define SCSI Protocol Chip Write registers structure.
+//
+
+typedef struct _SCSI_WRITE_REGISTERS {
+ SCSI_REGISTER TransferCountLow;
+ SCSI_REGISTER TransferCountHigh;
+ SCSI_REGISTER Fifo;
+ SCSI_REGISTER Command;
+ SCSI_REGISTER DestinationId;
+ SCSI_REGISTER SelectTimeOut;
+ SCSI_REGISTER SynchronousPeriod;
+ SCSI_REGISTER SynchronousOffset;
+ SCSI_REGISTER Configuration1;
+ SCSI_REGISTER ClockConversionFactor;
+ SCSI_REGISTER TestMode;
+ SCSI_REGISTER Configuration2;
+ SCSI_REGISTER Configuration3;
+ SCSI_REGISTER Configuration4;
+ SCSI_REGISTER TransferCountPage;
+ SCSI_REGISTER FifoBottem;
+} SCSI_WRITE_REGISTERS, *PSCSI_WRITE_REGISTERS;
+
+typedef union _SCSI_REGISTERS {
+ SCSI_READ_REGISTERS ReadRegisters;
+ SCSI_WRITE_REGISTERS WriteRegisters;
+} SCSI_REGISTERS, *PSCSI_REGISTERS;
+
+//
+// Define SCSI Command Codes.
+//
+
+#define NO_OPERATION_DMA 0x80
+#define FLUSH_FIFO 0x1
+#define RESET_SCSI_CHIP 0x2
+#define RESET_SCSI_BUS 0x3
+#define TRANSFER_INFORMATION 0x10
+#define TRANSFER_INFORMATION_DMA 0x90
+#define COMMAND_COMPLETE 0x11
+#define MESSAGE_ACCEPTED 0x12
+#define TRANSFER_PAD 0x18
+#define SET_ATTENTION 0x1a
+#define RESET_ATTENTION 0x1b
+#define RESELECT 0x40
+#define SELECT_WITHOUT_ATTENTION 0x41
+#define SELECT_WITH_ATTENTION 0x42
+#define SELECT_WITH_ATTENTION_STOP 0x43
+#define ENABLE_SELECTION_RESELECTION 0x44
+#define DISABLE_SELECTION_RESELECTION 0x45
+#define SELECT_WITH_ATTENTION3 0x46
+
+//
+// Define SCSI Status Register structure.
+//
+typedef struct _SCSI_STATUS {
+ UCHAR Phase : 3;
+ UCHAR ValidGroup : 1;
+ UCHAR TerminalCount : 1;
+ UCHAR ParityError : 1;
+ UCHAR GrossError : 1;
+ UCHAR Interrupt : 1;
+} SCSI_STATUS, *PSCSI_STATUS;
+
+//
+// Define SCSI Phase Codes.
+//
+
+#define DATA_OUT 0x0
+#define DATA_IN 0x1
+#define COMMAND_OUT 0x2
+#define STATUS_IN 0x3
+#define MESSAGE_OUT 0x6
+#define MESSAGE_IN 0x7
+
+//
+// Define SCSI Interrupt Register structure.
+//
+
+typedef struct _SCSI_INTERRUPT {
+ UCHAR Selected : 1;
+ UCHAR SelectedWithAttention : 1;
+ UCHAR Reselected : 1;
+ UCHAR FunctionComplete : 1;
+ UCHAR BusService : 1;
+ UCHAR Disconnect : 1;
+ UCHAR IllegalCommand : 1;
+ UCHAR ScsiReset : 1;
+} SCSI_INTERRUPT, *PSCSI_INTERRUPT;
+
+//
+// Define SCSI Sequence Step Register structure.
+//
+
+typedef struct _SCSI_SEQUENCE_STEP {
+ UCHAR Step : 3;
+ UCHAR MaximumOffset : 1;
+ UCHAR Reserved : 4;
+} SCSI_SEQUENCE_STEP, *PSCSI_SEQUENCE_STEP;
+
+//
+// Define SCSI Fifo Flags Register structure.
+//
+
+typedef struct _SCSI_FIFO_FLAGS {
+ UCHAR ByteCount : 5;
+ UCHAR FifoStep : 3;
+} SCSI_FIFO_FLAGS, *PSCSI_FIFO_FLAGS;
+
+//
+// Define SCSI Configuration 1 Register structure.
+//
+
+typedef struct _SCSI_CONFIGURATION1 {
+ UCHAR HostBusId : 3;
+ UCHAR ChipTestEnable : 1;
+ UCHAR ParityEnable : 1;
+ UCHAR ParityTestMode : 1;
+ UCHAR ResetInterruptDisable : 1;
+ UCHAR SlowCableMode : 1;
+} SCSI_CONFIGURATION1, *PSCSI_CONFIGURATION1;
+
+//
+// Define SCSI Configuration 2 Register structure.
+//
+
+typedef struct _SCSI_CONFIGURATION2 {
+ UCHAR DmaParityEnable : 1;
+ UCHAR RegisterParityEnable : 1;
+ UCHAR TargetBadParityAbort : 1;
+ UCHAR Scsi2 : 1;
+ UCHAR HighImpedance : 1;
+ UCHAR EnableByteControl : 1;
+ UCHAR EnablePhaseLatch : 1;
+ UCHAR ReserveFifoByte : 1;
+} SCSI_CONFIGURATION2, *PSCSI_CONFIGURATION2;
+
+//
+// Define SCSI Configuration 3 Register structure.
+//
+
+typedef struct _SCSI_CONFIGURATION3 {
+ UCHAR Threshold8 : 1;
+ UCHAR AlternateDmaMode : 1;
+ UCHAR SaveResidualByte : 1;
+ UCHAR FastClock : 1;
+ UCHAR FastScsi : 1;
+ UCHAR EnableCdb10 : 1;
+ UCHAR EnableQueue : 1;
+ UCHAR CheckIdMessage : 1;
+} SCSI_CONFIGURATION3, *PSCSI_CONFIGURATION3;
+
+//
+// Define SCSI Configuration 4 Register structure.
+//
+
+typedef struct _SCSI_CONFIGURATION4 {
+ UCHAR ActiveNegation : 1;
+ UCHAR TestTransferCounter : 1;
+ UCHAR BackToBackTransfer : 1;
+ UCHAR Reserved : 5;
+} SCSI_CONFIGURATION4, *PSCSI_CONFIGURATION4;
+
+//
+// Define Emulex FAS 218 unique part Id code.
+//
+
+typedef struct _NCR_PART_CODE {
+ UCHAR RevisionLevel : 3;
+ UCHAR ChipFamily : 5;
+}NCR_PART_CODE, *PNCR_PART_CODE;
+
+#define EMULEX_FAS_216 2
+#define NCR_53c96 0x14
+
+//
+// SCSI Protocol Chip Control read and write macros.
+//
+
+#if defined(DECSTATION)
+
+#define SCSI_READ(ChipAddr, Register) \
+ (READ_REGISTER_UCHAR (&((ChipAddr)->ReadRegisters.Register.Byte)))
+
+#define SCSI_WRITE(ChipAddr, Register, Value) \
+ WRITE_REGISTER_UCHAR(&((ChipAddr)->WriteRegisters.Register.Byte), (Value))
+
+#else
+
+#define SCSI_READ(ChipAddr, Register) \
+ (READ_REGISTER_UCHAR (&((ChipAddr)->ReadRegisters.Register)))
+
+#define SCSI_WRITE(ChipAddr, Register, Value) \
+ WRITE_REGISTER_UCHAR(&((ChipAddr)->WriteRegisters.Register), (Value))
+
+#endif
+
+
+//
+// Define SCSI Adapter Specific Read registers structure
+//
+
+typedef struct _ADAPTER_READ_REGISTERS {
+ UCHAR Reserved00;
+ UCHAR Reserved01;
+ UCHAR OptionSelect1;
+ UCHAR OptionSelect2;
+ UCHAR Reserved04;
+ UCHAR OptionSelect5;
+ UCHAR Reserved06;
+ UCHAR Reserved07;
+ UCHAR Reserved08;
+ UCHAR Reserved09;
+ UCHAR Reserved0a;
+ UCHAR Reserved0b;
+ UCHAR DmaStatus;
+ UCHAR Reserved0d;
+ UCHAR Reserved0e;
+ UCHAR Reserved0f;
+} ADAPTER_READ_REGISTERS, *PADAPTER_READ_REGISTERS;
+
+//
+// Define SCSI Adapter Specific Write registers structure
+//
+
+typedef struct _ADAPTER_WRITE_REGISTERS {
+ UCHAR Reserved00;
+ UCHAR Reserved01;
+ UCHAR OptionSelect1;
+ UCHAR OptionSelect2;
+ UCHAR Reserved04;
+ UCHAR OptionSelect5;
+ UCHAR Reserved06;
+ UCHAR Reserved07;
+ UCHAR Reserved08;
+ UCHAR Reserved09;
+ UCHAR DmaDecode;
+ UCHAR Reserved0b;
+ UCHAR Reserved0c;
+ UCHAR Reserved0d;
+ UCHAR Reserved0e;
+ UCHAR Reserved0f;
+} ADAPTER_WRITE_REGISTERS, *PADAPTER_WRITE_REGISTERS;
+
+
+
+typedef union _ADAPTER_REGISTERS {
+ ADAPTER_READ_REGISTERS ReadRegisters;
+ ADAPTER_WRITE_REGISTERS WriteRegisters;
+} ADAPTER_REGISTERS, *PADAPTER_REGISTERS;
+
+
+
+//
+// Define Option Select Register structures.
+//
+
+typedef struct _POS_DATA_1 {
+ UCHAR AdapterEnable : 1;
+ UCHAR IoAddressSelects : 3;
+ UCHAR InterruptSelects : 2;
+ UCHAR InterruptEnable : 1;
+ UCHAR Reserved : 1;
+} POS_DATA_1, *PPOS_DATA_1;
+
+typedef struct _POS_DATA_2 {
+ UCHAR DmaSelects : 3;
+ UCHAR UnusedDmaSelect : 1;
+ UCHAR AdapterFairness : 1;
+ UCHAR PreemptCount : 2;
+ UCHAR DmaEnable : 1;
+} POS_DATA_2, *PPOS_DATA_2;
+
+typedef struct _POS_DATA_3 {
+ UCHAR Reserved : 3;
+ UCHAR SramAddressSelects : 3; // 7f4c only
+ UCHAR HostIdSelects : 2; // 7f4c only
+} POS_DATA_3, *PPOS_DATA_3;
+
+typedef struct _POS_DATA_4 {
+ UCHAR Reserved0 : 5;
+ UCHAR HostIdSelects : 1; // 7f4d & 7f4f only
+ UCHAR Reserved1 : 2;
+} POS_DATA_4, *PPOS_DATA_4;
+
+//
+// Define SCSI Dma Status Register structure.
+//
+
+typedef struct _SCSI_DMA_STATUS {
+ UCHAR Interrupt : 1;
+ UCHAR DmaRequest : 1;
+ UCHAR Reserved : 6;
+} SCSI_DMA_STATUS, *PSCSI_DMA_STATUS;
+
+//
+// Adapter configuration Information.
+//
+
+#define ONBOARD_C94_ADAPTER_ID 0x7f4c
+#define ONBOARD_C90_ADAPTER_ID 0x7f4d
+#define PLUGIN_C90_ADAPTER_ID 0x7f4f
+
+typedef struct _POS_DATA {
+ USHORT AdapterId;
+ UCHAR OptionData1;
+ UCHAR OptionData2;
+ UCHAR OptionData3;
+ UCHAR OptionData4;
+} POS_DATA, *PPOS_DATA;
+
+typedef struct _INIT_DATA {
+ ULONG AdapterId;
+ ULONG CardSlot;
+ POS_DATA PosData[8];
+}INIT_DATA, *PINIT_DATA;
+
+static const PVOID
+AdapterBaseAddress[] = {
+ (PVOID) 0x0000,
+ (PVOID) 0x0240,
+ (PVOID) 0x0340,
+ (PVOID) 0x0400,
+ (PVOID) 0x0420,
+ (PVOID) 0x3240,
+ (PVOID) 0x8240,
+ (PVOID) 0xa240
+};
+
+static const UCHAR
+AdapterInterruptLevel[] = {
+ 0x03,
+ 0x05,
+ 0x07,
+ 0x09
+};
+
+static const UCHAR
+AdapterDmaLevel[] = {
+ 0x00,
+ 0x01,
+ 0x02, // invalid setting
+ 0x03,
+ 0x04, // invalid setting
+ 0x05,
+ 0x06,
+ 0x07
+};
+
+static const UCHAR
+AdapterScsiIdC90[] = {
+ 0x06,
+ 0x07
+};
+
+static const UCHAR
+AdapterScsiIdC94[] = {
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07
+};
+
+#endif
diff --git a/private/ntos/miniport/ncr53c94/ncr53c9x.rc b/private/ntos/miniport/ncr53c94/ncr53c9x.rc
new file mode 100644
index 000000000..71f2d24c9
--- /dev/null
+++ b/private/ntos/miniport/ncr53c94/ncr53c9x.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "NCR 53c9x Driver"
+#define VER_INTERNALNAME_STR "NCR53c9x.sys"
+#define VER_ORIGINALFILENAME_STR "NCR53c9x.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/ncr53c94/sources b/private/ntos/miniport/ncr53c94/sources
new file mode 100644
index 000000000..007085359
--- /dev/null
+++ b/private/ntos/miniport/ncr53c94/sources
@@ -0,0 +1,36 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=ncr53c9x
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=ncr53c9x.c \
+ ncr53c9x.rc
diff --git a/private/ntos/miniport/oliscsi/makefile b/private/ntos/miniport/oliscsi/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/oliscsi/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/oliscsi/oliesc1.c b/private/ntos/miniport/oliscsi/oliesc1.c
new file mode 100644
index 000000000..a3ae32d8f
--- /dev/null
+++ b/private/ntos/miniport/oliscsi/oliesc1.c
@@ -0,0 +1,2364 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ oliesc1.c
+
+Abstract:
+
+ This is the port driver for the Olivetti ESC-1 SCSI adapters.
+
+Authors:
+
+ Bruno Sartirana (o-obruno) 13-Dec-1991
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+ 12-Feb-1992: (o-obruno) Replaced calls to HAL and MM with calls to
+ ScsiPortGetDeviceBase and ScsiPortFreeDeviceBase.
+
+ 8-Nov-1992: (o-obruno)
+ - Added error logging
+ - Removed adapter reset at initialization time
+ (it saves 2-3 secs.)
+ - Removed list of present peripherals
+ - Enhanced interrupt status check for better handling
+ of the ESC-2 interrupt status codes.
+
+ 9-Apr-1993: (v-egidis)
+ - Removed the search for ESC-2 cards.
+ - Added call to ESC-2/EFP-2 driver init routine.
+ - Added code to claim the primary AT disk ctrl
+ if the AT mode is enabled.
+ - Now all the routine names start with the "OliEsc1".
+ - Removed all the "static" directives, this will
+ be very useful during the debugging sessions.
+ - Now if there is an error during the execution of
+ OliEsc1Configuration routine the SP_RETURN_ERROR
+ error code is returned instead of
+ SP_RETURN_NOT_FOUND.
+ - Now all the physical slots 1-15 are checked,
+ before only slots 1-7 were checked.
+
+ 7-Jul-1993: (v-egidis)
+ - The reset has been changed to use the scsiport's
+ timer. This modification fixes the following
+ problem: the reset is taking too much DPC time.
+
+
+--*/
+
+#include "miniport.h"
+#include "oliesc1.h" // includes scsi.h
+
+
+//
+// Function declarations
+//
+// Functions that start with 'OliEsc1' are entry points
+// for the OS port driver.
+//
+
+VOID
+OliEsc1BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+OliEsc1BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+BOOLEAN
+OliEsc1GetIrql(
+ IN PEISA_CONTROLLER eisaController,
+ PUCHAR Irql
+ );
+
+BOOLEAN
+OliEsc1CheckAtMode(
+ IN PEISA_CONTROLLER eisaController,
+ PBOOLEAN AtModeEnabled
+ );
+
+ULONG
+OliEsc1DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+OliEsc1Configuration(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+OliEsc1Initialize(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+OliEsc1Interrupt(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+OliEsc1ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+BOOLEAN
+OliEsc1StartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+OliEsc1SendCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR OperationCode,
+ IN PCCB ccb
+ );
+
+BOOLEAN
+OliEsc1SendCommandQuick(
+ IN PEISA_CONTROLLER EisaController,
+ IN UCHAR TaskId,
+ IN UCHAR OperationCode,
+ IN USHORT CommandLength,
+ IN ULONG Address
+ );
+
+VOID
+OliEsc1ResetAdapter(
+ IN PVOID Context
+ );
+
+
+//
+// External entry points
+//
+
+ULONG
+OliEsc2DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+
+VOID
+OliEsc1BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build a Command Control Block for the ESC-1.
+
+Arguments:
+
+ DeviceExtension Pointer to the device extension for this driver.
+ Srb Pointer to the Scsi Request Block to service
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PCCB ccb; // Virtual address of the CCB
+ ULONG physicalAddress; // Physical address of the CCB
+ ULONG length; // Length of contiguous memory in the
+ // data buffer, starting at the
+ // beginning of the buffer
+
+ DebugPrint((3,"OliEsc1BuildCcb: Enter routine\n"));
+
+ //
+ // Get the CCB address
+ //
+
+ ccb = Srb->SrbExtension;
+
+ //
+ // Set LUN and Target ID
+ //
+
+ ccb->TaskId = Srb->Lun | (UCHAR) (Srb->TargetId << CCB_TARGET_ID_SHIFT);
+
+ //
+ // We distinguish between the Abort command and all the others, because
+ // we translate the Abort into a Target Reset, which does not require
+ // a CCB. Since a Terget Reset doesn't imply any data transfer, we skip
+ // some proceessing here below, but we use a CCB anyway, so as to allow
+ // the interrupt service routine to complete the Target Reset request
+ // like any others, without special case handling.
+ //
+
+ if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Set transfer direction bit.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ //
+ // Adapter to system transfer
+ //
+
+ ccb->TaskId |= CCB_DATA_XFER_OUT;
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ //
+ // System to adapter transfer
+ //
+
+ ccb->TaskId |= CCB_DATA_XFER_IN;
+
+ } else ccb->TaskId |= CCB_DATA_XFER_NONE;
+
+ //
+ // Set the LinkedCommandAddress to NULL. It is not used by the ESC-1,
+ // but, for safety, it's better to set it.
+ //
+
+ ccb->LinkedCommandAddress = (ULONG) NULL;
+
+ //
+ // Copy the Command Descriptor Block (CDB) into the CCB.
+ //
+
+ ScsiPortMoveMemory(ccb->Cdb, Srb->Cdb, Srb->CdbLength);
+
+ DebugPrint((3,"OliEsc1BuildCcb: CDB at %lx, length=%x\n",
+ ccb->Cdb, Srb->CdbLength));
+
+ //
+ // Set the CDB length and the data transfer length in the CCB
+ //
+
+ ccb->CdbLength = (UCHAR) Srb->CdbLength;
+ ccb->DataLength = Srb->DataTransferLength;
+
+ //
+ // Build a actter/gather list in the CCB if necessary
+ //
+
+ if (Srb->DataTransferLength > 0) {
+
+ physicalAddress = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ Srb->DataBuffer,
+ &length));
+
+ //
+ // length contains the length of contiguous memory starting
+ // at Srb->DataBuffer
+ //
+
+ if (length >= Srb->DataTransferLength) {
+
+ //
+ // The Srb->DataBuffer is contiguous: no need of
+ // scatter/gather descriptors
+ //
+
+ ccb->DataAddress = physicalAddress;
+ ccb->AdditionalRequestBlockLength = 0;
+
+ } else {
+
+ //
+ // The Srb->DataBuffer is not contiguous: we need
+ // scatter/gather descriptors
+ //
+
+ OliEsc1BuildSgl(DeviceExtension, Srb);
+
+ }
+
+ } else {
+
+ //
+ // No data transfer is requested
+ //
+
+ ccb->AdditionalRequestBlockLength = 0;
+ }
+ }
+
+ return;
+
+} // end OliEsc1BuildCcb()
+
+
+VOID
+OliEsc1BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list for the Command
+ Control Block.
+
+Arguments:
+
+ DeviceExtension Pointer to the device extension for this driver.
+ Srb Pointer to the Scsi Request Block to service
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG bytesLeft; // # of bytes left to be described
+ // in an SGL
+ PCCB ccb; // CCB address
+ PVOID dataPointer; // Pointer to the data buffer to send
+ ULONG descriptorCount; // # of scatter/gather descriptors
+ // built
+ ULONG length; // Length of contiguous memory in the
+ // data buffer, starting at a given
+ // offset
+ ULONG physicalAddress; // Physical address of the data buffer
+ ULONG physicalSgl; // Physical SGL address
+ PSGL sgl; // Virtual SGL address
+
+
+ DebugPrint((3,"OliEsc1BuildSgl: Enter routine\n"));
+
+ //
+ // Initialize some variables
+ //
+
+ dataPointer = Srb->DataBuffer;
+ bytesLeft = Srb->DataTransferLength;
+ ccb = Srb->SrbExtension;
+ sgl = &ccb->Sgl;
+ descriptorCount = 0;
+
+ //
+ // Get physical SGL address.
+ //
+
+ physicalSgl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sgl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SGL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SGL));
+
+ //
+ // Create SGL segment descriptors.
+ //
+
+ do {
+
+ DebugPrint((3,
+ "OliEsc1BuildSgl: Data buffer %lx\n", dataPointer));
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "OliEsc1BuildSgl: Physical address %lx\n",
+ physicalAddress));
+ DebugPrint((3, "OliEsc1BuildSgl: Data length %lx\n", length));
+ DebugPrint((3, "OliEsc1BuildSgl: Bytes left %lx\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ sgl->Descriptor[descriptorCount].Address = physicalAddress;
+ sgl->Descriptor[descriptorCount].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ //
+ // Write SGL length to CCB.
+ //
+
+ ccb->AdditionalRequestBlockLength = descriptorCount * sizeof(SG_DESCRIPTOR);
+
+ DebugPrint((3,"OliEsc1BuildSgl: SGL length is %d\n", descriptorCount));
+
+ //
+ // Write SGL address to CCB.
+ //
+
+ ccb->DataAddress = physicalSgl;
+
+ DebugPrint((3,"OliEsc1BuildSgl: SGL address is %lx\n", sgl));
+
+ DebugPrint((3,"OliEsc1BuildSgl: CCB address is %lx\n", ccb));
+
+ return;
+
+} // end OliEsc1BuildSgl()
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for the OS.
+
+Arguments:
+
+ Driver Object Pointer to the driver object for this driver
+
+Return Value:
+
+ Status from OliEsc1DriverEntry()
+
+--*/
+
+{
+ ULONG Esc1Status, Esc2Status;
+
+ //
+ // Search for any ESC-1
+ //
+
+ Esc1Status = OliEsc1DriverEntry(DriverObject, Argument2);
+
+ //
+ // Search for any ESC-2 and EFP-2
+ //
+
+ Esc2Status = OliEsc2DriverEntry(DriverObject, Argument2);
+
+ //
+ // The driver should return the lowest status
+ //
+
+ return MIN( Esc1Status, Esc2Status );
+
+} // end DriverEntry()
+
+
+BOOLEAN
+OliEsc1GetIrql(
+ IN PEISA_CONTROLLER eisaController,
+ PUCHAR Irql
+ )
+
+/*++
+
+Routine Description:
+
+ It reads the ESC-1's IRQL. It is assumed to be called at system
+ initialization time only, since it uses polling.
+
+Arguments:
+
+
+Return Value:
+
+ TRUE Success
+ FALSE Failure
+
+--*/
+
+{
+
+ BOOLEAN Success; // Return value
+ UCHAR IntMask; // Current System Doorbell interrupt mask value
+ ULONG i; // Auxiliary variable
+
+
+
+ //
+ // Get the current System Doorbell Interrupt Mask
+ //
+
+ IntMask = ScsiPortReadPortUchar(&eisaController->SystemDoorBellMask);
+
+ //
+ // Disable ESC-1 interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_DISABLE);
+
+
+ //
+ // Get the ESC-1 Irql
+ //
+
+ Success = OliEsc1SendCommandQuick(eisaController,
+ CCB_DATA_XFER_NONE,
+ GET_CONFIGURATION,
+ IRQL_REGISTER,
+ (ULONG) NULL);
+
+ if (Success) {
+
+ i = 0;
+
+ //
+ // Poll interrupt pending bit
+ //
+
+ while (!(ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ INTERRUPT_PENDING) && i < INTERRUPT_POLLING_TIME) {
+
+ ScsiPortStallExecution(1);
+ i++;
+
+ }
+
+ DebugPrint((4, "OliEsc1GetIrql: got INT after %ld us\n", i));
+
+ if (i < INTERRUPT_POLLING_TIME) {
+
+ //
+ // Sensed the INTERRUPT_PENDING bit. Reset the interrupt pending.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ INTERRUPT_PENDING);
+
+ //
+ // Check to see whether the command completed correctly
+ //
+
+ if ((UCHAR)
+ ((ScsiPortReadPortUshort(&eisaController->Status) >> 8)) ==
+ NO_ERROR) {
+
+ Success = TRUE;
+
+ //
+ // The IRQL value is available in the OutAddress mailbox
+ // register, in the low byte
+ //
+
+ switch((UCHAR) ScsiPortReadPortUlong(
+ &eisaController->OutAddress)) {
+
+ case 0: *Irql = (KIRQL) 11;
+ break;
+ case 1: *Irql = (KIRQL) 10;
+ break;
+ case 2: *Irql = (KIRQL) 5;
+ break;
+ case 3: *Irql = (KIRQL) 15;
+ break;
+ default: Success = FALSE;
+ }
+
+ //
+ // Unlock the Result Semaphore, so that the ESC-1 can load
+ // new values in the output mailboxes.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore,
+ SEM_UNLOCK);
+
+ } else Success = FALSE;
+
+ } else Success = FALSE;
+ }
+
+ //
+ // Restore the original interrupt mask
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask, IntMask);
+
+ return Success;
+
+} // end OliEsc1GetIrql
+
+
+BOOLEAN
+OliEsc1CheckAtMode(
+ IN PEISA_CONTROLLER eisaController,
+ PBOOLEAN AtModeEnabled
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks if this board has the AT compatible mode enabled.
+
+Arguments:
+
+ eisaController I/O address of ESC-1 controller.
+ AtModeEnabled pointer to a variable. This variable is
+ set to FALSE if the AT mode is not enable,
+ and to TRUE otherwise.
+
+Return Value:
+
+ TRUE Success
+ FALSE Failure
+
+--*/
+
+{
+
+ BOOLEAN Success; // Return value
+ UCHAR IntMask; // Current System Doorbell interrupt mask value
+ ULONG i; // Auxiliary variable
+
+ //
+ // Get the current System Doorbell Interrupt Mask
+ //
+
+ IntMask = ScsiPortReadPortUchar(&eisaController->SystemDoorBellMask);
+
+ //
+ // Disable ESC-1 interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_DISABLE);
+
+
+ //
+ // Get the ESC-1 Hard Disk Configuration value
+ //
+
+ Success = OliEsc1SendCommandQuick(eisaController,
+ CCB_DATA_XFER_NONE,
+ GET_CONFIGURATION,
+ ATCFG_REGISTER,
+ (ULONG) NULL);
+
+ if (Success) {
+
+ i = 0;
+
+ //
+ // Poll interrupt pending bit
+ //
+
+ while (!(ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ INTERRUPT_PENDING) && i < INTERRUPT_POLLING_TIME) {
+
+ ScsiPortStallExecution(1);
+ i++;
+
+ }
+
+ DebugPrint((4, "OliEsc1CheckAtMode: got INT after %ld us\n", i));
+
+ if (i < INTERRUPT_POLLING_TIME) {
+
+ //
+ // Sensed the INTERRUPT_PENDING bit. Reset the interrupt pending.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ INTERRUPT_PENDING);
+
+ //
+ // Check to see whether the command completed correctly
+ //
+
+ if ((UCHAR)
+ ((ScsiPortReadPortUshort(&eisaController->Status) >> 8)) ==
+ NO_ERROR) {
+
+ Success = TRUE;
+
+ //
+ // The AT info is available in the OutAddress mailbox
+ // register, in the low byte
+ //
+
+ if (ScsiPortReadPortUlong(&eisaController->OutAddress)& 0x01) {
+
+ *AtModeEnabled = TRUE;
+ }
+ else {
+
+ *AtModeEnabled = FALSE;
+ }
+
+ //
+ // Unlock the Result Semaphore, so that the ESC-1 can load
+ // new values in the output mailboxes.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore,
+ SEM_UNLOCK);
+
+ } else Success = FALSE;
+
+ } else Success = FALSE;
+ }
+
+ //
+ // Restore the original interrupt mask
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask, IntMask);
+
+ return Success;
+
+} // end OliEsc1CheckAtMode
+
+
+
+ULONG
+OliEsc1DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from DriverEntry(). It initializes some fields
+ in a data structure of type HW_INITIALIZATION_DATA for use by the port
+ driver.
+
+Arguments:
+
+ DriverObject Address of the context to pass to ScsiPortInitialize
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+
+ HW_INITIALIZATION_DATA hwInitializationData;
+ // Structure used to tell the upper
+ // layer the entry points of this
+ // driver
+ ULONG i; // Auxiliary variable
+ ULONG adapterCount = 0; // Indicates the slot which have been
+ // check for adapters.
+
+ DebugPrint((1,"\n\nSCSI ESC-1 MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i = 0; i < sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = OliEsc1Initialize;
+ hwInitializationData.HwFindAdapter = OliEsc1Configuration;
+ hwInitializationData.HwStartIo = OliEsc1StartIo;
+ hwInitializationData.HwInterrupt = OliEsc1Interrupt;
+ hwInitializationData.HwResetBus = OliEsc1ResetBus;
+
+ //
+ // Set number of access ranges and the bus type.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ //
+ // The ESC-1 supports tagged queuing
+ //
+
+ hwInitializationData.TaggedQueuing = TRUE;
+
+ //
+ // Indicate no buffer mapping but will need physical
+ // addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(LU_EXTENSION);
+
+ //
+ // Ask for SRB extensions for CCBs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(CCB);
+
+ DebugPrint((1,
+ "OliEsc1DriverEntry: hwInitializationData address %lx\n",
+ &hwInitializationData));
+
+ return(ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount));
+
+} // end OliEsc1DriverEntry()
+
+
+ULONG
+OliEsc1Configuration(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+ The EISA bus is scanned in search for an ESC-1 or an ESC-2 board.
+ ES: The search for an ESC-2 has been removed.
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+ Context ESC-1 registers' address space
+ ConfigInfo Configuration information structure describing
+ the board configuration
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension; // Pointer to the device extension
+ // for this driver
+ PEISA_CONTROLLER eisaController; // Base address of the ESC-1
+ // registers' address space
+ ULONG eisaSlotNumber; // Auxiliary variable
+ // in case of initialization failure
+ BOOLEAN Success = FALSE; // Indicates an adapter was found.
+ PULONG adapterCount = Context; // Indicates which slots have been
+ // checked.
+
+ deviceExtension = HwDeviceExtension;
+
+ //
+ // Check to see if an adapter is present in the system
+ //
+
+ for (eisaSlotNumber = *adapterCount + 1;
+ eisaSlotNumber < MAX_EISA_SLOTS_STD; eisaSlotNumber++) {
+
+ //
+ // Update the adpater count to indicate this slot has been checked.
+ //
+
+ (*adapterCount)++;
+
+ //
+ // Get the system physical address for this card.
+ // The card uses I/O space.
+ //
+
+ eisaController = ScsiPortGetDeviceBase(
+ deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ (BOOLEAN) TRUE);
+
+ eisaController =
+ (PEISA_CONTROLLER)((PUCHAR)eisaController + EISA_ADDRESS_BASE);
+
+ //
+ // Read the EISA board ID and check to see whether it identifies
+ // an ESC-1
+ //
+
+ if ((ScsiPortReadPortUchar(&eisaController->BoardId[0]) == 0x3D) &&
+ (ScsiPortReadPortUchar(&eisaController->BoardId[1]) == 0x89) &&
+ (ScsiPortReadPortUchar(&eisaController->BoardId[2]) == 0x10) &&
+ (ScsiPortReadPortUchar(&eisaController->BoardId[3]) == 0x21)) {
+
+ DebugPrint((1,"ESC-1 Adapter found at EISA slot %d\n",
+ eisaSlotNumber));
+
+ //
+ // Immediately disable system interrupts (bellinte).
+ // They will remain disabled (polling mode only) during
+ // the EFP initialization sequence.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemIntEnable,
+ INTERRUPTS_DISABLE);
+
+ //
+ // The adpater is not reset and assumed to be functioning.
+ // Resetting the adapter is particularly time consuming (2 secs.
+ // for the ESC-1, 3.1 secs. for the ESC-2). The BIOS on x86
+ // computers or the EISA Support F/W on the M700 computers have
+ // already reset the adapter and checked its status.
+ //
+
+ //
+ // Reset System Doorbell interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, 0x0FF);
+
+ //
+ // Enable the ESC-1 High Performance interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+ Success = TRUE;
+ break;
+ }
+
+ //
+ // In the current slot there isn't an ESC-1/ESC-2 card. Try next
+ // slot.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension,
+ (PUCHAR)eisaController - EISA_ADDRESS_BASE);
+
+ } // end for (eisaSlotNumber ...
+
+ if (!Success) {
+
+ //
+ // No adapter was found. Clear the call again flag, reset the adapter
+ // count for the next bus and return.
+ //
+
+ *Again = FALSE;
+ *adapterCount = 0;
+ return(SP_RETURN_NOT_FOUND);
+ }
+
+ //
+ // There are more slots to search so call again.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Store base address of EISA registers in device extension.
+ //
+
+ deviceExtension->EisaController = eisaController;
+
+ //
+ // Reset the "ResetInProgress" variable.
+ //
+
+ deviceExtension->ResetInProgress = 0;
+
+ //
+ // Indicate the SCSI ID of the ESC-x, that's always 7
+ //
+
+ ConfigInfo->InitiatorBusId[0] = ADAPTER_ID;
+
+ //
+ // Indicate the maximum transfer length in bytes.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE;
+
+ //
+ // Indicate the maximum number of physical segments
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS;
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Get the "AtdiskPrimaryClaimed" info
+ //
+
+ if (!OliEsc1CheckAtMode(deviceExtension->EisaController,
+ &ConfigInfo->AtdiskPrimaryClaimed)) {
+
+ DebugPrint((1,
+ "OliEsc1Configuration: Adapter initialization error.\n"));
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED
+ );
+
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Indicate which interrupt mode the adapter uses
+ //
+
+ if (ScsiPortReadPortUchar(&eisaController->GlobalConfiguration) &
+ EDGE_SENSITIVE) {
+
+ ConfigInfo->InterruptMode = Latched;
+
+ } else {
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+ }
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + EISA_ADDRESS_BASE);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ //
+ // Get the ESC-x IRQL.
+ //
+
+ if (OliEsc1GetIrql(deviceExtension->EisaController,
+ (UCHAR *) &ConfigInfo->BusInterruptLevel)) {
+
+ return SP_RETURN_FOUND;
+
+ } else {
+
+ DebugPrint((1,
+ "OliEsc1Configuration: Adapter initialization error.\n"));
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED
+ );
+
+ return SP_RETURN_ERROR;
+ }
+
+} // end OliEsc1Configuration()
+
+
+BOOLEAN
+OliEsc1Initialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ It does nothing (for now).
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+
+Return Value:
+
+ Always TRUE.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension; // Pointer to the device extension
+ // for this driver
+ PEISA_CONTROLLER eisaController; // Base address of the ESC-1
+
+ deviceExtension = HwDeviceExtension;
+ eisaController = deviceExtension->EisaController;
+
+ //
+ // Make sure that the ESC-1 High Performance interrupt is enabled.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+ //
+ // Enable system interrupts (bellinte).
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemIntEnable,
+ SYSTEM_INTS_ENABLE);
+
+ return TRUE;
+
+} // end OliEsc1Initialize()
+
+
+BOOLEAN
+OliEsc1Interrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the ESC-1 SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because an outuput mailbox is full,
+ the CCB is retrieved to complete the request.
+
+ NOTE: if the semaphore 1 is used, it must be released after resetting
+ the associated interrupt !
+
+
+Arguments:
+
+ HwDeviceExtension Device extention for this driver
+
+Return Value:
+
+ TRUE if the interrupt was expected
+
+--*/
+
+{
+ PCCB ccb;
+ PHW_DEVICE_EXTENSION deviceExtension;
+ PEISA_CONTROLLER eisaController;
+ USHORT interruptStatus;
+ ULONG physicalCcb;
+ PLU_EXTENSION LuExtension;
+ UCHAR Lun;
+ PSCSI_REQUEST_BLOCK srb;
+
+ deviceExtension = HwDeviceExtension;
+ eisaController = deviceExtension->EisaController;
+
+ //
+ // Disable interrupts to diminish the chance for other CPUs to "spin-lock"
+ // for the same interrupt vector (multi-processor environment with dynamic
+ // interrupt dispatching).
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_DISABLE);
+
+ //
+ // Check interrupt pending.
+ //
+
+ if (!(ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ INTERRUPT_PENDING)) {
+
+ //
+ // No interrupt is pending.
+ // Enable interrupts.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+ DebugPrint((2, "OliEsc1Interrupt: Unrecognized interrupt\n"));
+ return FALSE;
+ }
+
+ //
+ // Read interrupt status. The high byte is the adapter status, whereas
+ // the low byte is the device status. If the device status is not zero,
+ // an error will be returned, regardless of the adapter status.
+ //
+
+ interruptStatus = ScsiPortReadPortUshort(&eisaController->Status);
+
+ //
+ // Get physical address of CCB.
+ //
+
+ physicalCcb = ScsiPortReadPortUlong(&eisaController->OutAddress);
+
+ //
+ // Acknowledge interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, INTERRUPT_RESET);
+
+ //
+ // Unlock the Result Semaphore, so that the ESC-1 can load
+ // new values in the output mailboxes.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, SEM_UNLOCK);
+
+ //
+ // Enable interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+
+ //
+ // Get virtual CCB address.
+ //
+
+ ccb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalCcb));
+
+ //
+ // Make sure the virtual address was found.
+ //
+
+ if (ccb == NULL) {
+
+ //
+ // A bad physcial address was return by the adapter.
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ ADAPTER_ID,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESC1_BAD_PHYSICAL_ADDRESS | (ULONG) interruptStatus
+ );
+
+ return TRUE;
+ }
+
+ //
+ // Get SRB from CCB.
+ //
+
+ srb = ccb->SrbAddress;
+
+ DebugPrint((5,
+ "OliEsc1Interrupt: ccb = %lx, srb = %lx, Int Status = %x\n",
+ ccb, srb, interruptStatus));
+
+ //
+ // Check the adapter status.
+ //
+
+ switch (interruptStatus >> 8) {
+
+ case NO_ERROR:
+
+ //
+ // Check the device status.
+ //
+
+ if ((interruptStatus & 0xff) != NO_ERROR) {
+
+ //
+ // The device status is not ok: return an error. This allows
+ // the class driver to detect a media change on a removable disk
+ // unit.
+ //
+
+ DebugPrint((1, "OliEsc1Interrupt: Status = %x\n",
+ interruptStatus));
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ srb->ScsiStatus = (UCHAR) (interruptStatus & 0xff);
+ } else {
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+ }
+ break;
+
+
+ case SELECTION_TIMEOUT_EXPIRED:
+
+ srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case DATA_OVERRUN_UNDERRUN:
+
+ srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ //
+ // On the ESC-1 it is not possible to distinguish the overrun error
+ // from the underrun error.
+ // We don't log the error because the underrun error can be very
+ // common on some devices (example: scanner).
+ //
+ // ScsiPortLogError(
+ // deviceExtension,
+ // NULL,
+ // 0,
+ // ADAPTER_ID,
+ // 0,
+ // SP_INTERNAL_ADAPTER_ERROR,
+ // DATA_OVERRUN_UNDERRUN
+ // );
+ //
+
+ break;
+
+ case UNEXPECTED_BUS_FREE:
+
+ srb->SrbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ break;
+
+ case SCSI_PHASE_SEQUENCE_FAILURE:
+
+ srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ break;
+
+ case QUEUE_FULL:
+
+ srb->SrbStatus = SRB_STATUS_BUSY;
+ break;
+
+ case PARITY_ERROR:
+
+ //
+ // This is a severe error. The controller is now shut down.
+ //
+
+ srb->SrbStatus = SRB_STATUS_PARITY_ERROR;
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ ADAPTER_ID,
+ 0,
+ SP_BUS_PARITY_ERROR,
+ 0
+ );
+ break;
+
+ case PROTOCOL_ERROR:
+
+ //
+ // Return bus reset error, because the bus has been reset.
+ //
+
+ srb->SrbStatus = SRB_STATUS_BUS_RESET;
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ ADAPTER_ID,
+ 0,
+ SP_PROTOCOL_ERROR,
+ 0
+ );
+ break;
+
+ case BUS_RESET_BY_TARGET:
+
+ //
+ // No error logging.
+ //
+ // Return bus reset error, because the bus has been reset.
+ //
+
+ srb->SrbStatus = SRB_STATUS_BUS_RESET;
+ break;
+
+ case UNEXPECTED_PHASE_CHANGE:
+
+ //
+ // This is a severe error. The controller is now shut down.
+ //
+
+ case PARITY_ERROR_DURING_DATA_PHASE:
+ case AUTO_REQUEST_SENSE_FAILURE:
+ case NO_REQUEST_SENSE_ISSUED:
+ case INVALID_CONFIGURATION_COMMAND:
+ case INVALID_CONFIGURATION_REGISTER:
+ case INVALID_COMMAND:
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ ADAPTER_ID,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ interruptStatus
+ );
+ break;
+
+ default:
+
+ DebugPrint((1,
+ "OliEsc1Interrupt: Unrecognized interrupt status %x\n",
+ interruptStatus));
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ ADAPTER_ID,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ interruptStatus
+ );
+
+ } // end switch
+
+
+ if (srb->Function == SRB_FUNCTION_ABORT_COMMAND ||
+ srb->Function == SRB_FUNCTION_RESET_DEVICE) {
+
+ if (srb->Function == SRB_FUNCTION_RESET_DEVICE) {
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete, (PVOID)deviceExtension, srb);
+
+ }
+
+ //
+ // The interrupt refers to a Target Reset command issued
+ // instead of the unsupported Abort command or to a real one.
+ // All the pending requests for the target have to be completed
+ // with status SRB_STATUS_BUS_RESET (any better idea?).
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR) 0,
+ srb->TargetId,
+ (UCHAR) ALL_LUNS,
+ (UCHAR) SRB_STATUS_BUS_RESET);
+
+ //
+ // Reset all the pending request counters for the target
+ //
+
+ for (Lun = 0; Lun < 8; Lun++) {
+ LuExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ 0,
+ srb->TargetId,
+ Lun);
+
+ if (LuExtension != NULL) {
+ LuExtension->NumberOfPendingRequests = 0;
+ }
+ }
+ } else {
+
+ //
+ // Decrement the pending requests counter for this (targetId, LUN)
+ // pair
+ //
+
+ LuExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ 0,
+ srb->TargetId,
+ srb->Lun);
+ ASSERT(LuExtension);
+ LuExtension->NumberOfPendingRequests--;
+ ASSERT (LuExtension->NumberOfPendingRequests >= 0);
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete, (PVOID)deviceExtension, srb);
+ }
+
+ return TRUE;
+
+} // end OliEsc1Interrupt()
+
+
+BOOLEAN
+OliEsc1ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset ESC-1 SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+ PathId SCSI Bus path ID (always 0 for the ESC-1)
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension;
+ PEISA_CONTROLLER eisaController;
+ PLU_EXTENSION LuExtension;
+ UCHAR Lun;
+ UCHAR TargetId;
+
+ UNREFERENCED_PARAMETER(PathId);
+
+ DebugPrint((2,"OliEsc1ResetBus: Reset ESC-1 and SCSI bus\n"));
+
+ //
+ // Get the ESC-1 registers' base address
+ //
+
+ deviceExtension = HwDeviceExtension;
+ eisaController = deviceExtension->EisaController;
+
+ //
+ // If the reset is already in progress, return TRUE.
+ // This should never happen!
+ //
+
+ if (deviceExtension->ResetInProgress) {
+
+ DebugPrint((2,"OliEsc1ResetBus: The reset is already in progess.\n"));
+ return TRUE;
+ }
+
+ //
+ // Issue a board reset
+ //
+
+ OliEsc1ResetAdapter(deviceExtension);
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR) 0,
+ (UCHAR) ALL_TARGET_IDS,
+ (UCHAR) ALL_LUNS,
+ (UCHAR) SRB_STATUS_BUS_RESET);
+
+ //
+ // Reset to zero all the pending request counters
+ //
+
+ for (TargetId = 0; TargetId < 8; TargetId++) {
+ for (Lun = 0; Lun < 8; Lun++) {
+ LuExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ 0,
+ TargetId,
+ Lun);
+
+ if (LuExtension != NULL) {
+ LuExtension->NumberOfPendingRequests = 0;
+ }
+ }
+ }
+
+ //
+ // Send a "reset detected" notification.
+ //
+
+ ScsiPortNotification(ResetDetected, deviceExtension, 0);
+
+ return TRUE;
+
+} // end Oliesc1ResetBus
+
+BOOLEAN
+OliEsc1StartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to send a CCB or issue an immediate command.
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+ Srb Pointer to the Scsi Request Block to service
+
+Return Value:
+
+ Nothing
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension;
+ PEISA_CONTROLLER eisaController;
+ PLU_EXTENSION luExtension;
+ PCCB ccb;
+ UCHAR opCode;
+ BOOLEAN Send;
+
+ DebugPrint((3,"OliEsc1StartIo: Enter routine\n"));
+
+ //
+ // Get the base address of the ESC-1 registers' address space
+ //
+
+ deviceExtension = HwDeviceExtension;
+ eisaController = deviceExtension->EisaController;
+
+ //
+ // If the "ResetInProgress" flag is TRUE, no SRBs are allowed to go
+ // through because the SCSI controller needs more time to complete its
+ // initialization.
+ //
+
+ if (deviceExtension->ResetInProgress) {
+
+ DebugPrint((2,"OliEsc1StartIo: The reset is not completed yet.\n"));
+
+ //
+ // Complete the current request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_BUS_RESET;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ //
+ // Notify that a reset was detected on the SCSI bus.
+ //
+
+ ScsiPortNotification(ResetDetected, deviceExtension, 0);
+
+ //
+ // The controller is now ready for the next request.
+ //
+
+ ScsiPortNotification(NextRequest, deviceExtension, NULL);
+
+ return(TRUE);
+ }
+
+ //
+ // Assume we are going to send a command to the ESC-1
+ //
+
+ Send = TRUE;
+
+ //
+ // Get CCB from SRB
+ //
+
+ ccb = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in CCB
+ //
+
+ ccb->SrbAddress = Srb;
+
+ //
+ // Get the pointer to the extension data area associated with the
+ // pair (Srb->TargetId, Srb->Lun)
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ 0,
+ Srb->TargetId,
+ Srb->Lun);
+ ASSERT(luExtension);
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ if (Srb->TargetId == ADAPTER_ID) {
+
+ //
+ // No SCSI massages directed to the adatpter are let
+ // go through, because the adapter doesn't support any
+ //
+
+ DebugPrint((1,
+ "OliEsc1StartIo: SCSI command to adapter rejected\n"));
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ Send = FALSE;
+
+ } else {
+
+ //
+ // Increment the number of pending requests for this (targetId,
+ // LUN), so that we can process an abort request in case this
+ // command gets timed out
+ //
+
+ luExtension->NumberOfPendingRequests++;
+
+ //
+ // Build CCB.
+ //
+
+ OliEsc1BuildCcb(deviceExtension, Srb);
+
+ opCode = START_CCB;
+ }
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1,
+ "OliEsc1StartIo: Abort Cmd Target ID %d\n", Srb->TargetId));
+ //
+ // The Abort command is not supported by the ESC-x. Here we do what
+ // we can.
+ //
+
+ if (luExtension->NumberOfPendingRequests) {
+
+ //
+ // A command sent to a device has to be aborted.
+ // All we can do is to reset the target.
+ //
+
+ OliEsc1BuildCcb(deviceExtension, Srb);
+ opCode = RESET_TARGET;
+
+ } else {
+
+ //
+ // The request to abort has already completed.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ Send = FALSE;
+ }
+
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset ESC-1 and SCSI bus.
+ //
+
+ DebugPrint((1, "OliEsc1StartIo: Reset bus request received\n"));
+
+ //
+ // The following routine will ...
+ //
+ // a) reset the bus.
+ // b) complete all the active requests (including this one).
+ // c) notify that a reset was detected on the SCSI bus.
+ //
+
+ OliEsc1ResetBus(deviceExtension, (ULONG) NULL);
+
+ Send = FALSE;
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ if (Srb->TargetId == ADAPTER_ID) {
+
+ //
+ // No SCSI massages directed to the adatpter are let
+ // go through, because the adapter doesn't support any
+ //
+
+ DebugPrint((1,
+ "OliEsc1StartIo: Reset Device sent to the adapter rjected\n"));
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+ Send = FALSE;
+
+ } else {
+
+ //
+ // Increment the number of pending requests for this (targetId,
+ // LUN), so that we can process an abort request in case this
+ // command gets timed out
+ //
+
+ DebugPrint((4,"OliEsc1StartIo: Reset device ID %d\n",
+ Srb->TargetId));
+ OliEsc1BuildCcb(deviceExtension, Srb);
+ opCode = RESET_TARGET;
+ }
+ break;
+
+ default:
+
+ //
+ // Set error and complete request
+ //
+
+ DebugPrint((1,"OliEsc1StartIo: Invalid Request\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete, deviceExtension, Srb);
+
+ Send = FALSE;
+
+ } // end switch
+
+ if (Send) {
+ if (!OliEsc1SendCommand(deviceExtension, opCode, ccb)) {
+
+ DebugPrint((1,"OliEsc1StartIo: Send command timed out\n"));
+
+ //
+ // Let operating system time out SRB.
+ //
+ }
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest, deviceExtension, NULL);
+
+ return TRUE;
+
+} // end OliEsc1StartIo()
+
+
+
+VOID
+OliEsc1ResetAdapter(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ The routine resets the SCSI controller.
+
+Arguments:
+
+ Context Device adapter context pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension;
+ PEISA_CONTROLLER eisaController;
+ ULONG Delay;
+ BOOLEAN Error = FALSE;
+
+ deviceExtension = Context;
+ eisaController = deviceExtension->EisaController;
+
+ //
+ // The routine releases the control of the CPU while waiting for some
+ // status/interrupt, this is required because the reset/re-initialization
+ // of the controller can take several seconds.
+ //
+ // Reset Controller:
+ //
+ // Phase 0: Reset the controller.
+ // Phase 1: Waiting for the controller to complete its initialization.
+ // Phase 2: Small delay.
+ //
+
+ switch(deviceExtension->ResetInProgress) {
+
+ //
+ // Phase 0: Reset the controller.
+ //
+
+ case 0:
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Disable interrupts.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_DISABLE);
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Reset controller.
+ //
+
+ DebugPrint((3,
+ "OliEsc1ResetAdapter: Phase 1 (reset adapter) max time = %ld us.\n",
+ ESC_RESET_DELAY + ESC_RESET_INTERVAL * ESC_RESET_LOOPS
+ ));
+
+ //
+ // Initialize the output location to a known value.
+ //
+
+ ScsiPortWritePortUchar( (PUCHAR)&eisaController->Status,
+ (UCHAR)(~DIAGNOSTICS_OK_NO_CONFIG_RECEIVED));
+
+ //
+ // Reset ESC-1 and SCSI bus. Wait to allow the
+ // board diagnostics to complete
+ //
+
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, ADAPTER_RESET);
+
+ //
+ // Request a timer call to complete the reset.
+ //
+
+ deviceExtension->ResetTimerCalls = ESC_RESET_LOOPS + 1;
+ Delay = ESC_RESET_DELAY;
+
+ //
+ // The "ResetNotification" variable is used to keep track of the
+ // time during the reset. If the reset is not completed before
+ // the next ESC1_RESET_NOTIFICATION usec. unit, we call the
+ // "ScsiPortNotification(ResetDetected...)" routine.
+ // After the call the ScsiPort stops the delivery of SRBs for a
+ // little bit (~4 sec.).
+ //
+
+ deviceExtension->ResetNotification = 0;
+ deviceExtension->ResetInProgress++;
+ break;
+
+ //
+ // Phase 1: Waiting for the controller to complete its initialization.
+ //
+
+ case 1:
+
+ //
+ // Note that after a reset the LOW byte of the Status register is
+ // loaded with the diagnostics result code. This should be the
+ // only case, since usually the high byte reports the adapter status.
+ //
+
+ if ( (UCHAR)ScsiPortReadPortUshort(&eisaController->Status) !=
+ DIAGNOSTICS_OK_NO_CONFIG_RECEIVED ) {
+
+ Delay = ESC_RESET_INTERVAL;
+ break;
+ }
+
+ //
+ // Reset completed!
+ //
+
+ DebugPrint((1,
+ "OliEsc1ResetAdapter: Reset bus succeeded after %ld us\n",
+ ESC_RESET_DELAY + ESC_RESET_INTERVAL *
+ (ESC_RESET_LOOPS - deviceExtension->ResetTimerCalls)
+ ));
+
+ //
+ // The following delay is necessary because the adapter, immediately
+ // after a reset, is insensitive to interrupts through the Local
+ // Doorbell Register for almost 50ms. This shouldn't be and needs
+ // to be investigated further. After the adapter has accepted the very
+ // first command (see OliEsc1GetIrql()), it take 500ms to return the answer to
+ // the CPU (i.e., to generate an interrupt). The very first command sent
+ // to the adapter is a "Get Configuration" to read the IRQL register
+ // at system boot time
+ //
+
+ deviceExtension->ResetTimerCalls = 1;
+ Delay = POST_RESET_DELAY;
+ deviceExtension->ResetInProgress++;
+ break;
+
+ //
+ // Phase 2: Small delay.
+ //
+
+ case 2:
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Remove any interrupt that was pending before issuing the reset.
+ // The controller doesn't reset these interrupts.
+ //
+
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ INTERRUPT_PENDING) {
+
+ DebugPrint((3,
+ "OliEsc1ResetAdapter: The HP interrupt was pending.\n"));
+
+ //
+ // Reset the interrupt
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ INTERRUPT_PENDING);
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Enable interrupts.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // All done !
+ //
+
+ deviceExtension->ResetInProgress = 0;
+ return;
+
+ default:
+
+ //
+ // Invalid reset phase number. This should never happen!
+ //
+
+ DebugPrint((1,
+ "OliEsc1ResetAdapter: Invalid reset phase number: %x hex.\n",
+ deviceExtension->ResetInProgress ));
+
+ ASSERT(0);
+
+ Error = TRUE;
+ break;
+ }
+
+ //
+ // If no error, request a timer call.
+ //
+
+ if (!Error) {
+
+ //
+ // Check if time-out.
+ //
+
+ if (deviceExtension->ResetTimerCalls--) {
+
+ //
+ // Request a timer call.
+ //
+
+ ScsiPortNotification(RequestTimerCall,
+ deviceExtension,
+ OliEsc1ResetAdapter,
+ Delay);
+
+ //
+ // The "ResetNotification" variable is used to keep track of the
+ // time during the reset. If the reset is not completed before
+ // the next ESC1_RESET_NOTIFICATION usec. unit, we call the
+ // "ScsiPortNotification(ResetDetected...)" routine.
+ // After the call the ScsiPort stops the delivery of SRBs for a
+ // little bit (~4 sec.).
+ //
+
+ if (deviceExtension->ResetNotification >= ESC1_RESET_NOTIFICATION) {
+
+ //
+ // Notify that a reset was detected on the SCSI bus.
+ //
+
+ ScsiPortNotification(ResetDetected, deviceExtension, 0);
+
+ //
+ // Reset the "reset notification timer".
+ //
+
+ deviceExtension->ResetNotification = 0;
+ }
+
+ //
+ // Update the "reset notification timer".
+ //
+
+ deviceExtension->ResetNotification += Delay;
+ }
+ else {
+
+ //
+ // Time-out !
+ //
+
+ DebugPrint((1,
+ "OliEsc1ResetAdapter: Time-out! Reset phase number: %x hex.\n",
+ deviceExtension->ResetInProgress ));
+
+ Error = TRUE;
+ }
+ }
+
+ //
+ // If error, log it.
+ //
+
+ if (Error) {
+
+ //
+ // Log an error.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ ADAPTER_ID,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_RESET_FAILED
+ );
+
+ //
+ // We clear the "ResetInProgress" variable to force another SCSI
+ // bus reset when the driver receives the first SRB request.
+ // Note that the interrupts are left disabled at the controller level.
+ //
+
+ deviceExtension->ResetInProgress = 0;
+ }
+
+ //
+ // Done for now.
+ //
+
+ return;
+
+} // end OliEsc1ResetAdapter
+
+
+
+BOOLEAN
+OliEsc1SendCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR OperationCode,
+ IN PCCB ccb
+ )
+
+/*++
+
+Routine Description:
+
+ Send a Command Control Block to ESC-1.
+
+Arguments:
+
+ DeviceExtension Device extension for this driver
+ OperationCode Command for the ESC-1
+ ccb Pointer to the CCB
+
+Return Value:
+
+ True if command was sent.
+ False if the Command Semaphore was busy.
+
+--*/
+
+{
+
+ PEISA_CONTROLLER EisaController;
+ ULONG physicalCcb;
+ ULONG length;
+
+ //
+ // Get the base address of the ESC-1 registers' address space
+ //
+
+ EisaController = DeviceExtension->EisaController;
+
+ length = 0;
+
+ //
+ // Get the CCB physical address
+ //
+
+ physicalCcb =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL, ccb, &length));
+
+ ASSERT (length >= sizeof(CCB));
+
+ return(OliEsc1SendCommandQuick(EisaController, ccb->TaskId, OperationCode,
+ (USHORT) (CCB_FIXED_LENGTH + ccb->CdbLength),
+ physicalCcb));
+
+}
+
+BOOLEAN
+OliEsc1SendCommandQuick(
+ IN PEISA_CONTROLLER EisaController,
+ IN UCHAR TaskId,
+ IN UCHAR OperationCode,
+ IN USHORT CommandLength,
+ IN ULONG Address
+ )
+
+/*++
+
+Routine Description:
+
+ Send CCB or immediate command to ESC-1.
+
+Arguments:
+
+ EisaController Base address of the ESC-1 registers' address space
+ TaskId Task ID for the ESC-1
+ OperationCode Command code for the ESC-1
+ CommandLength Total CCB length
+ Address Physical address of the CCB
+
+Return Value:
+
+ True if the command was sent.
+ False if the Command Semaphore was busy.
+
+--*/
+
+{
+ ULONG i;
+ BOOLEAN ReturnCode = FALSE;
+
+ //
+ // Try to send the command for up to 100 microsends
+ //
+
+ for (i = 0; i < 100; i++) {
+
+
+ ScsiPortWritePortUchar(&EisaController->CommandSemaphore, SEM_LOCK);
+
+ if ((ScsiPortReadPortUchar(&EisaController->CommandSemaphore) &
+ SEM_TAKEN_MASK) == SEM_TAKEN) {
+
+ //
+ // We can send a command to the ESC-1.
+ //
+
+ ScsiPortWritePortUchar(&EisaController->InTaskId, TaskId);
+ ScsiPortWritePortUchar(&EisaController->Command, OperationCode);
+ ScsiPortWritePortUshort(&EisaController->CommandLength,
+ CommandLength);
+ ScsiPortWritePortUlong(&EisaController->InAddress, Address);
+
+ //
+ // Send an attention interrupt to the adapter.
+ //
+
+ ScsiPortWritePortUchar(&EisaController->LocalDoorBell,
+ INTERRUPT_PENDING);
+
+ ReturnCode = TRUE;
+ break;
+ }
+
+ //
+ // Stall execution for 1 microsecond.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+
+ return ReturnCode;
+
+} // end OliEsc1SendCommand()
diff --git a/private/ntos/miniport/oliscsi/oliesc1.h b/private/ntos/miniport/oliscsi/oliesc1.h
new file mode 100644
index 000000000..99ffb5a55
--- /dev/null
+++ b/private/ntos/miniport/oliscsi/oliesc1.h
@@ -0,0 +1,363 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ oliesc1.h
+
+Abstract:
+
+ This module contains the structures, specific to the Olivetti ESC-1
+ and ESC-2 host bus adapter, used by the SCSI port driver. Data
+ structures that are part of standard ANSI SCSI will be defined
+ in a header file that will be available to all SCSI device drivers.
+
+Author:
+
+ Bruno Sartirana (o-obruno) 13-Dec-1991
+
+
+Revision History:
+
+ Bruno Sartirana (o-obruno) 8-Nov-1992
+ Added error codes of the ESC-2 adapter.
+ Increased the board reset timeout to 6 secs.
+
+--*/
+
+#include <scsi.h>
+
+//
+// Minimum define
+//
+
+#define MIN(x,y) ((x) > (y) ? (y) : (x))
+
+//
+// Maximun number of EISA slots in the system
+//
+
+#define MAX_EISA_SLOTS_STD 16 // # of EISA slots possible (per EISA std)
+#define MAX_EISA_SLOTS 8 // max # that Oli machines support
+
+//
+// Base of the EISA address space
+//
+
+#define EISA_ADDRESS_BASE 0x0C80
+
+//
+// Define constants for request completion in case of bus reset
+//
+
+#define ALL_TARGET_IDS -1
+#define ALL_LUNS -1
+
+//
+// Maximum number of scatter/gather descriptors (the ESC-1 has no limit)
+//
+
+#define MAXIMUM_SGL_DESCRIPTORS 20
+
+//
+// Maximum data transfer length
+//
+
+#define MAXIMUM_TRANSFER_SIZE 0xffffffff
+
+//
+// The ESC-1 SCSI ID is fixed to 7
+//
+
+#define ADAPTER_ID 7
+
+//
+// ESC-1 8-bit command codes (for CCB)
+//
+
+#define START_CCB 0x01
+#define SEND_CONF_INFO 0x02
+#define RESET_TARGET 0x04
+#define SET_CONFIGURATION 0x40
+#define GET_CONFIGURATION 0x41
+#define GET_FW_VERSION 0x42
+#define CHECK_DEVICE_PRESENT 0x43
+
+//
+// ESC-1 configuration registers
+//
+
+#define IRQL_REGISTER 0x2
+#define ATCFG_REGISTER 0X1
+
+//
+// First byte of the Command Control Block:
+//
+// Drive Number / Transfer Direction
+//
+// --------------------------------------
+// | XFER Dir | Target ID | LU Number |
+// --------------------------------------
+// 7 6 5 4 3 2 1 0
+//
+//
+// Subfield constants:
+
+#define CCB_DATA_XFER_ANY_DIR 0 // The adapter decides
+#define CCB_DATA_XFER_IN 0x40 // XFER Dir = 01
+#define CCB_DATA_XFER_OUT 0x80 // XFER Dir = 10
+#define CCB_DATA_XFER_NONE 0xC0 // XFER Dir = 11
+#define CCB_TARGET_ID_SHIFT 3
+
+//
+// Status Register: bit 15-8: adapter status, bits 7-0: target status
+//
+// Adapter status after a power cycle:
+
+#define DIAGNOSTICS_RUNNING 0x53
+#define DIAGNOSTICS_OK_CONFIG_RECEIVED 0x01
+#define DIAGNOSTICS_OK_NO_CONFIG_RECEIVED 0x02
+
+// Adapter status after a CCB command:
+
+#define NO_ERROR 0x00
+#define INVALID_COMMAND 0x01
+#define SELECTION_TIMEOUT_EXPIRED 0x11
+#define DATA_OVERRUN_UNDERRUN 0x12
+#define UNEXPECTED_BUS_FREE 0x13
+#define SCSI_PHASE_SEQUENCE_FAILURE 0x14
+#define COMMAND_ABORTED 0x15
+#define COMMAND_TO_BE_ABORTED_NOT_FOUND 0x16
+#define QUEUE_FULL 0x1F
+#define INVALID_CONFIGURATION_COMMAND 0x20
+#define INVALID_CONFIGURATION_REGISTER 0x21
+#define NO_REQUEST_SENSE_ISSUED 0x3B
+#define AUTO_REQUEST_SENSE_FAILURE 0x80
+#define PARITY_ERROR 0x81
+#define UNEXPECTED_PHASE_CHANGE 0x82
+#define BUS_RESET_BY_TARGET 0x83
+#define PARITY_ERROR_DURING_DATA_PHASE 0x84
+#define PROTOCOL_ERROR 0x85
+
+// Codes to identify logged errors related to H/W malfunction.
+// These codes must be shifted left by 8 bits, to distinguish them from
+// the adapter status after a CCB command.
+//
+// For use with ScsiPortLogError().
+
+#define ESC1_BAD_PHYSICAL_ADDRESS (0x01 << 16)
+#define ESCX_RESET_FAILED (0x06 << 16)
+#define ESCX_INIT_FAILED (0x07 << 16)
+
+
+//
+// Define various timeouts:
+//
+// RESET_REACTION_TIME number of microseconds the adapter takes to
+// change the status register on the reset command.
+//
+// ESC_RESET_DELAY number of microseconds the driver waits for after
+// a ESC-1 reset command. The minimum value for
+// this define is RESET_REACTION_TIME.
+//
+// ESC_RESET_LOOPS maximum number of attempts made by the driver to
+// get the diagnostics result from the status
+// register after a ESC-1 reset command.
+//
+// ESC_RESET_INTERVAL number of microseconds the driver waits for after
+// each read of the status register (on the reset
+// command).
+//
+// INTERRUPT_POLLING_TIME maximum time (in microseconds) spent by driver
+// polling the adapter's interrupt register on a
+// synchronous get configuration command.
+//
+// POST_RESET_DELAY number of microseconds the adpater needs (!) after
+// a successful reset in order to accept the first
+// command (this should not happen and needs to be
+// investigated).
+//
+//
+
+#define RESET_REACTION_TIME 80
+#define ESC_RESET_DELAY 100000 // 100 msec.
+#define ESC_RESET_LOOPS 140 // 14 sec.
+#define ESC_RESET_INTERVAL 100000 // 100 msec.
+#define INTERRUPT_POLLING_TIME 1000000
+#define POST_RESET_DELAY 50000
+
+//
+// If the reset is not completed before the next ESC1_RESET_NOTIFICATION usec.
+// unit, we call the "ScsiPortNotification(ResetDetected...)" routine.
+// After the call the ScsiPort stops the delivery of SRBs for a little bit
+// (~4 sec.). The value of this define is lower than 4 sec. because:
+// a) it's more implementation indipendent.
+// b) we want really really to make sure that the SRBs are held at the ScsiPort
+// level during the reset phase.
+//
+
+#define ESC1_RESET_NOTIFICATION 1000000 // 1 sec. (in usec).
+
+//
+// System/Local Interrupt Mask Register constants
+//
+
+#define INTERRUPTS_DISABLE 0x00
+#define INTERRUPTS_ENABLE 0x80
+
+//
+// SystemIntEnable register bit definition(s) (bellinte)
+//
+
+#define SYSTEM_INTS_ENABLE 0x01
+
+//
+// System/Local Interrupt register
+//
+// bit 3: Adpater reset w/out reconfiguration (Local Interrupt Register only)
+// bit 4: Adapter reset w/ reconfiguration (Local Interrupt Register only)
+// bit 7: Interrupt pending (read), reset (write)
+//
+
+#define ADAPTER_RESET 0x08
+#define INTERRUPT_PENDING 0x80
+#define INTERRUPT_RESET 0x80
+
+
+//
+// Semaphore constants
+//
+
+#define SEM_LOCK 1
+#define SEM_TAKEN 1
+#define SEM_TAKEN_MASK 0x03
+#define SEM_UNLOCK 0
+
+//
+// Global Configuration Register bits
+//
+// Bit 3: 1 = edge-triggered interrupts
+// 0 = level-triggered interrupts
+//
+
+#define EDGE_SENSITIVE 8
+
+//
+// Command Control Block length (includes only the fields meaningful to the
+// ESC-1, SCSI Command Descriptor Block excluded)
+//
+
+#define CCB_FIXED_LENGTH 18
+
+//
+// ESC-1 registers model
+//
+
+typedef struct _EISA_CONTROLLER {
+ UCHAR BoardId[4]; // xC80
+ UCHAR Unused[4];
+ UCHAR GlobalConfiguration; // xC88 - Indicates level- or edge-triggered
+ // interrupts
+ UCHAR SystemIntEnable; // xC89 - system int enab/ctrl reg (bellinte)
+ UCHAR CommandSemaphore; // xC8A - Semaphore port 0 for the Incoming
+ // Mailbox Registers
+ UCHAR ResultSemaphore; // xC8B - Semaphore port 1 for the Outgoing
+ // Mailbox Registers
+ UCHAR LocalDoorBellMask; // xC8C - Interrupt mask register for the
+ // Local Doorbell register
+ UCHAR LocalDoorBell; // xC8D - Local Doorbell register
+ UCHAR SystemDoorBellMask; // xC8E - Interrupt mask register for the
+ // System Doorbel register
+ UCHAR SystemDoorBell; // xC8F - System Doorbell register
+ UCHAR InTaskId; // xC90 - 8-bit Incoming Mailbox Register
+ UCHAR Command; // xC91 - 8-bit Incoming Mailbox Register
+ USHORT CommandLength; // xC92 - 16-bit Incoming Mailbox Register
+ ULONG InAddress; // xC94 - 32-bit Incoming Mailbox Register
+ UCHAR OutTaskId; // xC98 - 8-bit Outgoing Mailbox register
+ UCHAR Reserved; // xC99
+ USHORT Status; // xC9A - 16-bit Outgoing Mailbox register
+ ULONG OutAddress; // xC9C - 32-bit Outgoing Mailbox register
+ // Other use: XC9C: Target ID
+ // XC9D: Device Present/
+ // not Present
+
+ } EISA_CONTROLLER, *PEISA_CONTROLLER;
+
+//
+// Scatter Gather descriptor
+//
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Length;
+ ULONG Address;
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+//
+// Scatter Gather descriptor list (SGL)
+//
+
+typedef struct _SGL {
+ SG_DESCRIPTOR Descriptor[MAXIMUM_SGL_DESCRIPTORS];
+} SGL, *PSGL;
+
+//
+// ESC-1 Command Control Block (byte-aligned)
+//
+
+#pragma pack(1)
+
+typedef struct _CCB {
+
+ //
+ // This first portion is the structure expected by the ESC-1.
+ // Its size is CCB_FIXED_LENGTH and does NOT include the variable
+ // length field Cdb (which can be 6, 10 or 12 bytes long).
+ //
+
+ UCHAR TaskId; // CCB byte 0 (bits 7-6: xfer dir;
+ // bits 5-3: target ID;
+ // bits 2-0: LUN)
+ UCHAR CdbLength; // CCB byte 1 SCSI Command Descriptor
+ // Block length
+ ULONG DataLength; // CCB bytes 2-5 Total data transfer
+ // length
+ ULONG DataAddress; // CCB bytes 6-9 Data segment address
+ ULONG AdditionalRequestBlockLength; // CCB bytes 10-13 Length of the
+ // scatter/gather list
+ ULONG LinkedCommandAddress; // CCB bytes 14-17 Not used
+ UCHAR Cdb[12]; // CCB bytes 18-29 SCSI Command
+ // Descriptor Block
+ //
+ // The following portion is for the miniport driver use only
+ //
+
+ PVOID SrbAddress; // Address of the related SRB
+ SGL Sgl; // Scatter/gather data segment list
+} CCB, *PCCB;
+
+#pragma pack()
+
+//
+// This structure is allocated on a per logical unit basis. It is necessary
+// for the Abort request handling.
+//
+
+typedef struct _LU_EXTENSION {
+ SHORT NumberOfPendingRequests; // Number of SRBs for a logical unit
+ // not completed yet
+} LU_EXTENSION, *PLU_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ PEISA_CONTROLLER EisaController;
+
+ ULONG ResetInProgress; // >0 if reset is in progress.
+ ULONG ResetTimerCalls; // # of timer calls before time-out.
+ ULONG ResetNotification; // Reset notification trigger.
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
diff --git a/private/ntos/miniport/oliscsi/oliesc2.c b/private/ntos/miniport/oliscsi/oliesc2.c
new file mode 100644
index 000000000..cb4c223b8
--- /dev/null
+++ b/private/ntos/miniport/oliscsi/oliesc2.c
@@ -0,0 +1,6108 @@
+/*++
+
+Copyright (c) 1992 Ing. C. Olivetti & C., S.p.A.
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ oliesc2.c
+
+Abstract:
+
+ This is the miniport driver for the Olivetti ESC-2 SCSI adapter.
+
+Authors:
+
+ Kris Karnos 1-Nov-1992
+ Young-Chi Tan 1-Nov-1992
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+ Founded on 8-Nov-1992 version of Bruno Sartirana's NT miniport for the ESC-1
+
+ 9-Apr-1993: (v-egidis)
+ - The "FindAdapter" process has been subdivided in
+ two phases:
+ #0, gather the # of devices on each SCSI controller.
+ #1, allocate the right quantity of uncached memory.
+ - Now if there is an error during the FindAdapter
+ process (phase #1) the SP_RETURN_ERROR error
+ code is returned instead of SP_RETURN_NOT_FOUND.
+ - Now all the physical slots 1-15 are checked,
+ before only slots 1-7 were checked.
+ - Only the 1st, the 2nd, the 3rd and the upper nibble
+ of the 4th ID byte are used to identify the EFP
+ boards. This will allow future EFP controllers to be
+ supported by this driver.
+ - The StartIo routine has been modified to behave
+ correctly when the device's command queue is full.
+ - The enqueue command routine has been modified to
+ return different error codes.
+ - The dequeue reply routine has been modified to
+ return a different error code.
+ - The interrupt routine has been modified to handle
+ more efficiently critical situations.
+ - Implemented the EFP reset.
+ CHECK BACK WITH RUFFONI THE FOLLOWING:
+ From Ruffoni's answer to one of my e-mails,
+ the EFP-2 controller re-sends all the commands
+ interrupted by a SCSI reset (this is the reason
+ why I didn't abort any pending SRBs during a SCSI
+ bus reset).
+ - ScsiPortLogError: removed the PathId, TargetId and
+ Lun (substituted with zeros) when the error is
+ global to the whole adapter.
+
+ 28-May-1993: (v-egidis)
+ - The EFP reset is now done resetting the EFP board.
+ - The "Reset Device" commands has been changed to
+ behave like the "Reset Bus" command.
+ - The "Abort" routine now verifies that the SRB to
+ abort is still outstanding before resetting the
+ SCSI bus.
+
+ 7-Jul-1993: (v-egidis)
+ - The reset has been changed to use the scsiport's
+ timer. This modification fixes the following
+ problem: the reset is taking too much DPC time.
+ - The EISA bus number is now checked during the
+ OliEsc2FindAdapter routine because this miniport
+ supports only one EISA bus.
+ (see MAX_EISA_BUSES for more info).
+
+ 14-Sep-1993: (v-egidis)
+ - Added support for the EFP-2 mirroring mode.
+
+--*/
+
+#include "miniport.h"
+#include "oliesc2.h" // includes scsi.h
+
+
+//
+// Function declarations
+//
+// Functions that start with 'OliEsc2' are entry points for this
+// NT miniport driver.
+//
+
+
+ULONG
+OliEsc2DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+OliEsc2FindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+ULONG
+OliEsc2FindAdapterPhase0(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+ULONG
+OliEsc2FindAdapterPhase1(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+OliEsc2Initialize(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+OliEsc2StartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+OliEsc2Interrupt(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+OliEsc2ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+BOOLEAN
+ReadEsc2ConfigReg(
+ IN PEISA_CONTROLLER EisaController,
+ IN UCHAR ConfigReg,
+ OUT PUCHAR ConfigByteInfo
+ );
+
+
+BOOLEAN
+OliEsc2IrqRegToIrql(
+ IN UCHAR IrqReg,
+ OUT PUCHAR pIrql
+ );
+
+BOOLEAN
+RegisterEfpQueues(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+OliEsc2ResetAdapter(
+ IN PVOID Context
+ );
+
+BOOLEAN
+GainSemaphore0(
+ PEISA_CONTROLLER EisaController
+ );
+
+VOID
+BuildEfpCmd(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+EfpGetDevinfo(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+OliEsc2DisableEfp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+EnqueueEfpCmd (
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PQ_ENTRY pEfpCmd,
+ IN PCOMMAND_QUEUE qPtr,
+ IN UCHAR TarLun,
+ OUT PUCHAR pSignal
+ );
+
+BOOLEAN
+DequeueEfpReply (
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+EfpReplyQNotFull (
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+EfpCommand (
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR TarLun
+ );
+
+BOOLEAN
+EfpGetInformation (
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+EfpGetConfiguration (
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+
+#if EFP_MIRRORING_ENABLED
+
+VOID
+OliEsc2MirrorInitialize(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN InitTime
+ );
+
+#endif // EFP_MIRRORING_ENABLED
+
+
+// Function definitions
+
+
+ULONG
+OliEsc2DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for the OS.
+
+ This routine initializes the fields of the HW_INITIALIZATION_DATA
+ structure (see SRB.H), reporting this miniport driver's entry point
+ and storage requirements, and describing the features supported by
+ this HBA. The routine then calls the Port driver's ScsiPortInitialize.
+
+Arguments:
+
+ Driver Object Pointer to the driver object for this driver
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+
+ // This structure tells the upper layer the entry points of this driver.
+ HW_INITIALIZATION_DATA hwInitializationData;
+
+ ULONG i; // Auxiliary variable
+ ESC2_CONTEXT Context; // Used to keep track of the
+ // slots that have been checked
+ // and to pass info between
+ // phase #0 and phase #1.
+
+ DebugPrint((1,"\n\nSCSI Olivetti ESC-2 MiniPort Driver.\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i = 0; i < sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set adapter bus type
+ //
+
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwFindAdapter = OliEsc2FindAdapter;
+ hwInitializationData.HwInitialize = OliEsc2Initialize;
+ hwInitializationData.HwStartIo = OliEsc2StartIo;
+ hwInitializationData.HwInterrupt = OliEsc2Interrupt;
+ hwInitializationData.HwResetBus = OliEsc2ResetBus;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(LU_EXTENSION);
+
+ //
+ // Ask for SRB extensions for SGL.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(EFP_SGL);
+
+ //
+ // Set number of access ranges.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // The ESC-2 supports tagged queueing, but it's not currently enabled.
+ //
+ // KMK EFP queueing is done in the controller, not at the target.
+ // Although the ESC-2 can support tagged queueing, the feature is
+ // currently (and for the foreseeable future) disabled.
+ //
+ hwInitializationData.TaggedQueuing = FALSE;
+
+ //
+ // We will enable the ESC-2's Automatic Request Sense (ARS) capability
+ //
+ // Note: Other parts of the code assume that ARS is enabled; if this
+ // capability is ever disabled, that code will need to be changed too.
+ //
+
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // The ESC-2 supports multiple requests per logical unit.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+
+ // KMK Do we support ReceiveEvent function?
+
+ DebugPrint((4,
+ "OliEsc2DriverEntry: hwInitializationData address %lx.\n",
+ &hwInitializationData));
+
+ //
+ // Zero out the context structure used to pass info between phases.
+ //
+
+ for (i = 0; i < sizeof(ESC2_CONTEXT); i++) {
+ ((PUCHAR)&Context)[i] = 0;
+ }
+
+ //
+ // Phase #0, gather all the info about the devices.
+ //
+
+ Context.Phase = 0;
+
+ ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &Context);
+
+ //
+ // Phase #1, perform the real driver initialization.
+ //
+
+ Context.Phase = 1;
+
+ Context.CheckedSlot = 0; // Start from the beginning.
+
+ return(ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &Context));
+
+} // end OliEsc2DriverEntry()
+
+
+ULONG
+OliEsc2FindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration. This routine checks each slot
+ on the EISA bus, checking for ESC-2 adapters. This routine will
+ act on two phases. The first one (see the 1st call to the
+ ScsiPortInitialize routine in the OliEsc2DriverEntry routine)
+ fills only the ESC2_CONTEXT structure (with the number of devices
+ attached to each EFP-2/ESC-2 SCSI controllers). The second
+ phase will use the info gathered within the ESC2_CONTEXT to
+ allocate the right amount of "non cached" memory.
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+ Context ESC-2 registers' address space
+ ConfigInfo Configuration information structure describing
+ the board configuration
+
+Return Value:
+
+ SP_RETURN_NOT_FOUND Adapter not found
+ SP_RETURN_FOUND Adapter found
+ SP_RETURN_ERROR General error
+ SP_RETURN_BAD_CONFIG Configuration error
+
+--*/
+
+{
+ PESC2_CONTEXT pContext = Context;
+
+ //
+ // This miniport supports only one EISA bus.
+ //
+
+ if (ConfigInfo->SystemIoBusNumber >= MAX_EISA_BUSES) {
+
+ *Again = FALSE;
+ return(SP_RETURN_NOT_FOUND);
+ }
+
+ //
+ // Call the routine associated to the current phase number
+ //
+
+ if (pContext->Phase == 0) {
+
+ //
+ // phase #0
+ //
+
+ return OliEsc2FindAdapterPhase0( HwDeviceExtension,
+ Context,
+ BusInformation,
+ ArgumentString,
+ ConfigInfo,
+ Again );
+
+ }
+
+ //
+ // phase #1
+ //
+
+ return OliEsc2FindAdapterPhase1( HwDeviceExtension,
+ Context,
+ BusInformation,
+ ArgumentString,
+ ConfigInfo,
+ Again );
+
+} // end OliEsc2FindAdapter()
+
+
+
+ULONG
+OliEsc2FindAdapterPhase0(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration. This routine checks each slot
+ on the EISA bus, checking for ESC-2 adapters. The routine will
+ store all the devices info within the ESC2_CONTEXT structure
+ (used during the 2nd phase).
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+ Context ESC-2 registers' address space
+ ConfigInfo Configuration information structure describing
+ the board configuration
+
+Return Value:
+
+ SP_RETURN_FOUND Adapter found
+ SP_RETURN_ERROR General error
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension; // Pointer to device extension
+ PEISA_CONTROLLER eisaController; // Base address of the ESC-2
+ // registers' address space
+ PESC2_CONTEXT pContext = Context; // Used to pass info between
+ // phase #0 and phase #1.
+ BOOLEAN ExtensionAllocated = FALSE; // Non cached extension is
+ // not yet allocated.
+ UCHAR Slot; // EISA slot #
+ UCHAR DataByte;
+
+ DebugPrint((4,"OliEsc2FindAdapterPhase0: Phase #0 started.\n"));
+
+ //
+ // Initialize pointers.
+ //
+
+ DeviceExtension = HwDeviceExtension;
+
+ //
+ // Search for any ESC2/EFP2 adapters
+ //
+
+ for (Slot = 1; Slot < MAX_EISA_SLOTS_STD; Slot++) {
+
+ //
+ // Get the system physical address for this card.
+ // The card uses I/O space.
+ //
+
+ eisaController = ScsiPortGetDeviceBase(
+ DeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * Slot),
+ 0x1000,
+ (BOOLEAN) TRUE);
+
+ //
+ // eisaController stores all our HBA's registers
+ //
+
+ eisaController =
+ (PEISA_CONTROLLER)((PUCHAR)eisaController + EISA_ADDRESS_BASE);
+
+ //
+ // Read the EISA board ID and check to see if it identifies
+ // an ESC-2 (ID 2x10893D where x = any digit greater than 1,
+ // because 2110893D is the ID of the ESC-1, which does not support
+ // the EFP interface).
+ //
+
+ DataByte = ScsiPortReadPortUchar(&eisaController->BoardId[3]);
+
+ if ((ScsiPortReadPortUchar(&eisaController->BoardId[0]) == 0x3D) &&
+ (ScsiPortReadPortUchar(&eisaController->BoardId[1]) == 0x89) &&
+ (ScsiPortReadPortUchar(&eisaController->BoardId[2]) == 0x10) &&
+ ( ((DataByte > 0x21) && ((DataByte & 0xF0) == 0x20))
+ || ((DataByte & 0xF0) == 0x50) )) {
+
+ DebugPrint((2,
+ "OliEsc2FindAdapterPhase0: ESC-2 Adapter found at EISA slot %d.\n",
+ Slot));
+
+ //
+ // Immediately disable system interrupts (bellinte).
+ // They will remain disabled (polling mode only) during
+ // the EFP initialization sequence.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemIntEnable,
+ INTERRUPTS_DISABLE);
+
+
+ // The adapter is not reset and is assumed to be functioning.
+ // Resetting the adapter is particularly time consuming
+ // (approximately 3 seconds for the ESC-2). The BIOS on x86
+ // computers or the EISA Support F/W on the M700 computers
+ // has already reset the adapter and checked its status.
+ //
+
+ // ...
+
+ //
+ // Check if we need to allocate some "non cached" memory.
+ //
+
+ if (!ExtensionAllocated) {
+
+ //
+ // Fill-in the minimum info to make the call.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE;
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+
+ //
+ // Allocate some "non cached" memory.
+ //
+
+ DeviceExtension->NoncachedExt = (PNONCACHED_EXTENSION)
+ ScsiPortGetUncachedExtension(
+ DeviceExtension,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ //
+ // Make sure that the call succeeded.
+ //
+
+ if (DeviceExtension->NoncachedExt == NULL) {
+
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase0: UncachedExtesion error.\n"));
+
+ ScsiPortLogError( DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED );
+
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // No need to make this call again.
+ //
+
+ ExtensionAllocated = TRUE;
+
+ } // end if (no extension) ....
+
+ //
+ // Store base address of EISA registers in device extension.
+ //
+
+ DeviceExtension->EisaController = eisaController;
+
+ //
+ // Store the controller type
+ //
+
+ DataByte = ScsiPortReadPortUchar(&eisaController->BoardId[3]);
+
+ DeviceExtension->Esc2 = (DataByte & 0xF0) != 0x50 ? TRUE : FALSE;
+
+ //
+ // Reset hardware interrupts.
+ //
+ // This process ensures that we can communicate with the
+ // controller in polling mode during initialization time.
+ //
+
+ //
+ // Reset System Doorbell interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, 0x0FF);
+
+ //
+ // Enable System Doorbell interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+ //
+ // Get the ESC-2 IRQL,
+ // get the SCSI device info,
+ // and finally disable the EFP mode.
+ //
+
+ if ( ReadEsc2ConfigReg(DeviceExtension->EisaController,
+ IRQL_REGISTER,
+ &DeviceExtension->IRQ_In_Use)
+ &&
+
+ OliEsc2IrqRegToIrql( DeviceExtension->IRQ_In_Use,
+ &DeviceExtension->IRQ_In_Use )
+
+ &&
+
+ EfpGetDevinfo(DeviceExtension)
+
+ &&
+
+ OliEsc2DisableEfp(DeviceExtension) ) {
+
+ //----------------------------------------
+ // Fill-in the ESC2_CONTEXT structure
+ //----------------------------------------
+
+ pContext->ScsiInfo[Slot - 1].AdapterPresent = 1;
+
+ pContext->ScsiInfo[Slot - 1].NumberOfDevices =
+ DeviceExtension->TotalAttachedDevices;
+
+ }
+ else {
+
+ //
+ // Log errror and continue the search.
+ //
+
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase0: Adapter initialization error.\n"));
+
+ ScsiPortLogError( DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED );
+
+ } // end if (Adapter configuration corret)
+
+ } // end if (ESC-2/EFP-2)
+
+ //
+ // Deallocate this I/O address and go check the next slot.
+ //
+
+ ScsiPortFreeDeviceBase(DeviceExtension,
+ (PUCHAR)eisaController - EISA_ADDRESS_BASE);
+
+ } // end for (Slot=1 to 15)
+
+ //
+ // End of phase #0.
+ //
+
+ DebugPrint((4,"OliEsc2FindAdapterPhase0: Phase #0 completed.\n"));
+
+ *Again = FALSE;
+
+ return(SP_RETURN_NOT_FOUND);
+
+} // end OliEsc2FindAdapterPhase0()
+
+
+
+
+ULONG
+OliEsc2FindAdapterPhase1(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration. This routine checks each slot
+ on the EISA bus, checking for ESC-2 adapters. The routine will
+ store all the necessary info within the ESC2_CONTEXT structure
+ (used during the 2nd phase).
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+ Context ESC-2 registers' address space
+ ConfigInfo Configuration information structure describing
+ the board configuration
+
+Return Value:
+
+ SP_RETURN_NOT_FOUND Adapter not found
+ SP_RETURN_FOUND Adapter found
+ SP_RETURN_ERROR General error
+ SP_RETURN_BAD_CONFIG Configuration error
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension; // Pointer to device extension
+ PEISA_CONTROLLER eisaController; // Base address of the ESC-2
+ // registers' address space
+ UCHAR Slot, BusCount;
+ ULONG i, TotalQueueSize;
+ UCHAR DataByte;
+ BOOLEAN Success = FALSE; // Indicates an adapter was found.
+ PESC2_CONTEXT pContext = Context; // Context pointer.
+ PUCHAR pCheckedSlot; // Indicates which slots have
+ // been checked.
+
+ DebugPrint((4,"OliEsc2FindAdapterPhase1: Phase #1 started.\n"));
+
+ //
+ // Initialize pointers.
+ //
+
+ DeviceExtension = HwDeviceExtension;
+ pCheckedSlot = &pContext->CheckedSlot;
+
+ //
+ // Check to see if an adapter is present in the system
+ //
+
+ for (Slot = *pCheckedSlot + 1; Slot < MAX_EISA_SLOTS_STD; Slot++) {
+
+ //
+ // Update the adapter count to indicate this slot has been checked.
+ //
+
+ (*pCheckedSlot)++;
+
+ //
+ // Check next slot if this is empty.
+ //
+
+ if (pContext->ScsiInfo[Slot - 1].AdapterPresent == 1) {
+
+ //
+ // Get the system physical address for this card.
+ // The card uses I/O space.
+ //
+
+ eisaController = ScsiPortGetDeviceBase(
+ DeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * Slot),
+ 0x1000,
+ (BOOLEAN) TRUE);
+
+
+ // eisaController stores all our HBA's registers
+
+ eisaController =
+ (PEISA_CONTROLLER)((PUCHAR)eisaController + EISA_ADDRESS_BASE);
+
+ //
+ // We found one!
+ //
+
+ Success = TRUE;
+ break;
+ }
+
+ } // end for (Slot 1 to 15)
+
+ if (!Success) {
+
+ //
+ // End of phase #1.
+ //
+
+ DebugPrint((4,"OliEsc2FindAdapterPhase1: Phase #1 completed.\n"));
+
+
+ //
+ // No adapter was found. Clear the call again flag, reset the
+ // adapter count for the next bus and return.
+ //
+
+ *Again = FALSE;
+ *pCheckedSlot = 0;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // There are more slots to search so call again.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Store base address of EISA registers in device extension.
+ //
+
+ DeviceExtension->EisaController = eisaController;
+
+ //
+ // Store the controller type
+ //
+
+ DataByte = ScsiPortReadPortUchar(&eisaController->BoardId[3]);
+
+ DeviceExtension->Esc2 = (DataByte & 0xF0) != 0x50 ? TRUE : FALSE;
+
+ //
+ // Reset the "ResetInProgress" variable.
+ //
+
+ DeviceExtension->ResetInProgress = 0;
+
+ //
+ // Indicate the maximum transfer length in bytes.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE; // KMK Check..
+
+ //
+ // Indicate the maximum number of physical segments
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SGL_DESCRIPTORS; // KMK yes?
+
+ // no DMA, so we use the default values (no DMA) for DMA parameters.
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+
+ //
+ // Indicate which interrupt mode the ESC-2 uses
+ //
+
+ if (ScsiPortReadPortUchar(&eisaController->GlobalConfiguration) &
+ EDGE_SENSITIVE) {
+
+ ConfigInfo->InterruptMode = Latched;
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase1: EDGE_SENSITIVE interrupts.\n"));
+
+ } else {
+
+ ConfigInfo->InterruptMode = LevelSensitive;
+ DebugPrint((4,
+ "OliEsc2FindAdapterPhase1: LEVEL_SENSITIVE interrupts.\n"));
+
+ }
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * Slot + EISA_ADDRESS_BASE);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ //
+ // Reset hardware interrupts.
+ //
+ // This process ensures that we can communicate with the controller
+ // in polling mode during initialization time.
+ //
+
+ //
+ // Reset System Doorbell interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, 0x0FF);
+
+ //
+ // Enable System Doorbell interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+ //
+ // Read the ESC-2's / EFP-2's configuration registers.
+ //
+
+ for (i=0; i < CFG_REGS_NUMBER; i++) {
+
+ if (ReadEsc2ConfigReg(DeviceExtension->EisaController,
+ (UCHAR)i,
+ &DeviceExtension->CfgRegs[i])) {
+
+ //
+ // Got it!
+ //
+
+ DeviceExtension->CfgRegsPresent[i] = TRUE;
+
+ }
+ else {
+
+ //
+ // Error reading the config register or
+ // config register not present.
+ //
+
+ DeviceExtension->CfgRegsPresent[i] = FALSE;
+ DeviceExtension->CfgRegs[i] = 0;
+ }
+ }
+
+
+ //
+ // Read the ESC-2's ATCFG register, to see if this adapter is in
+ // AT-enabled mode. If so, report that this controller is acting
+ // like an AT primary controller, to prevent access by the "AT"
+ // controller driver. An ESC-2 cannot be an AT secondary controller.
+ //
+
+ if (DeviceExtension->CfgRegsPresent[ATCFG_REGISTER] &&
+ DeviceExtension->CfgRegs[ATCFG_REGISTER] & AT_ENABLED) {
+
+ ConfigInfo->AtdiskPrimaryClaimed = TRUE;
+ }
+
+ //
+ // Get the ESC-2 IRQL.
+ //
+
+ if (!DeviceExtension->CfgRegsPresent[IRQL_REGISTER] ||
+ !OliEsc2IrqRegToIrql( DeviceExtension->CfgRegs[IRQL_REGISTER],
+ &DeviceExtension->IRQ_In_Use )) {
+
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase1: Adapter initialization error.\n"));
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED
+ );
+
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Save the IRQL value in the ConfigInfo structure.
+ //
+
+ ConfigInfo->BusInterruptLevel = DeviceExtension->IRQ_In_Use;
+
+ //
+ // Allocate queues here.
+ //
+
+ TotalQueueSize = (pContext->ScsiInfo[Slot - 1].NumberOfDevices) *
+ sizeof(EFP_COMMAND_QUEUE) +
+ sizeof(NONCACHED_EXTENSION);
+
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase1: TotalQueueSize = %d.\n",TotalQueueSize));
+
+ DeviceExtension->NoncachedExt = (PNONCACHED_EXTENSION)
+ ScsiPortGetUncachedExtension(
+ DeviceExtension,
+ ConfigInfo,
+ TotalQueueSize);
+ //
+ // Make sure that the call succeeded.
+ //
+
+ if (DeviceExtension->NoncachedExt == NULL) {
+
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase1: UncachedExtesion error.\n"));
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED
+ );
+
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // Get the SCSI devices info
+ //
+
+ if ( !EfpGetDevinfo(DeviceExtension) ) {
+
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase1: Adapter initialization error.\n"));
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED
+ );
+
+ return SP_RETURN_ERROR;
+ };
+
+ //
+ // Make sure that the two phases got the same number of devices.
+ //
+
+ if (pContext->ScsiInfo[Slot - 1].NumberOfDevices !=
+ DeviceExtension->TotalAttachedDevices) {
+
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase1: The number of devices is different:\n"
+ " phase #0: %d, phase #1: %d.\n",
+ pContext->ScsiInfo[Slot - 1].NumberOfDevices,
+ DeviceExtension->TotalAttachedDevices));
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED
+ );
+
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Count the number of buses
+ //
+
+ for ( i=0,BusCount=0 ; i < MAX_HAIDS ; i++ ) {
+ if ( DeviceExtension->Adapter_ID[i] != NO_BUS_ID ) {
+ ConfigInfo->InitiatorBusId[BusCount] =
+ DeviceExtension->Adapter_ID[i];
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase1: InitiatorBusId[%d] = %d.\n",
+ BusCount,
+ ConfigInfo->InitiatorBusId[BusCount]));
+ BusCount++;
+ };
+ };
+
+ ConfigInfo->NumberOfBuses = BusCount;
+ DeviceExtension->NumberOfBuses = BusCount;
+
+ //
+ // End of phase #1.
+ //
+
+ DebugPrint((4,"OliEsc2FindAdapterPhase1: Phase #1 multi-stage.\n"));
+
+ return SP_RETURN_FOUND;
+
+} // end OliEsc2FindAdapterPhase1()
+
+
+
+
+BOOLEAN
+OliEsc2Initialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the EFP interface on the adapter. As directed by the NT
+ miniport specification, this routine avoids resetting the SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+
+Return Value:
+
+ Returns TRUE if initialization completed successfully.
+ Returns FALSE and logs an error if adapter initialization fails.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension;
+ PEISA_CONTROLLER eisaController;
+
+ DeviceExtension = HwDeviceExtension;
+
+ eisaController = DeviceExtension->EisaController;
+
+ //
+ // At this point, we know how many devices are attached; therefore,
+ // we know how many device queues are required. We call another
+ // routine which will use the Get Configuration information stored
+ // in the uncached extension to build a new queues descriptor,
+ // allocate mailbox and device queues, and resend the EFP_SET and
+ // EFP_START commands to register this new revised information with
+ // the EFP-2 controller.
+ //
+
+ if ( !RegisterEfpQueues(DeviceExtension) ) {
+
+ DebugPrint((1,
+ "OliEsc2FindAdapterPhase1: Adapter initialization error.\n"));
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_INIT_FAILED
+ );
+
+ return(FALSE);
+ }
+
+#if EFP_MIRRORING_ENABLED
+
+ //
+ // We need to initialize all the mirroring structures.
+ //
+
+ OliEsc2MirrorInitialize(DeviceExtension, TRUE);
+
+#endif // EFP_MIRRORING_ENABLED
+
+ //
+ // The EFP-2 interface is now ready for use, so now we can
+ // enable interrupts.
+ //
+
+ //
+ // Ensure that EFP interrupts (0 and 1) are enabled.
+ // Enable also the ESC-1 High Performance interrupt, which is
+ // need for implementation of the Reset_Bus command.
+ //
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+ //
+ // Enable system interrupts (bellinte).
+ //
+ ScsiPortWritePortUchar(&eisaController->SystemIntEnable,
+ SYSTEM_INTS_ENABLE);
+
+ //
+ // Initialization completed successfully.
+ //
+
+ return(TRUE);
+} // end OliEsc2Initialize()
+
+
+BOOLEAN
+EfpGetDevinfo(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the EFP interface on the adapter. As directed by the NT
+ miniport specification, this routine avoids resetting the SCSI bus.
+
+Arguments:
+
+ DeviceExtension Device extension for this driver
+
+Return Value:
+
+ Returns TRUE if initialization completed successfully.
+ Returns FALSE and logs an error if adapter initialization fails.
+
+--*/
+
+{
+ PEISA_CONTROLLER eisaController;
+ PNONCACHED_EXTENSION pNoncachedExt;
+ ULONG i, length;
+ BOOLEAN GotInt = FALSE;
+ UCHAR EfpMsg;
+
+ eisaController = DeviceExtension->EisaController;
+ pNoncachedExt = DeviceExtension->NoncachedExt;
+
+ //
+ // Interrupts have already been disabled on entry (see OliEsc2FindAdapter).
+ // Polling is possible through enabling the ESC-1 HP and EFP interface
+ // in the System Doorbell Mask.
+ //
+
+ //
+ // 1. Issue EFP_SET command via I/O instruction 'TYPE SERVICE' to the
+ // BMIC mailbox registers.
+ //
+
+ if (!GainSemaphore0(eisaController)) {
+ return(FALSE);
+ }
+
+ // if got the semaphore, place IRQ parameter in mailbox register 1
+ ScsiPortWritePortUchar(&eisaController->InParm1,
+ DeviceExtension->IRQ_In_Use);
+
+ // output a TYPE SERVICE request: 'efp_set'
+ ScsiPortWritePortUchar(&eisaController->InTypeService, S_EFP_SET);
+
+ // set bit 1 of local doorbell register to generate interrupt request
+ // (EFP_ATTENTION)
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ // Wait for controller to respond
+ for (i = 0; i < WAIT_INT_LOOPS && !GotInt; i++) {
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell)
+ & EFP_TYPE_MSG) {
+ GotInt = TRUE;
+ }
+ else {
+ ScsiPortStallExecution(WAIT_INT_INTERVAL);
+ }
+ }
+
+ if (!GotInt) {
+ DebugPrint((1, "EfpGetDevinfo: No interrupt after EFP_SET.\n"));
+ return(FALSE);
+ }
+ else {
+ DebugPrint((4, "EfpGetDevinfo: Set, interrupt after %ld us.\n",
+ i*WAIT_INT_INTERVAL));
+
+ EfpMsg = ScsiPortReadPortUchar(&eisaController->OutTypeMsg);
+ if (EfpMsg != M_INIT_DIAG_OK) {
+ DebugPrint((1,
+ "EfpGetDevinfo: INIT_DIAG_OK not received after EFP_SET.\n"));
+ if (EfpMsg == M_ERR_INIT) {
+ DebugPrint((1,
+ "EfpGetDevinfo: M_ERR_INIT received after EFP_SET.\n"));
+ }
+ return(FALSE);
+ }
+ }
+
+ // reset bit 1 of the system doorbell register to clear request
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_MSG);
+
+ // clear semaphore 1 after reading TYPE_MSG
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, 0);
+
+ //
+ // 2. Build queues descriptor. This initial QD defines only the mailbox
+ // command queue and the reply queue.
+ //
+
+ //
+ // First, initialize queue-related fields in HW_DEVICE_EXTENSION
+ // and NONCACHED_EXTENSION.
+ //
+
+ DeviceExtension->Reply_Q_Full_Flag = 0;
+ DeviceExtension->Reply_Q_Get = 0;
+ DeviceExtension->RQ_In_Process = 0;
+ pNoncachedExt->Command_Qs[0].Cmd_Q_Get = 0;
+ pNoncachedExt->Command_Qs[0].Cmd_Q_Put = 0;
+
+ for (i = 0; i < HA_QUEUES; i++) {
+ DeviceExtension->Q_Full_Map[i] = 0;
+ DeviceExtension->DevicesPresent[i].present = FALSE;
+ }
+
+ for (i = 0; i < REPLY_Q_ENTRIES; i++) {
+ pNoncachedExt->Reply_Q[i].qnrply.nrply_flag = 0;
+ }
+
+ // set up Queues Descriptor header
+
+ pNoncachedExt->QD_Head.qdh_maint = 0; // normal environment
+ pNoncachedExt->QD_Head.qdh_n_cmd_q = 1; // # of queues
+ pNoncachedExt->QD_Head.qdh_type_reply = 0; // int after 1+
+ pNoncachedExt->QD_Head.qdh_reserved1 = 0;
+ pNoncachedExt->QD_Head.qdh_reply_q_addr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL, // No SRB
+ &pNoncachedExt->Reply_Q,
+ &length));
+ pNoncachedExt->QD_Head.qdh_n_ent_reply = REPLY_Q_ENTRIES;
+ pNoncachedExt->QD_Head.qdh_reserved2 = 0;
+
+ // set up Queues Descriptor body for mailbox queue
+
+ pNoncachedExt->QD_Bodies[0].qdb_scsi_level = 0xFF;
+ pNoncachedExt->QD_Bodies[0].qdb_channel = 0xFF;
+ pNoncachedExt->QD_Bodies[0].qdb_ID = 0xFF;
+ pNoncachedExt->QD_Bodies[0].qdb_LUN = 0xFF;
+ pNoncachedExt->QD_Bodies[0].qdb_n_entry_cmd = COMMAND_Q_ENTRIES;
+ pNoncachedExt->QD_Bodies[0].qdb_notfull_int = 1;
+ pNoncachedExt->QD_Bodies[0].qdb_no_ars = 0; // ESC2/EFP2
+ pNoncachedExt->QD_Bodies[0].qdb_timeout = 0;
+ pNoncachedExt->QD_Bodies[0].qdb_cmd_q_addr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL, // no SRB
+ &pNoncachedExt->Command_Qs[0],
+ &length));
+ pNoncachedExt->QD_Bodies[0].qdb_reserved = 0;
+
+ // store the controller mailbox info in common area
+
+ DeviceExtension->DevicesPresent[0].present = TRUE;
+ DeviceExtension->DevicesPresent[0].qnumber = 0;
+ DeviceExtension->DevicesPresent[0].qPtr = &pNoncachedExt->Command_Qs[0];
+
+ //
+ // 3. Issue EFP_START command to BMIC mailbox registers.
+ //
+
+ if (!GainSemaphore0(eisaController)) {
+ return(FALSE);
+ }
+
+ //
+ // Get the physical address of the queues descriptor (and store it,
+ // as we'll need it in RegisterEfpQueues).
+ //
+
+ DeviceExtension->QueuesDescriptor_PA =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL, // no SRB
+ &pNoncachedExt->QD_Head,
+ &length));
+
+ // if got the semaphore, output physical address of the queues descriptor
+ // to mailbox registers 1 - 4.
+ ScsiPortWritePortUlong((PULONG)&eisaController->InParm1,
+ DeviceExtension->QueuesDescriptor_PA);
+
+ // output a TYPE SERVICE request to 'efp_start'
+ ScsiPortWritePortUchar(&eisaController->InTypeService, S_EFP_START);
+
+ // set bit 1 of local doorbell register to generate an interrupt request
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ // Wait for controller to respond.
+ GotInt = FALSE; // re-initialize GotInt
+ for (i = 0; i < WAIT_INT_LOOPS && !GotInt; i++) {
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ EFP_TYPE_MSG) { // was EFP_MSG_INT()
+ GotInt = TRUE;
+ }
+ else {
+ ScsiPortStallExecution(WAIT_INT_INTERVAL);
+ }
+ }
+
+ if (!GotInt) {
+ DebugPrint((1, "EfpGetDevinfo: No interrupt after EFP_START.\n"));
+ return(FALSE);
+ }
+ else {
+ DebugPrint((4, "EfpGetDevinfo: Start, interrupt after %ld us.\n",
+ i*WAIT_INT_INTERVAL));
+
+ EfpMsg = ScsiPortReadPortUchar(&eisaController->OutTypeMsg);
+ if (EfpMsg != M_INIT_DIAG_OK) {
+ DebugPrint((1,
+ "EfpGetDevinfo: INIT_DIAG_OK not received after EFP_START.\n"));
+ if (EfpMsg == M_ERR_INIT) {
+ DebugPrint((1,
+ "EfpGetDevinfo: M_ERR_INIT received after EFP_START.\n"));
+ }
+ return(FALSE);
+ }
+ }
+
+ // reset bit 1 of the system doorbell register to clear request
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_MSG);
+
+ // clear semaphore 1 after reading TYPE_MSG (RELEASE_SEM1)
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, 0);
+
+ //
+ // 4. Issue Get_Information command.
+ //
+
+ if (!EfpGetInformation(DeviceExtension)) {
+ DebugPrint((1, "EfpGetDevinfo: EFP Get_Information failed.\n"));
+ return(FALSE);
+ }
+
+ if (DeviceExtension->Max_CmdQ_ents < COMMAND_Q_ENTRIES) {
+ DebugPrint((1,
+ "EfpGetDevinfo: Controller's max command q size too small.\n"));
+ return(FALSE);
+ }
+
+ //
+ // 5. Issue Get_Configuration command.
+ //
+
+ if (!EfpGetConfiguration(DeviceExtension)) {
+ DebugPrint((1, "EfpGetDevinfo: EfpGetConfiguration failed.\n"));
+ return(FALSE);
+ }
+
+ DeviceExtension->TotalAttachedDevices =
+ (USHORT)(DeviceExtension->Q_Buf.qmbr.mbr_length / sizeof(GET_CONF));
+ DebugPrint((1,"EfpGetDevinfo: TotalAttachedDevices = %d.\n",
+ DeviceExtension->TotalAttachedDevices));
+ return(TRUE);
+
+
+} // end EfpGetDevinfo()
+
+
+BOOLEAN
+OliEsc2DisableEfp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Disables the EFP interface on the adapter sending the SET command.
+
+Arguments:
+
+ DeviceExtension Device extension for this driver
+
+Return Value:
+
+ Returns TRUE if initialization completed successfully.
+ Returns FALSE and logs an error if adapter initialization fails.
+
+--*/
+
+{
+ PEISA_CONTROLLER eisaController;
+ ULONG i;
+ BOOLEAN GotInt = FALSE;
+ UCHAR EfpMsg;
+
+ eisaController = DeviceExtension->EisaController;
+
+ //
+ // Interrupts have already been disabled on entry (see OliEsc2FindAdapter).
+ // Polling is possible through enabling the ESC-1 HP and EFP interface
+ // in the System Doorbell Mask.
+ //
+
+ //
+ // Issue EFP_SET command via I/O instruction 'TYPE SERVICE' to the
+ // BMIC mailbox registers.
+ //
+
+ if (!GainSemaphore0(eisaController)) {
+ return(FALSE);
+ }
+
+ // if got the semaphore, place IRQ parameter in mailbox register 1
+ ScsiPortWritePortUchar(&eisaController->InParm1,
+ DeviceExtension->IRQ_In_Use);
+
+ // output a TYPE SERVICE request: 'efp_set'
+ ScsiPortWritePortUchar(&eisaController->InTypeService, S_EFP_SET);
+
+ // set bit 1 of local doorbell register to generate interrupt request
+ // (EFP_ATTENTION)
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ // Wait for controller to respond
+ for (i = 0; i < WAIT_INT_LOOPS && !GotInt; i++) {
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell)
+ & EFP_TYPE_MSG) {
+ GotInt = TRUE;
+ }
+ else {
+ ScsiPortStallExecution(WAIT_INT_INTERVAL);
+ }
+ }
+
+ if (!GotInt) {
+ DebugPrint((1, "OliEsc2Disable: No interrupt after EFP_SET.\n"));
+ return(FALSE);
+ }
+ else {
+ DebugPrint((4, "OliEsc2Disable: Set, interrupt after %ld us.\n",
+ i*WAIT_INT_INTERVAL));
+
+ EfpMsg = ScsiPortReadPortUchar(&eisaController->OutTypeMsg);
+ if (EfpMsg != M_INIT_DIAG_OK) {
+ DebugPrint((1,
+ "OliEsc2Disable: INIT_DIAG_OK not received after EFP_SET.\n"));
+ if (EfpMsg == M_ERR_INIT) {
+ DebugPrint((1,
+ "OliEsc2Disable: M_ERR_INIT received after EFP_SET.\n"));
+ }
+ return(FALSE);
+ }
+ }
+
+ // reset bit 1 of the system doorbell register to clear request
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_MSG);
+
+ // clear semaphore 1 after reading TYPE_MSG
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, 0);
+
+ return(TRUE);
+}
+
+
+
+BOOLEAN
+OliEsc2StartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to send an SRB or issue an immediate command.
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+ Srb Pointer to the Scsi Request Block to service
+
+Return Value:
+
+ Nothing
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ PLU_EXTENSION luExtension;
+ PEFP_SGL pEFP;
+ UCHAR opCode = 0;
+ UCHAR qnumber, TarLun, SignalFlag;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ UCHAR Bus;
+
+ DebugPrint((3,"OliEsc2StartIo: Enter routine.\n"));
+
+ //
+ // Get the base address of the ESC-2 registers' address space
+ //
+
+ DeviceExtension = HwDeviceExtension;
+ eisaController = DeviceExtension->EisaController;
+
+ //
+ // Get EFP command extension from SRB
+ //
+
+ pEFP = Srb->SrbExtension;
+
+
+ DebugPrint((3,"OliEsc2StartIo: Srb->Function = %x,\n", Srb->Function));
+ DebugPrint((3,"OliEsc2StartIo: PathId=%d TargetId=%d Lun=%d.\n",
+ Srb->PathId,Srb->TargetId,Srb->Lun));
+
+ //
+ // If the "ResetInProgress" flag is TRUE, no SRBs are allowed to go
+ // through because the SCSI controller needs more time to complete its
+ // initialization.
+ //
+
+ if (DeviceExtension->ResetInProgress) {
+
+ DebugPrint((2,"OliEsc2StartIo: The reset is not completed yet.\n"));
+
+ //
+ // Complete the current request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_BUS_RESET;
+ ScsiPortNotification(RequestComplete, DeviceExtension, Srb);
+
+ //
+ // Notify that a reset was detected on the SCSI bus.
+ //
+
+ for (Bus=0; Bus < DeviceExtension->NumberOfBuses; Bus++) {
+ ScsiPortNotification(ResetDetected, DeviceExtension, Bus);
+ }
+
+ //
+ // The controller is now ready for the next request.
+ //
+
+ ScsiPortNotification(NextRequest, DeviceExtension, NULL);
+
+ return(TRUE);
+ }
+
+ //
+ // Perform the requested function.
+ //
+
+ switch (Srb->Function) {
+
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ TarLun = GET_QINDEX(Srb->PathId, Srb->TargetId, Srb->Lun);
+
+ //
+ // Do not process requests to non-existent devices.
+ //
+
+ if (Srb->TargetId == DeviceExtension->Adapter_ID[Srb->PathId] ||
+ !DeviceExtension->DevicesPresent[TarLun].present) {
+
+ //
+ // We are filtering SCSI messages directed to not present
+ // devices and messages to the host adapter itself.
+ //
+
+ DebugPrint((2,
+ "OliEsc2StartIo: Rejected SCSI cmd to TID %d LUN %d.\n",
+ Srb->TargetId, Srb->Lun));
+
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+
+ ScsiPortNotification(RequestComplete, DeviceExtension, Srb);
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL);
+ return(TRUE);
+
+ }
+ break;
+
+ //
+ // ... if the request is for a valid device, go at the end of this
+ // switch body.
+ //
+
+
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((2, "OliEsc2StartIo: Abort Cmd Target ID %d.\n",
+ Srb->TargetId));
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ abortedSrb = ScsiPortGetSrb(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ if (abortedSrb != Srb->NextSrb ||
+ abortedSrb->SrbStatus != SRB_STATUS_PENDING) {
+
+ DebugPrint((1,
+ "OliEsc2StartIo: SRB to abort already completed.\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification(RequestComplete,
+ DeviceExtension,
+ Srb);
+
+ }
+ else {
+
+ //
+ // Only Reset Bus, not Abort Request or Reset Device, is supported
+ // on the ESC-2 in EFP mode, so we will send a Reset Bus command.
+ //
+
+ //
+ // The following routine will ...
+ //
+ // a) reset the bus.
+ // b) complete all the active requests (including this one).
+ // c) notify that a reset was detected on the SCSI bus.
+ //
+
+ OliEsc2ResetBus(DeviceExtension, Srb->PathId);
+
+ }
+
+ //
+ // The controller is now ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL);
+ return(TRUE);
+
+
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset ESC-2 and SCSI bus.
+ //
+
+ DebugPrint((2, "OliEsc2StartIo: Reset bus request received.\n"));
+
+ //
+ // The following routine will ...
+ //
+ // a) reset the bus.
+ // b) complete all the active requests (including this one).
+ // c) notify that a reset was detected on the SCSI bus.
+ //
+
+ OliEsc2ResetBus(DeviceExtension, Srb->PathId);
+
+ //
+ // The controller is now ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL);
+ return(TRUE);
+
+
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ //
+ // Only Reset Bus, not Reset Device, is supported on the ESC-2
+ // in EFP mode, so we will send a Reset Bus command.
+ //
+
+ DebugPrint((2, "OliEsc2StartIo: Reset Device Target ID %d.\n",
+ Srb->TargetId));
+
+ //
+ // The following routine will ...
+ //
+ // a) reset the bus.
+ // b) complete all the active requests (including this one).
+ // c) notify that a reset was detected on the SCSI bus.
+ //
+
+ OliEsc2ResetBus(DeviceExtension, Srb->PathId);
+
+ //
+ // The controller is now ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL);
+ return(TRUE);
+
+
+
+ default:
+
+ //
+ // Set error and complete request
+ //
+
+ DebugPrint((1, "OliEsc2StartIo: Invalid Request.\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete, DeviceExtension, Srb);
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL);
+
+
+ return(TRUE);
+
+ } // end switch (function to perform)
+
+
+ //-----------------------------------------------------------------
+ // The following code can be executed only if we are coming from
+ // the SRB_FUNCTION_EXECUTE_SCSI function.
+ //-----------------------------------------------------------------
+
+ //
+ // Get the pointer to the extension data area associated with
+ // the pair (Srb->TargetId, Srb->Lun)
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ ASSERT(luExtension);
+
+ //
+ // Increment the number of pending requests for this (targetId,
+ // LUN), so that we can process an abort request in case this
+ // command gets timed out
+ //
+
+ luExtension->NumberOfPendingRequests++;
+
+ //
+ // Build EFP command.
+ //
+
+ BuildEfpCmd(DeviceExtension, Srb);
+
+ //
+ // Enqueue the command
+ //
+
+ if (!EnqueueEfpCmd(DeviceExtension,
+ &pEFP->EfpCmd,
+ DeviceExtension->DevicesPresent[TarLun].qPtr,
+ TarLun,
+ &SignalFlag)) {
+
+ //
+ // Error enqueuing the command.
+ //
+
+ if (SignalFlag) { // send command time out
+
+ //
+ // Let the operating system time-out this SRB.
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ Srb->PathId,
+ DeviceExtension->Adapter_ID[Srb->PathId],
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ SEND_COMMAND_TIMED_OUT
+ );
+
+ DebugPrint((1,"OliEsc2StartIo: Send command timed out.\n"));
+
+ //
+ // Ready for the next command but not for the same queue.
+ //
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL);
+
+ //
+ // Note: the StartIo return code is not checked.
+ //
+
+ return (FALSE);
+
+ }
+ else { // command not enqueued, queue was full
+
+ //
+ // Note: this error should never happen !
+ //
+
+ qnumber = DeviceExtension->DevicesPresent[TarLun].qnumber;
+
+ DebugPrint((1, "OliEsc2StartIo: Command queue %d was full.\n",
+ qnumber));
+
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+
+ ScsiPortNotification(RequestComplete, DeviceExtension, Srb);
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL);
+
+ return (TRUE);
+ }
+
+ } // end if (command not enqueued)
+
+ //
+ // The command has been enqueued,
+ // the adapter is ready for the next command.
+ //
+
+ if (SignalFlag) { // command enqueued, queue not full
+
+ //
+ // ESC-2 supports multiple requests and
+ // the queue for this device is not full.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ return(TRUE);
+
+ }
+ else { // command enqueued, queue is now full
+
+ //
+ // The queue is now full, no more commands for this device.
+ //
+
+ qnumber = DeviceExtension->DevicesPresent[TarLun].qnumber;
+ DeviceExtension->Q_Full_Map[qnumber] = 1;
+
+ DebugPrint((2,"OliEsc2StartIo: Command queue %d is now full.\n",
+ qnumber));
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL);
+
+ return(TRUE);
+
+ }
+
+} // end OliEsc2StartIo()
+
+
+BOOLEAN
+OliEsc2Interrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the ESC-2 SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because an output mailbox is full,
+ the SRB is retrieved to complete the request.
+
+ NOTE: if the semaphore 1 is used, it must be released after resetting
+ the associated interrupt !
+
+Arguments:
+
+ HwDeviceExtension Device extention for this driver
+
+Return Value:
+
+ TRUE if the interrupt was expected
+
+
+// START NOTE EFP_MIRRORING_ENABLED.
+//
+// The OliEsc2Interrupt routine always uses the "userid" field of the
+// NORMAL_REPLY struct to retrieve the SRB. This is OK because the "userid"
+// field is at the same offset in both structures (NORMAL_REPLY and
+// MIRROR_REPLY).
+//
+// END NOTE EFP_MIRRORING_ENABLED.
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ PLU_EXTENSION LuExtension;
+ UCHAR messagedata, qnumber, intpending;
+ PSCSI_REQUEST_BLOCK pSrb;
+ UCHAR sensevalid = FALSE;
+
+#if EFP_MIRRORING_ENABLED
+
+ PMIRROR_REPLY mr;
+ PMREPLY_SDATA pMreplySdata;
+ UCHAR TarLun;
+ PTAR_Q pDevInfo;
+ USHORT Index;
+ SENSE_DATA Sdata;
+
+#endif // EFP_MIRRORING_ENABLED
+
+ DeviceExtension = HwDeviceExtension;
+ eisaController = DeviceExtension->EisaController;
+
+ //
+ // Disable interrupts to diminish the chance for other CPUs to "spin-lock"
+ // for the same interrupt vector (multi-processor environment with dynamic
+ // interrupt dispatching).
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_DISABLE);
+
+ //
+ // Check interrupt pending.
+ //
+
+ intpending = ScsiPortReadPortUchar(&eisaController->SystemDoorBell);
+
+ DebugPrint((3, "OliEsc2Interrupt: intpending on entry is: %x.\n",
+ intpending));
+
+ //
+ // Check if this is our interrupt
+ //
+
+ if (!(intpending & INTERRUPTS_ENABLE)) {
+
+ //
+ // No interrupt is pending.
+ // Enable interrupts.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+ return(FALSE);
+
+ }
+
+ //
+ // Check if any ESC-1 type interrupt
+ //
+
+ if (intpending & ESC_INT_BIT) {
+
+ //
+ // Int this driver, ESC-1 HP interrupts are used only for the
+ // reset_bus command.
+ //
+
+ //
+ // reset the interrupt
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ ESC_INT_BIT);
+ //
+ // unlock the semaphore
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore,
+ SEM_UNLOCK);
+
+ }
+
+ //
+ // Check for any EFP_TYPE_MSG interrupt
+ //
+
+ if (intpending & EFP_TYPE_MSG) {
+
+ //
+ // Get the message.
+ //
+
+ messagedata = ScsiPortReadPortUchar(&eisaController->OutTypeMsg);
+
+ //
+ // Acknowledge the type message interrupt
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_MSG);
+
+ //
+ // Unlock the Result Semaphore, so that the ESC-2 can load
+ // new values in the output mailboxes.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, SEM_UNLOCK);
+
+ //
+ // Check the type of message.
+ //
+
+ if (messagedata & M_ERR_CMDQ_NFUL) {
+
+ //
+ // The queue is no longer full. Notify the ScsiPort driver.
+ //
+
+ messagedata &= 0x7F;
+ qnumber = (UCHAR)messagedata;
+ DeviceExtension->Q_Full_Map[qnumber] = 0;
+
+ ScsiPortNotification(
+ NextLuRequest,
+ DeviceExtension,
+ DeviceExtension->NoncachedExt->QD_Bodies[qnumber].qdb_channel - 1,
+ DeviceExtension->NoncachedExt->QD_Bodies[qnumber].qdb_ID,
+ DeviceExtension->NoncachedExt->QD_Bodies[qnumber].qdb_LUN
+ );
+
+ //
+ // Send a info message to the debug port
+ //
+
+ DebugPrint((2,"OliEsc2Interrupt: Command queue %d not full.\n",
+ qnumber));
+
+ }
+ else if (messagedata == M_REPLY_Q_FULL) {
+
+ //
+ // mark reply Q full
+ //
+
+ DeviceExtension->Reply_Q_Full_Flag = 0x01;
+
+ //
+ // NOTE: This is just a workaround for the ESC-2 firmware.
+ // (at least up to revision 2.25).
+ // If the reply queue gets full, the ESC-2 firmware
+ // sends only the "Reply Queue Full" message.
+ // To make it work with our logic we need to simulate
+ // a "Command Complete" interrupt.
+ //
+
+ intpending |= EFP_CMD_COMPL;
+
+ //
+ // Send a info message to the debug port
+ //
+
+ DebugPrint((2,"OliEsc2Interrupt: Reply queue is full.\n"));
+
+ }
+ else {
+
+ //
+ // Send a warning message to the debug port
+ //
+
+ DebugPrint((1, "OliEsc2Interrupt: Unknown message: %x.\n",
+ messagedata));
+
+ }
+
+ } // end {int_status is EFP_TYPE_MESSAGE}
+
+ //
+ // Check if any EFP command complete interrupt
+ //
+
+ if (intpending & EFP_CMD_COMPL) {
+
+ //
+ // This is the EFP command completion processing
+ //
+ //
+ // Loop through the reply queue start from Reply_Get to look for
+ // valid reply entry and send out command completion
+ //
+
+ while (1) {
+
+ //
+ // Acknowledge interrupt.
+ //
+ // The interrupt is reset each time a reply is dequeued
+ // to remove any subsequent interrupts of the same type.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ EFP_ACK_INT);
+
+ //
+ // Dequeue a reply.
+ //
+
+ if (!DequeueEfpReply(DeviceExtension)) {
+
+ //
+ // Note: also if there was an error during the dequeue
+ // phase, we still need to check the RQ_In_Process
+ // for any valid reply.
+ //
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_REPLY_DEQUEUE_ERROR
+ );
+
+ //
+ // Send error message to the debug port
+ //
+
+ DebugPrint((1, "OliEsc2Interrupt: Reply dequeue error.\n"));
+ }
+
+ //
+ // Note: this is the only place where we can exit the loop !
+ //
+
+ if (DeviceExtension->RQ_In_Process == 0x00) { // any reply ?
+ break; // No, exit loop.
+ }
+
+ //
+ // Check for any EFP_TYPE_MSG interrupt.
+ // We need to update the Reply_Q_Full_Flag before dequeuing
+ // another request.
+ //
+
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ EFP_TYPE_MSG) {
+
+ //
+ // Get the message.
+ //
+
+ messagedata = ScsiPortReadPortUchar(
+ &eisaController->OutTypeMsg);
+
+ //
+ // Acknowledge the type message interrupt
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ EFP_ACK_MSG);
+
+ //
+ // Unlock the Result Semaphore, so that the ESC-2 can load
+ // new values in the output mailboxes.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore,
+ SEM_UNLOCK);
+
+ //
+ // Check the type of message.
+ //
+
+ if (messagedata & M_ERR_CMDQ_NFUL) {
+
+ //
+ // The queue is no longer full. Notify the ScsiPort driver.
+ //
+
+ messagedata &= 0x7F;
+ qnumber = (UCHAR)messagedata;
+ DeviceExtension->Q_Full_Map[qnumber] = 0;
+
+ ScsiPortNotification(
+ NextLuRequest,
+ DeviceExtension,
+ DeviceExtension->NoncachedExt->QD_Bodies[qnumber].
+ qdb_channel - 1,
+ DeviceExtension->NoncachedExt->QD_Bodies[qnumber].
+ qdb_ID,
+ DeviceExtension->NoncachedExt->QD_Bodies[qnumber].
+ qdb_LUN
+ );
+
+ //
+ // Send a info message to the debug port
+ //
+
+ DebugPrint((2,
+ "OliEsc2Interrupt: Command queue %d not full.\n",
+ qnumber));
+
+ }
+ else if (messagedata == M_REPLY_Q_FULL) {
+
+ //
+ // mark reply Q full
+ //
+
+ DeviceExtension->Reply_Q_Full_Flag = 0x01;
+
+ //
+ // Send a info message to the debug port
+ //
+
+ DebugPrint((2,
+ "OliEsc2Interrupt: Reply queue is full.\n"));
+
+ }
+ else {
+
+ //
+ // Send a warning message to the debug port
+ //
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Unknown message: %x.\n",
+ messagedata));
+
+ }
+
+ } // end {int_status is EFP_TYPE_MESSAGE}
+
+ //
+ // Make sure the reply is valid.
+ //
+
+ pSrb = (PVOID) DeviceExtension->Q_Buf.qnrply.nrply_userid;
+ if (pSrb == NULL) {
+
+ //
+ // Can't get valid SRB pointer for this reply entry
+ // Log it as an error.
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_BAD_PHYSICAL_ADDRESS
+ );
+
+ //
+ // Send error message to the debug port
+ //
+
+ DebugPrint((1, "OliEsc2Interrupt: Bad physical address.\n"));
+
+ //
+ // Go check if there is any other reply.
+ //
+
+ continue;
+ }
+
+ //
+ // The ESC-2 and EFP-2 don't report the underrun/overrun error
+ // during the execution of some commands (example: inquiry).
+ // The following code detects these cases and simulates an
+ // underrun/overrun error.
+ //
+
+ if (DeviceExtension->Q_Buf.qnrply.nrply_scsi_len !=
+ pSrb->DataTransferLength &&
+ (DeviceExtension->Q_Buf.qnrply.nrply_status == EFP_CMD_SUCC ||
+ DeviceExtension->Q_Buf.qnrply.nrply_status == EFP_AUTOREC_OK)){
+
+ DeviceExtension->Q_Buf.qnrply.nrply_status = EFP_DATA_RUN;
+
+ DebugPrint((2,
+ "OliEsc2Interrupt: Simulated an overrun/underrun error.\n"));
+ }
+
+ //
+ // Check the status of the operation.
+ //
+
+#if EFP_MIRRORING_ENABLED
+
+ // ---------------------------------------------------------------
+ //
+ // MIRRORING REPLY
+ //
+ // ---------------------------------------------------------------
+
+ //
+ // Initialize pointer to mirroring reply
+ //
+
+ mr = &DeviceExtension->Q_Buf.qmrply;
+
+ if (mr->mrply_flag == MREPLY_VALID) {
+
+ //
+ // Get the reply state.
+ //
+
+ switch (mr->mrply_off_attr){
+
+ case EFP_SOURCE_OFFLINE:
+
+ //
+ // Get the mirror disk status.
+ //
+
+ pMreplySdata = (PMREPLY_SDATA)&mr->mrply_valid2;
+ break;
+
+
+ case EFP_MIRROR_OFFLINE:
+
+ //
+ // Get the source disk status.
+ //
+
+ pMreplySdata = (PMREPLY_SDATA)&mr->mrply_valid1;
+ break;
+
+
+ default:
+
+ //
+ // Mirroring in progress, get the status of
+ // the disk that has the SCSI status related
+ // to the SCSI device and not to controller.
+ // If both disks have a valid SCSI status, get
+ // the lowest. The following table shows the
+ // possible values of "Valid":
+ //
+ // 00 -> Ok or Sense Data related to the controller.
+ // 70 -> Sense data related to the disk.
+ // F0 -> Sense data related to the disk.
+ // 31 -> Ok (condition met).
+ // 32 -> EFP-2 never returns this value because if
+ // the 1st and 2nd ARP fail, it returns
+ // hardware error using the "00" value.
+ // 34 -> Ok (intermediate good).
+ // 35 -> Ok (intermediate good/condition met).
+ // 36 -> EFP-2 never returns this value because if
+ // the 1st and 2nd ARP fail, it returns
+ // hardware error using the "00" value.
+ //
+
+ if (mr->mrply_valid2 == EFP_NO_ERROR) {
+
+ //
+ // Get the source disk status
+ //
+
+ pMreplySdata = (PMREPLY_SDATA)&mr->mrply_valid1;
+ }
+ else if (mr->mrply_valid1 == EFP_NO_ERROR) {
+
+ //
+ // Get the mirror disk status
+ //
+
+ pMreplySdata = (PMREPLY_SDATA)&mr->mrply_valid2;
+ }
+ else if (mr->mrply_valid1 <= mr->mrply_valid2) {
+
+ //
+ // Get the source disk status
+ //
+
+ pMreplySdata = (PMREPLY_SDATA)&mr->mrply_valid1;
+ }
+ else {
+
+ //
+ // Get the mirror disk status
+ //
+
+ pMreplySdata = (PMREPLY_SDATA)&mr->mrply_valid2;
+ }
+ break;
+ }
+
+ //
+ // Convert EFP error in SRB error.
+ //
+
+ switch(mr->mrply_status) {
+
+ case EFP_AUTOREC_OK:
+ case EFP_CMD_SUCC:
+
+ //
+ // Successful command.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ switch(pMreplySdata->Valid) {
+
+ case EFP_NO_ERROR:
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+
+ case EFP_COND_MET:
+
+ pSrb->ScsiStatus = SCSISTAT_CONDITION_MET;
+ break;
+
+ case EFP_INTER_GOOD:
+
+ pSrb->ScsiStatus = SCSISTAT_INTERMEDIATE;
+ break;
+
+ case EFP_INTER_COND:
+
+ pSrb->ScsiStatus =
+ SCSISTAT_INTERMEDIATE_COND_MET;
+ break;
+
+ default:
+
+ //
+ // The autonomous recovery procedure was
+ // successful and after the recovery the
+ // controller received a CHECK_CONDITION
+ // status (with ARS enabled) and a RECOVERED
+ // error as a reply to a REQUEST SENSE.
+ //
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+ }
+ break;
+
+
+ case EFP_DATA_RUN:
+
+ pSrb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ //
+ // If overrun error, log it.
+ // The underrun error can be very common on
+ // some devices (example: scanner).
+ //
+
+ if (pSrb->DataTransferLength <= mr->mrply_scsi_len) {
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ DeviceExtension->Adapter_ID[pSrb->PathId],
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ EFP_DATA_RUN
+ );
+ }
+
+ pSrb->DataTransferLength = mr->mrply_scsi_len;
+
+ break;
+
+
+ case EFP_AUTOREC_KO:
+ case EFP_WARN_ERR:
+
+ //
+ // Get the device info pointer.
+ //
+
+ TarLun = GET_QINDEX(pSrb->PathId,
+ pSrb->TargetId,
+ pSrb->Lun);
+
+ pDevInfo = &DeviceExtension->DevicesPresent[TarLun];
+
+ //
+ // Check if the source disk is for the first time
+ // off-line.
+ //
+
+ if (mr->mrply_off_attr == EFP_SOURCE_OFFLINE &&
+ (pDevInfo->SourceDiskState == EfpFtMemberHealthy ||
+ pDevInfo->SourceDiskState == EfpFtMemberMissing)) {
+
+ //
+ // Check if we need to log an error.
+ //
+
+ if (!pDevInfo->KnownError) {
+
+ //
+ // Remember it.
+ //
+
+ pDevInfo->KnownError = TRUE;
+
+ //
+ // Log the error
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ pSrb->TargetId,
+ pSrb->Lun,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (pDevInfo->SourceDiskState ==
+ EfpFtMemberHealthy ?
+ EFP_SOURCE_OFFLINE_ERROR :
+ EFP_MISSING_SOURCE_ERROR) |
+ mr->mrply_d_off
+ );
+
+ //
+ // Send an error message to the debug port
+ //
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Source disk %s,"
+ " Bus=%x, Tid=%x, Lun=%x,\n",
+ pDevInfo->SourceDiskState ==
+ EfpFtMemberHealthy ?
+ "off-line" : "missing",
+ pSrb->PathId, pSrb->TargetId, pSrb->Lun));
+
+ DebugPrint((1,
+ "Valid=%x, "
+ "Sense=%x, "
+ "Addit=%x, "
+ "Qualif=%x, "
+ "Info=%x.\n",
+ mr->mrply_valid1,
+ mr->mrply_sense1,
+ mr->mrply_addit1,
+ mr->mrply_qualif1,
+ mr->mrply_info1
+ ));
+ }
+
+ //
+ // This is the first time that the source disk
+ // is off-line. Update source state.
+ //
+
+ pDevInfo->SourceDiskState = EfpFtMemberDisabled;
+
+ #if EFP_RETURN_BUSY
+
+ //
+ // Return the general SCSI busy error code.
+ // The ScsiPort driver will retry the command.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+ pSrb->ScsiStatus = SCSISTAT_BUSY;
+
+ #else
+
+ //
+ // Return the SRB bus reset error code.
+ // The class driver will retry the command.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_BUS_RESET;
+
+ #endif
+
+ break;
+
+ } // end if (1st time source disk off line)
+
+ //
+ // Check if the mirror disk is for the first time
+ // off-line.
+ //
+
+ if (mr->mrply_off_attr == EFP_MIRROR_OFFLINE &&
+ (pDevInfo->MirrorDiskState == EfpFtMemberHealthy ||
+ pDevInfo->MirrorDiskState == EfpFtMemberMissing)) {
+
+ //
+ // Check if we need to log an error.
+ //
+
+ if (!pDevInfo->KnownError) {
+
+ //
+ // Remember it.
+ //
+
+ pDevInfo->KnownError = TRUE;
+
+ //
+ // Log the error
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ pSrb->TargetId,
+ pSrb->Lun,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (pDevInfo->MirrorDiskState ==
+ EfpFtMemberHealthy ?
+ EFP_MIRROR_OFFLINE_ERROR :
+ EFP_MISSING_MIRROR_ERROR) |
+ mr->mrply_d_off
+ );
+
+ //
+ // Send an error message to the debug port
+ //
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Mirror disk %s,"
+ " Bus=%x, Tid=%x, Lun=%x,\n",
+ pDevInfo->MirrorDiskState ==
+ EfpFtMemberHealthy ?
+ "off-line" : "missing",
+ D_OFF_TO_PATH(mr->mrply_d_off),
+ D_OFF_TO_TARGET(mr->mrply_d_off),
+ D_OFF_TO_LUN(mr->mrply_d_off)));
+
+ DebugPrint((1,
+ "Valid=%x, "
+ "Sense=%x, "
+ "Addit=%x, "
+ "Qualif=%x, "
+ "Info=%x.\n",
+ mr->mrply_valid2,
+ mr->mrply_sense2,
+ mr->mrply_addit2,
+ mr->mrply_qualif2,
+ mr->mrply_info2
+ ));
+ }
+
+ //
+ // This is the first time that the mirror disk
+ // is off-line. Update mirroring state.
+ //
+
+ pDevInfo->MirrorDiskState = EfpFtMemberDisabled;
+
+ #if EFP_RETURN_BUSY
+
+ //
+ // Return the general SCSI busy error code.
+ // The ScsiPort driver will retry the command.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+ pSrb->ScsiStatus = SCSISTAT_BUSY;
+
+ #else
+
+ //
+ // Return the SRB bus reset error code.
+ // The class driver will retry the command.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_BUS_RESET;
+
+ #endif
+
+ break;
+
+ } // end if (1st time mirror disk off line)
+
+ //
+ // Send an error message to the debug port
+ //
+
+ DebugPrint((2,
+ "OliEsc2Interrupt: EFP command status error,\n"
+ " Status=%x, Valid=%x.\n",
+ mr->mrply_status, pMreplySdata->Valid));
+
+ //
+ // SRB status error.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+
+ //
+ // SCSI status error.
+ //
+
+ switch(pMreplySdata->Valid) {
+
+ case EFP_DEV_BUSY:
+
+ pSrb->ScsiStatus = SCSISTAT_BUSY;
+ break;
+
+ case EFP_RESV_CONF:
+
+ pSrb->ScsiStatus =
+ SCSISTAT_RESERVATION_CONFLICT;
+ break;
+
+ case EFP_SENSE_INFO:
+ case EFP_SENSE_NO_INFO:
+
+ pSrb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ //
+ // Update the SRB sense data area
+ //
+
+ if (pSrb->SenseInfoBufferLength != 0 &&
+ !(pSrb->SrbFlags &
+ SRB_FLAGS_DISABLE_AUTOSENSE )) {
+
+ //
+ // Initialize the sense area to zero
+ //
+
+ for( Index=0;
+ Index < sizeof(SENSE_DATA);
+ Index++) {
+
+ *((PUCHAR)&Sdata + Index) = 0;
+ }
+
+ Sdata.ErrorCode =
+ pMreplySdata->Valid;
+
+ Sdata.SenseKey =
+ pMreplySdata->Sense;
+
+ Sdata.AdditionalSenseCode =
+ pMreplySdata->Addit;
+
+ Sdata.AdditionalSenseCodeQualifier =
+ pMreplySdata->Qualif;
+
+ Sdata.Information[3]=
+ (UCHAR)pMreplySdata->Info;
+
+ Sdata.Information[2]=
+ (UCHAR)(pMreplySdata->Info >> 8);
+
+ Sdata.Information[1]=
+ (UCHAR)(pMreplySdata->Info >> 16);
+
+ Sdata.Information[0]=
+ (UCHAR)(pMreplySdata->Info >> 24);
+
+ //
+ // Copy the sense data in the SRB
+ //
+
+ ScsiPortMoveMemory(
+ pSrb->SenseInfoBuffer,
+ &Sdata,
+ pSrb->SenseInfoBufferLength
+ );
+
+ //
+ // The sense data area is now ok to read
+ //
+
+ pSrb->SrbStatus |=
+ SRB_STATUS_AUTOSENSE_VALID;
+
+ //
+ // Send info to the debug port
+ //
+
+ DebugPrint((2,
+ "OliEsc2Interrupt: Sense data, "
+ "Valid=%x, "
+ "Sense=%x, "
+ "Addit=%x, "
+ "Qualif=%x, "
+ "Info=%x.\n",
+ pMreplySdata->Valid,
+ pMreplySdata->Sense,
+ pMreplySdata->Addit,
+ pMreplySdata->Qualif,
+ pMreplySdata->Info
+ ));
+
+ } // end if (sense data)
+
+ else {
+
+ //
+ // Send a warning message to debug port
+ //
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Warning, "
+ "sense data is lost.\n"));
+ }
+ break;
+
+ case EFP_NO_ERROR:
+
+ //
+ // Device status is related to autonomous
+ // recovery procedure of the controller.
+ // The real status of the device is unknown.
+ //
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+
+ default:
+
+ //
+ // Unknown error.
+ //
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Status=%x, Valid=%x ?.\n",
+ mr->mrply_status, pMreplySdata->Valid));
+
+ break;
+
+ }
+ break;
+
+
+ default:
+
+ //
+ // Unknown error.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Status=%x ?.\n",
+ mr->mrply_status));
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ DeviceExtension->Adapter_ID[pSrb->PathId],
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ mr->mrply_status
+ );
+
+ break;
+
+ } // end switch (reply status)
+
+ } // end if (mirroring reply)
+
+ // ---------------------------------------------------------------
+ //
+ // NORMAL/MAINTENANECE REPLY
+ //
+ // ---------------------------------------------------------------
+
+ else {
+
+#endif // EFP_MIRRORING_ENABLED
+
+
+ if (DeviceExtension->Q_Buf.qnrply.nrply_status == EFP_CMD_SUCC) {
+
+ //
+ // Successful command
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ switch(DeviceExtension->Q_Buf.qnrply.nrply_ex_stat) {
+
+ case EFP_NO_ERROR:
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+
+ case EFP_COND_MET:
+
+ pSrb->ScsiStatus = SCSISTAT_CONDITION_MET;
+ break;
+
+ case EFP_INTER_GOOD:
+
+ pSrb->ScsiStatus = SCSISTAT_INTERMEDIATE;
+ break;
+
+ case EFP_INTER_COND:
+
+ pSrb->ScsiStatus = SCSISTAT_INTERMEDIATE_COND_MET;
+ break;
+
+ default:
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Status=00, ExStat=%x ?.\n",
+ DeviceExtension->Q_Buf.qnrply.nrply_ex_stat));
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+
+ } // end switch
+ }
+
+ else if (DeviceExtension->Q_Buf.qnrply.nrply_status ==
+ EFP_AUTOREC_OK) {
+
+ //
+ // Successful command using the autonomous recovery procedure
+ // (ARP).
+ //
+ // Note that only the EFP-2 controller can return this type
+ // of error code.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ switch(DeviceExtension->Q_Buf.qnrply.nrply_ex_stat) {
+
+ case EFP_NO_ERROR:
+ case EFP_CHK_COND:
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+
+ default:
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Status=10, ExStat=%x ?.\n",
+ DeviceExtension->Q_Buf.qnrply.nrply_ex_stat));
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+
+ } // end switch
+ }
+
+ else if (DeviceExtension->Q_Buf.qnrply.nrply_status ==
+ EFP_WARN_ERR) {
+
+ //
+ // The request completed with an error
+ //
+
+ DebugPrint((2,
+ "OliEsc2Interrupt: EFP command status error,\n"
+ " Status=%x, ExStat=%x.\n",
+ DeviceExtension->Q_Buf.qnrply.nrply_status,
+ DeviceExtension->Q_Buf.qnrply.nrply_ex_stat));
+
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+
+ switch(DeviceExtension->Q_Buf.qnrply.nrply_ex_stat) {
+
+ case EFP_NO_ERROR:
+
+ //
+ // We have automatic request sense enabled,
+ // so the 00 in ex_stat together with status = 01
+ // will be interpreted here as a check condition
+ // returned in the sense key.
+ //
+
+ pSrb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ sensevalid = TRUE;
+
+ pSrb->DataTransferLength =
+ DeviceExtension->Q_Buf.qnrply.nrply_scsi_len;
+ break;
+
+ case EFP_CHK_COND:
+
+ // This should NEVER happen (because ARS enabled)
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Status=01, ExStat=30: w/ARS ?.\n"));
+
+ pSrb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+
+ pSrb->DataTransferLength =
+ DeviceExtension->Q_Buf.qnrply.nrply_scsi_len;
+ break;
+
+ case EFP_DEV_BUSY:
+
+ pSrb->ScsiStatus = SCSISTAT_BUSY;
+ break;
+
+ case EFP_RESV_CONF:
+
+ pSrb->ScsiStatus = SCSISTAT_RESERVATION_CONFLICT;
+ break;
+
+ case EFP_ABORT_CMD:
+
+ pSrb->ScsiStatus = SCSISTAT_COMMAND_TERMINATED;
+ break;
+
+ default:
+
+ //
+ // Unknown error.
+ //
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Status=01, ExStat=%x ?.\n",
+ DeviceExtension->Q_Buf.qnrply.nrply_ex_stat));
+
+ break;
+
+ } // end switch
+
+ //
+ // Check if we need to copy the sense data to the SRB.
+ //
+
+ if (pSrb->SenseInfoBufferLength != 0 &&
+ !(pSrb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) &&
+ sensevalid) {
+
+ //
+ // copy sense data information to the SRB SenseInfoBuffer
+ //
+
+ ScsiPortMoveMemory(pSrb->SenseInfoBuffer,
+ &DeviceExtension->Q_Buf.qnrply.nrply_sense,
+ pSrb->SenseInfoBufferLength);
+
+ pSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+
+ DebugPrint((2,
+ "SenseKey: %x, AdditCode: %x, AdditQual: %x.\n",
+ ((PSENSE_DATA)pSrb->SenseInfoBuffer)->SenseKey,
+ ((PSENSE_DATA)pSrb->SenseInfoBuffer)->AdditionalSenseCode,
+ ((PSENSE_DATA)
+ pSrb->SenseInfoBuffer)->AdditionalSenseCodeQualifier));
+
+ }
+ else if (sensevalid) {
+ DebugPrint((1,
+ "OliEsc2Interrupt: Warning, sense data is lost.\n"));
+ }
+ }
+
+ else if (DeviceExtension->Q_Buf.qnrply.nrply_status ==
+ EFP_AUTOREC_KO) {
+
+ //
+ // The request completed with an error,
+ // the autonomous recovery procedure (ARP) was not
+ // successful.
+ //
+ // Note that only the EFP-2 controller can return this type
+ // of error code.
+ //
+
+ DebugPrint((2,
+ "OliEsc2Interrupt: EFP command status error,\n"
+ " Status=%x, ExStat=%x.\n",
+ DeviceExtension->Q_Buf.qnrply.nrply_status,
+ DeviceExtension->Q_Buf.qnrply.nrply_ex_stat));
+
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+
+ switch(DeviceExtension->Q_Buf.qnrply.nrply_ex_stat) {
+
+ case EFP_NO_ERROR:
+
+ //
+ // Unknown cause.
+ //
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+
+ case EFP_CHK_COND:
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ break;
+
+ case EFP_DEV_BUSY:
+
+ pSrb->ScsiStatus = SCSISTAT_BUSY;
+ break;
+
+ case EFP_RESV_CONF:
+
+ pSrb->ScsiStatus = SCSISTAT_RESERVATION_CONFLICT;
+ break;
+
+ default:
+
+ //
+ // Unknown error.
+ //
+
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Status=18, ExStat=%x ?.\n",
+ DeviceExtension->Q_Buf.qnrply.nrply_ex_stat));
+
+ break;
+
+ } // end switch
+ }
+
+ else {
+
+ //
+ // The request completed with an error.
+ //
+
+ DebugPrint((2,
+ "OliEsc2Interrupt: EFP command status error,\n"
+ " Status=%x, ExStat=%x.\n",
+ DeviceExtension->Q_Buf.qnrply.nrply_status,
+ DeviceExtension->Q_Buf.qnrply.nrply_ex_stat));
+
+
+ // note that no sense data is returned for these cases.
+
+ switch (DeviceExtension->Q_Buf.qnrply.nrply_status) {
+
+ case EFP_SEL_TIMEOUT:
+
+ pSrb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case EFP_DATA_RUN:
+
+ pSrb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ //
+ // If overrun error, log it.
+ // The underrun error can be very common on
+ // some devices (example: scanner).
+ //
+
+ if (pSrb->DataTransferLength <=
+ DeviceExtension->Q_Buf.qnrply.nrply_scsi_len) {
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ DeviceExtension->Adapter_ID[pSrb->PathId],
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ EFP_DATA_RUN
+ );
+ }
+
+ pSrb->DataTransferLength =
+ DeviceExtension->Q_Buf.qnrply.nrply_scsi_len;
+
+ break;
+
+ case EFP_BUS_FREE:
+
+ pSrb->SrbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ break;
+
+ case EFP_PHASE_ERR:
+
+ pSrb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ break;
+
+ //
+ // NOTE: The following error codes are only returned
+ // by the ESC-2 controller.
+
+ case PARITY_ERROR:
+
+ //
+ // This is a severe error.
+ // The controller is now shut down.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_PARITY_ERROR;
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ DeviceExtension->Adapter_ID[pSrb->PathId],
+ 0,
+ SP_BUS_PARITY_ERROR,
+ 0
+ );
+
+ break;
+
+ case BUS_RESET_BY_TARGET:
+
+ //
+ // No error logging.
+ //
+ // Return bus reset error, because the bus has been
+ // reset.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_BUS_RESET;
+ break;
+
+ case PROTOCOL_ERROR:
+
+ //
+ // The ESC-2 resets the bus when it detects this
+ // type of error.
+ // Return bus reset error.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_BUS_RESET;
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ DeviceExtension->Adapter_ID[pSrb->PathId],
+ 0,
+ SP_PROTOCOL_ERROR,
+ 0
+ );
+
+ break;
+
+ case UNEXPECTED_PHASE_CHANGE:
+
+ //
+ // This is a severe error.
+ // The controller is now shut down.
+ //
+
+ case AUTO_REQUEST_SENSE_FAILURE:
+ case PARITY_ERROR_DURING_DATA_PHASE:
+
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ DeviceExtension->Adapter_ID[pSrb->PathId],
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ DeviceExtension->Q_Buf.qnrply.nrply_status
+ );
+
+ break;
+
+ default:
+
+ //
+ // Unknown error.
+ //
+
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+
+ DebugPrint((1,
+ "OliEsc2Interrupt: Status=%x ?.\n",
+ DeviceExtension->Q_Buf.qnrply.nrply_status));
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ pSrb->PathId,
+ DeviceExtension->Adapter_ID[pSrb->PathId],
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ DeviceExtension->Q_Buf.qnrply.nrply_status
+ );
+
+ break;
+
+ } // end switch
+ } // end status check
+
+#if EFP_MIRRORING_ENABLED
+
+ } // end if (!mirroring reply)
+
+#endif // EFP_MIRRORING_ENABLED
+
+
+ //
+ // Decrement the pending requests counter for this
+ // (targetId, LUN) pair
+ //
+
+ LuExtension = ScsiPortGetLogicalUnit(DeviceExtension,
+ pSrb->PathId,
+ pSrb->TargetId,
+ pSrb->Lun);
+
+ ASSERT(LuExtension);
+ LuExtension->NumberOfPendingRequests--;
+ ASSERT (LuExtension->NumberOfPendingRequests >= 0);
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete, (PVOID)DeviceExtension, pSrb);
+
+ } // end while {w/EFP command completion processing}
+
+ } // end if (command complete interrupt)
+
+ //
+ // Enable interrupts
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ INTERRUPTS_ENABLE);
+
+ return(TRUE);
+
+} // end OliEsc2Interrupt()
+
+
+BOOLEAN
+OliEsc2ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset ESC-2 SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension Device extension for this driver
+ PathId SCSI Bus path ID (always 0 for the ESC-2)
+
+Return Value:
+
+ TRUE if reset and re-initialization of EFP queues appears successful.
+ FALSE otherwise.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ PLU_EXTENSION LuExtension;
+ UCHAR Lun;
+ UCHAR TargetId;
+ UCHAR Bus;
+
+ DebugPrint((2,"OliEsc2ResetBus: Reset SCSI bus.\n"));
+
+ //
+ // Get the ESC-2 registers' base address
+ //
+
+ DeviceExtension = HwDeviceExtension;
+ eisaController = DeviceExtension->EisaController;
+
+ //
+ // If the reset is already in progress, return TRUE.
+ // This can only happen when this routine is called directly
+ // by the above layer (scsiport.sys) to reset bus #1 and #2.
+ //
+
+ if (DeviceExtension->ResetInProgress) {
+
+ DebugPrint((2,"OliEsc2ResetBus: The reset is already in progess.\n"));
+ return TRUE;
+ }
+
+ //
+ // Reset the controller.
+ //
+
+ OliEsc2ResetAdapter(DeviceExtension);
+
+ //
+ // a) complete all outstanding requests.
+ // b) clear pending request counters.
+ // c) send a "reset detected" notification.
+ //
+
+ for (Bus=0; Bus < DeviceExtension->NumberOfBuses; Bus++) {
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET
+ //
+
+ ScsiPortCompleteRequest(DeviceExtension,
+ Bus,
+ (UCHAR) ALL_TARGET_IDS,
+ (UCHAR) ALL_LUNS,
+ (UCHAR) SRB_STATUS_BUS_RESET);
+
+ //
+ // Reset to zero all the pending request counters
+ //
+
+ for (TargetId = 0; TargetId < 8; TargetId++) {
+ for (Lun = 0; Lun < 8; Lun++) {
+ LuExtension = ScsiPortGetLogicalUnit(DeviceExtension,
+ Bus,
+ TargetId,
+ Lun);
+
+ if (LuExtension != NULL) {
+ LuExtension->NumberOfPendingRequests = 0;
+ }
+ }
+ }
+
+ //
+ // Send a "reset detected" notification.
+ //
+
+ ScsiPortNotification(ResetDetected, DeviceExtension, Bus);
+
+ }
+
+ //
+ // All done
+ //
+
+ return TRUE;
+
+} // end OliEsc2ResetBus
+
+
+
+BOOLEAN
+ReadEsc2ConfigReg(
+ IN PEISA_CONTROLLER EisaController,
+ IN UCHAR ConfigReg,
+ OUT PUCHAR ConfigByteInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Reads one of the ESC-2's 8-bit configuration registers, returning the
+ information stored there. Should be called at system initialization
+ time only, as it uses polling.
+
+Arguments:
+
+ EisaController Pointer to the adapter-info structure for this driver
+ ConfigReg configuration register to be read (eg. 2 = IRQ config)
+ ConfigByteInfo the information obtained from the configuration register
+
+Return Value:
+
+ TRUE Success (and returns the configuration byte in ConfigByteInfo)
+ FALSE Failure
+
+--*/
+
+{
+
+ BOOLEAN Success = FALSE; // Return value
+ UCHAR IntMask; // Current System Doorbell interrupt mask value
+ ULONG i; // Auxiliary variable
+ BOOLEAN GotInt = FALSE;
+
+ //
+ // Get the current System Doorbell Interrupt Mask
+ //
+ // KMK: We never used to do this (and the re-write of the mask at end)
+ //
+
+ IntMask = ScsiPortReadPortUchar(&EisaController->SystemDoorBellMask);
+
+ //
+ // Disable ESC-1 interrupts
+ //
+ // KMK: We used to use STI_CLI(), to let pending interrupts occur
+ //
+
+ ScsiPortWritePortUchar(&EisaController->SystemDoorBellMask,
+ INTERRUPTS_DISABLE);
+
+ //
+ // Gain semaphore 0
+ //
+
+ if (!GainSemaphore0(EisaController)) {
+ // KMK re-enable interrupts
+ Success = FALSE;
+ } else { // successfully gained semaphore
+
+ ScsiPortWritePortUchar(&EisaController->InTypeService, 0);
+ ScsiPortWritePortUchar(&EisaController->InParm1, GET_CONF_INFO);
+ ScsiPortWritePortUchar(&EisaController->InParm2, ConfigReg);
+
+ //ScsiPortWritePortUlong(&EisaController->InAddress, Address);
+
+ //
+ // Send an attention interrupt to the adapter.
+ //
+
+ ScsiPortWritePortUchar(&EisaController->LocalDoorBell, ESC_INT_BIT);
+
+ //
+ // We would re-enable interrupts here.
+ //
+ //ENAB();
+
+ // now loop, waiting for the board to "interrupt" us (we don't yet
+ // have an interrupt line set, so we will poll).
+ // KMK: Note, this is shorter than the wait we used to use!
+
+ for (i = 0; i < WAIT_INT_LOOPS && !GotInt; i++) {
+ if (ScsiPortReadPortUchar(&EisaController->SystemDoorBell) &
+ ESC_INT_BIT) { // was ESC_INTERRUPT
+ GotInt = TRUE;
+ }
+ else {
+ ScsiPortStallExecution(WAIT_INT_INTERVAL);
+ }
+ }
+
+ if (!GotInt) {
+ // Re-enable the interrupts here.
+ DebugPrint((1,
+ "No HP interrupt after read config byte attempt.\n"));
+ Success = FALSE;
+ } else { // did get the interrupt
+
+ //
+ // acknowledge the host interrupt, resetting the interrupt register
+ // (was ESC_ACK)
+ //
+
+ ScsiPortWritePortUchar(&EisaController->SystemDoorBell,
+ ESC_INT_BIT);
+
+ //
+ // read the mailbox registers. If the outgoing status was good,
+ // we read the value of the configuration register we queried.
+ //
+
+ if (ScsiPortReadPortUshort((PUSHORT)&EisaController->OutReserved2)
+ != 0) {
+ Success = FALSE;
+ } else {
+
+ Success = TRUE;
+
+ *ConfigByteInfo =
+ ScsiPortReadPortUchar(&EisaController->OutReserved4);
+
+ // reset outgoing semaphore 1
+ ScsiPortWritePortUchar(&EisaController->ResultSemaphore, 0);
+
+ } // end of else {successful status from read conf reg command}
+
+ } // end of else {did get the interrupt}
+
+ } // end of else {successfully gained the semaphore}
+
+ //
+ // Restore the original interrupt mask
+ //
+
+ ScsiPortWritePortUchar(&EisaController->SystemDoorBellMask, IntMask);
+
+ return(Success); // if an error occurred, Success holds FALSE
+
+} // end ReadEsc2ConfigReg
+
+
+
+BOOLEAN
+OliEsc2IrqRegToIrql(
+ IN UCHAR IrqReg,
+ OUT PUCHAR pIrql
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts the IRQ configuration register value in
+ the corrisponding IRQ level.
+
+Arguments:
+
+ IrqReg IRQ configuration register value.
+ pIrql Location where to store the IRQ level.
+
+Return Value:
+
+ TRUE Success
+ FALSE Failure (IRQ config reg was invalid)
+
+--*/
+
+{
+ BOOLEAN Success = TRUE;
+
+ switch(IrqReg) {
+
+ case 0: *pIrql = 11;
+ break;
+
+ case 1: *pIrql = 10;
+ break;
+
+ case 2: *pIrql = 5;
+ break;
+
+ case 3: *pIrql = 15;
+ break;
+
+ default: Success = FALSE;
+ break;
+
+ }
+
+ return Success;
+
+} // end of OliEsc2IrqRegToIrql
+
+
+
+BOOLEAN
+RegisterEfpQueues(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+
+ This routine re-initializes the EFP interface, setting up the
+ queues descriptor, plus the mailbox queue and device queues.
+ It assumes that information on the attached SCSI devices has
+ already been obtained by the Get Configuration call, and is
+ stored in the Noncached Extension.
+
+Arguments:
+
+ DeviceExtension Pointer to the device extension for this driver.
+
+Return Value:
+
+ Returns TRUE if queues initialization completed successfully.
+ Returns FALSE and logs an error if initialization fails.
+
+--*/
+
+{
+ PEISA_CONTROLLER eisaController;
+ PNONCACHED_EXTENSION pNoncachedExt;
+ UCHAR TarLun, EfpMsg;
+ ULONG i, length;
+ BOOLEAN GotInt = FALSE;
+ PGET_CONF Info;
+ PCOMMAND_QUEUE qPtr;
+
+ eisaController = DeviceExtension->EisaController;
+ pNoncachedExt = DeviceExtension->NoncachedExt;
+
+ //
+ // With the information obtained from Get Information and
+ // Get Configuration, build a new queues descriptor, including
+ // device command queues. Allocate queues for all devices, but
+ // fill in Get Configuration device information only into device
+ // command queue descriptor bodies for existing devices.
+ //
+
+ //
+ // Interrupts have already been disabled on entry (see OliEsc2FindAdapter).
+ // Polling is possible through enabling the ESC-1 HP and EFP interface
+ // in the System Doorbell Mask.
+ //
+
+ //
+ // 1. Issue EFP_SET command via I/O instruction 'TYPE SERVICE' to the
+ // BMIC mailbox registers.
+ //
+
+ //
+ // Issue EFP_Set command to register new Queues Descriptor.
+ //
+
+ if (!GainSemaphore0(eisaController)) {
+ return(FALSE);
+ }
+
+ // if got the semaphore, place IRQ parameter in mailbox register 1
+ ScsiPortWritePortUchar(&eisaController->InParm1,
+ DeviceExtension->IRQ_In_Use);
+
+ // output a TYPE SERVICE request: 'efp_set'
+ ScsiPortWritePortUchar(&eisaController->InTypeService, S_EFP_SET);
+
+ // set bit 1 of the local doorbell register to generate interrupt request
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ // Wait for controller to respond.
+ GotInt = FALSE; // re-initialize GotInt
+ for (i = 0; i < WAIT_INT_LOOPS && !GotInt; i++) {
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell)
+ & EFP_TYPE_MSG) {
+ GotInt = TRUE;
+ }
+ else {
+ ScsiPortStallExecution(WAIT_INT_INTERVAL);
+ }
+ }
+
+ if (!GotInt) {
+ DebugPrint((1, "RegisterEfpQueues: No interrupt after EFP_SET.\n"));
+ return(FALSE);
+ }
+ else {
+ DebugPrint((4,
+ "RegisterEfpQueues: Set, interrupt after %ld us.\n",
+ i*WAIT_INT_INTERVAL));
+
+ EfpMsg = ScsiPortReadPortUchar(&eisaController->OutTypeMsg);
+ if (EfpMsg != M_INIT_DIAG_OK) {
+ DebugPrint((1,
+ "RegisterEfpQueues: INIT_DIAG_OK not received after EFP_SET.\n"));
+ if (EfpMsg == M_ERR_INIT) {
+ DebugPrint((1,
+ "RegisterEfpQueues: M_ERR_INIT received after EFP_SET.\n"));
+ }
+ else {
+ DebugPrint((1,
+ "RegisterEfpQueues: Error after EFP_SET: %x hex.\n",
+ EfpMsg));
+ }
+ return(FALSE);
+ }
+ }
+
+ // reset bit 1 of the system doorbell register to clear request
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_MSG);
+
+ // clear semaphore 1 after reading TYPE_MSG (RELEASE_SEM1)
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, 0);
+
+
+ //
+ // 2. Build queues descriptor.
+ //
+
+ //
+ // First, reinitialize queue-related fields in HW_DEVICE_EXTENSION
+ // and NONCACHED_EXTENSION.
+ //
+
+ DeviceExtension->Reply_Q_Full_Flag = 0;
+ DeviceExtension->Reply_Q_Get = 0;
+ DeviceExtension->RQ_In_Process = 0;
+ pNoncachedExt->Command_Qs[0].Cmd_Q_Get = 0;
+ pNoncachedExt->Command_Qs[0].Cmd_Q_Put = 0;
+
+ for (i = 0; i < HA_QUEUES; i++) { // device q's + mailbox q
+ DeviceExtension->Q_Full_Map[i] = 0;
+ }
+
+ for (i = 0; i < REPLY_Q_ENTRIES; i++) {
+ pNoncachedExt->Reply_Q[i].qnrply.nrply_flag = 0;
+ }
+
+ // Set up new queues descriptor header
+
+ // set up Queues Descriptor header
+
+ pNoncachedExt->QD_Head.qdh_maint = 0; // normal environment
+ pNoncachedExt->QD_Head.qdh_n_cmd_q =
+ (DeviceExtension->TotalAttachedDevices + 1);
+ pNoncachedExt->QD_Head.qdh_type_reply = 0; // int after 1+
+ pNoncachedExt->QD_Head.qdh_reserved1 = 0;
+ pNoncachedExt->QD_Head.qdh_reply_q_addr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL, // No SRB
+ &pNoncachedExt->Reply_Q,
+ &length));
+ pNoncachedExt->QD_Head.qdh_n_ent_reply = REPLY_Q_ENTRIES;
+ pNoncachedExt->QD_Head.qdh_reserved2 = 0;
+
+ // set up Queues Descriptor body for mailbox queue
+
+ pNoncachedExt->QD_Bodies[0].qdb_scsi_level = 0xFF;
+ pNoncachedExt->QD_Bodies[0].qdb_channel = 0xFF;
+ pNoncachedExt->QD_Bodies[0].qdb_ID = 0xFF;
+ pNoncachedExt->QD_Bodies[0].qdb_LUN = 0xFF;
+ pNoncachedExt->QD_Bodies[0].qdb_n_entry_cmd = COMMAND_Q_ENTRIES;
+ pNoncachedExt->QD_Bodies[0].qdb_notfull_int = 1;
+ pNoncachedExt->QD_Bodies[0].qdb_no_ars = 0; // ESC2/EFP2
+ pNoncachedExt->QD_Bodies[0].qdb_timeout = 0;
+ pNoncachedExt->QD_Bodies[0].qdb_cmd_q_addr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL, // no SRB
+ &pNoncachedExt->Command_Qs[0],
+ &length));
+ pNoncachedExt->QD_Bodies[0].qdb_reserved = 0;
+
+ // store the controller mailbox info in common area
+
+ DeviceExtension->DevicesPresent[0].present = TRUE;
+ DeviceExtension->DevicesPresent[0].qnumber = 0;
+ DeviceExtension->DevicesPresent[0].qPtr = &pNoncachedExt->Command_Qs[0];
+
+
+ // set up Queues Descriptor bodies for device queues
+
+ //
+ // Note that there will be garbage in QD_Bodies entries for non-existant
+ // TarLuns. We must, then, always check if a device/queue exists before
+ // trying to send a command to it.
+ //
+
+ for (i = 1; i <= DeviceExtension->TotalAttachedDevices; i++) {
+
+ Info = &pNoncachedExt->GetConfigInfo[i-1] ;
+
+ DebugPrint((1, "RegisterEfpQueues: channel=%d id=%d lun=%d.\n",
+ Info->gc_channel - 1,
+ Info->gc_id,
+ Info->gc_lun));
+
+ TarLun = GET_QINDEX(((Info->gc_channel)-1), Info->gc_id, Info->gc_lun);
+
+ qPtr = &pNoncachedExt->Command_Qs[i];
+
+ DeviceExtension->DevicesPresent[TarLun].present = TRUE;
+ DeviceExtension->DevicesPresent[TarLun].qnumber = (UCHAR)i;
+ DeviceExtension->DevicesPresent[TarLun].qPtr = qPtr ;
+
+ pNoncachedExt->QD_Bodies[i].qdb_scsi_level = Info->gc_scsi_level;
+
+ // Note: Discussed this with John Hanel. We believe it is unnecessary
+ // to ensure that the device's reported SCSI protocol level does not
+ // exceed the controller's level. If otherwise, change this code.
+
+ pNoncachedExt->QD_Bodies[i].qdb_channel = Info->gc_channel;
+ pNoncachedExt->QD_Bodies[i].qdb_ID = Info->gc_id;
+ pNoncachedExt->QD_Bodies[i].qdb_LUN = Info->gc_lun;
+
+ pNoncachedExt->QD_Bodies[i].qdb_n_entry_cmd = COMMAND_Q_ENTRIES;
+ pNoncachedExt->QD_Bodies[i].qdb_notfull_int = 1;
+ pNoncachedExt->QD_Bodies[i].qdb_no_ars = 0;
+ pNoncachedExt->QD_Bodies[i].qdb_timeout = 0;
+ pNoncachedExt->QD_Bodies[i].qdb_cmd_q_addr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL, // no SRB
+ qPtr,
+ &length));
+ pNoncachedExt->QD_Bodies[i].qdb_reserved = 0;
+
+ qPtr->Cmd_Q_Get = 0;
+ qPtr->Cmd_Q_Put = 0;
+
+ }
+
+
+ //
+ // 3. Issue EFP_Start.
+ //
+
+ if (!GainSemaphore0(eisaController)) {
+ return(FALSE);
+ }
+
+ // if got the semaphore, output physical address of the queues descriptor
+ // to mailbox registers 1 - 4.
+ ScsiPortWritePortUlong((PULONG)&eisaController->InParm1,
+ DeviceExtension->QueuesDescriptor_PA);
+
+ // output a TYPE SERVICE request to 'efp_start'
+ ScsiPortWritePortUchar(&eisaController->InTypeService, S_EFP_START);
+
+ // set bit 1 of local doorbell register to generate an interrupt request
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ // Wait for controller to respond.
+ GotInt = FALSE; // re-initialize GotInt
+ for (i = 0; i < WAIT_INT_LOOPS && !GotInt; i++) {
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ EFP_TYPE_MSG) { // was EFP_MSG_INT()
+ GotInt = TRUE;
+ }
+ else {
+ ScsiPortStallExecution(WAIT_INT_INTERVAL);
+ }
+ }
+
+ if (!GotInt) {
+ DebugPrint((1,
+ "RegisterEfpQueues: No interrupt after EFP_START.\n"));
+ return(FALSE);
+ }
+ else {
+ DebugPrint((4,
+ "RegisterEfpQueues: Start, interrupt after %ld us.\n",
+ i*WAIT_INT_INTERVAL));
+
+ EfpMsg = ScsiPortReadPortUchar(&eisaController->OutTypeMsg);
+ if (EfpMsg != M_INIT_DIAG_OK) {
+ DebugPrint((1,
+ "RegisterEfpQueues: INIT_DIAG_OK not received after EFP_START.\n"));
+ if (EfpMsg == M_ERR_INIT) {
+ DebugPrint((1,
+ "RegisterEfpQueues: M_ERR_INIT received after EFP_START.\n"));
+ }
+ else {
+ DebugPrint((1,
+ "RegisterEfpQueues: Error after EFP_START: %x hex.\n",
+ EfpMsg));
+ }
+ return(FALSE);
+ }
+ }
+
+ // reset bit 1 of the system doorbell register to clear request
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_MSG);
+
+ // clear semaphore 1 after reading TYPE_MSG (RELEASE_SEM1)
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, 0); // release sem
+
+ return(TRUE);
+
+} // end of RegisterEfpQueues()
+
+
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list for the EFP
+ command structure (SSG or ESG).
+
+Arguments:
+
+ DeviceExtension Pointer to the device extension for this driver.
+ Srb Pointer to the Scsi Request Block to service
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG bytesLeft; // # of bytes left to be described
+ // in an SGL
+ PEFP_SGL pEFP; // EFP command pointer
+ PQ_ENTRY pCQCmd; // EFP command queue structure
+
+ PVOID dataPointer; // Pointer to the data buffer to send
+ USHORT descriptorCount; // # of scatter/gather descriptors
+ // built
+ ULONG length; // Length of contiguous memory in the
+ // data buffer, starting at a given
+ // offset
+ ULONG physicalAddress; // Physical address of the data buffer
+ ULONG physicalSgl; // Physical SGL address
+ PSG_LIST sgl; // Virtual SGL address
+
+
+ DebugPrint((3,"OliEsc2BuildSgl: Enter routine.\n"));
+
+ //
+ // Initialize some variables
+ //
+
+ dataPointer = Srb->DataBuffer;
+ bytesLeft = Srb->DataTransferLength;
+ pEFP = Srb->SrbExtension;
+ pCQCmd = &pEFP->EfpCmd;
+ sgl = &pEFP->Sgl;
+ descriptorCount = 0;
+
+ //
+ // Get physical SGL address.
+ //
+
+ physicalSgl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL,
+ sgl,
+ &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SGL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SGL));
+
+ //
+ // Create SGL segment descriptors.
+ //
+
+ do {
+
+ DebugPrint((3, "OliEsc2BuildSgl: Data buffer %lx.\n", dataPointer));
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "OliEsc2BuildSgl: Physical address %lx,\n",
+ physicalAddress));
+ DebugPrint((3, "OliEsc2BuildSgl: Data length %lx,\n", length));
+ DebugPrint((3, "OliEsc2BuildSgl: Bytes left %lx.\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ sgl->Descriptor[descriptorCount].Address = physicalAddress;
+ sgl->Descriptor[descriptorCount].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ // Save the descriptor count in the EFP structure for performance tuning
+
+ pEFP->SGCount = descriptorCount;
+
+ DebugPrint((3, "OliEsc2BuildSgl: SGCount = >>>>>> %d.\n",
+ descriptorCount));
+
+ //
+ // The short/long scatter gather commands are not used because...
+ // a) These commands can be used only for disk devices
+ // (ESC-2 supports all SCSI devices).
+ // b) The miniport need to make some assumtions on the device block
+ // length (the miniport doesn't have enough knowledge to make them).
+ //
+
+ DebugPrint((3,"OliEsc2BuildSgl: Send << ESG >> command.\n"));
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ //
+ // Adapter to system transfer
+ //
+ ((PEXTENDED_SG)pCQCmd)->esg_cmd_type = ESG_WRITE;
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ //
+ // System to adapter transfer
+ //
+
+ ((PEXTENDED_SG)pCQCmd)->esg_cmd_type = ESG_READ;
+
+ }
+
+ //
+ // Copy the Command Descriptor Block (CDB) into the EFP command
+ //
+
+ ScsiPortMoveMemory(&pCQCmd->qncmd.ncmd_cdb, Srb->Cdb, Srb->CdbLength);
+
+ //
+ // Write SGL length to Short Scatter Gather command.
+ //
+
+ ((PEXTENDED_SG)pCQCmd)->esg_cdb_l = Srb->CdbLength;
+ ((PEXTENDED_SG)pCQCmd)->esg_lb = descriptorCount * sizeof(SG_DESCRIPTOR);
+
+ DebugPrint((3,"OliEsc2BuildSgl: SGL length is %d.\n",
+ descriptorCount * sizeof(SG_DESCRIPTOR) ));
+
+ //
+ // Write SGL address to EFP structure.
+ //
+
+ ((PEXTENDED_SG)pCQCmd)->esg_address = physicalSgl;
+
+ DebugPrint((3,"OliEsc2BuildSgl: SGL address is %lx\n", sgl));
+
+ return;
+
+} // end BuildSgl()
+
+
+
+VOID
+OliEsc2ResetAdapter(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ The routine resets the SCSI controller.
+
+Arguments:
+
+ Context Device adapter context pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ PNONCACHED_EXTENSION pNoncachedExt;
+ UCHAR intpending;
+ UCHAR EfpMsg;
+ ULONG Delay;
+ ULONG i;
+ BOOLEAN Error = FALSE;
+ UCHAR Bus;
+
+ DeviceExtension = Context;
+ eisaController = DeviceExtension->EisaController;
+ pNoncachedExt = DeviceExtension->NoncachedExt;
+
+ //
+ // The routine releases the control of the CPU while waiting for some
+ // status/interrupt, this is required because the reset/re-initialization
+ // of the controller can take several seconds.
+ //
+ // Reset Controller:
+ //
+ // Phase 0: Reset the controller.
+ // Phase 1: Waiting for the controller to complete its initialization.
+ // Phase 2: Small delay.
+ //
+ // Re-register EFP queues:
+ //
+ // Phase 3: Waiting for the EFP_SET command to complete.
+ // Phase 4: Waiting for the EFP_START command to complete.
+ //
+
+ switch(DeviceExtension->ResetInProgress) {
+
+ //
+ // Phase 0: Reset the controller.
+ //
+
+ case 0:
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Disable interrupts.
+ //
+
+ ScsiPortWritePortUchar( &eisaController->SystemIntEnable,
+ INTERRUPTS_DISABLE );
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Reset controller.
+ //
+
+ if (DeviceExtension->Esc2 == TRUE) {
+
+ DebugPrint((2,"OliEsc2ResetAdapter: ESC reset type.\n"));
+
+ DebugPrint((3, "OliEsc2ResetAdapter: "
+ "Phase 1 (reset adapter) max time = %ld us.\n",
+ ESC_RESET_DELAY + ESC_RESET_INTERVAL * ESC_RESET_LOOPS
+ ));
+
+ //
+ // Initialize the output location to a known value.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->OutReserved2,
+ (UCHAR)(~DIAGNOSTICS_OK_NO_CONFIG_RECEIVED));
+
+ //
+ // Reset ESC-2 and SCSI bus.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell,
+ ADAPTER_RESET);
+
+ //
+ // Request a timer call to complete the reset.
+ //
+
+ DeviceExtension->ResetTimerCalls = ESC_RESET_LOOPS + 1;
+ Delay = ESC_RESET_DELAY;
+ }
+ else {
+
+ DebugPrint((2,"OliEsc2ResetAdapter: EFP reset type.\n"));
+
+ DebugPrint((3, "OliEsc2ResetAdapter: "
+ "Phase 1 (reset adapter) max time = %ld us.\n",
+ EFP_RESET_DELAY + EFP_RESET_INTERVAL * EFP_RESET_LOOPS
+ ));
+
+ //
+ // Try to acquire the semaphore (note that this is not necessary).
+ //
+
+ if (!GainSemaphore0(eisaController)) {
+ DebugPrint((1,
+ "OliEsc2ResetAdapter: Warning, the semaphore is busy, "
+ "issuing the reset anyway.\n"));
+ }
+
+ //
+ // Initialize the input parameters for the reset.
+ //
+
+ for (i=0; i < CFG_REGS_NUMBER; i++) {
+
+ //
+ // The controller will re-initialize the board using
+ // these configuration registers values.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->InTypeService + i,
+ DeviceExtension->CfgRegs[i]);
+ }
+
+ //
+ // Reset EFP-2 and SCSI buses.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell,
+ ADAPTER_CFG_RESET);
+
+ //
+ // Request a timer call to complete the reset.
+ //
+
+ DeviceExtension->ResetTimerCalls = EFP_RESET_LOOPS + 1;
+ Delay = EFP_RESET_DELAY;
+ }
+
+ //
+ // The "ResetNotification" variable is used to keep track of the
+ // time during the reset. If the reset is not completed before
+ // the next ESC2_RESET_NOTIFICATION usec. unit, we call the
+ // "ScsiPortNotification(ResetDetected...)" routine.
+ // After the call the ScsiPort stops the delivery of SRBs for a
+ // little bit (~4 sec.).
+ //
+
+ DeviceExtension->ResetNotification = 0;
+ DeviceExtension->ResetInProgress++;
+ break;
+
+
+ //
+ // Phase 1: Waiting for the controller to complete its initialization.
+ //
+
+ case 1:
+
+ if (DeviceExtension->Esc2 == TRUE) {
+
+ //
+ // Note that after a reset the LOW byte of the ESC-2 Status
+ // register is loaded with the diagnostics result code.
+ //
+
+ if (ScsiPortReadPortUchar(&eisaController->OutReserved2) !=
+ DIAGNOSTICS_OK_NO_CONFIG_RECEIVED) {
+
+ Delay = ESC_RESET_INTERVAL;
+ break;
+ }
+
+ DebugPrint((1,
+ "OliEsc2ResetAdapter: Reset bus succeeded after %ld us.\n",
+ ESC_RESET_DELAY + ESC_RESET_INTERVAL *
+ (ESC_RESET_LOOPS - DeviceExtension->ResetTimerCalls)
+ ));
+ }
+ else {
+
+ //
+ // The following code allows the next revision of the EFP firmware
+ // to use more time during the reset phase.
+ //
+
+ if (ScsiPortReadPortUchar(&eisaController->LocalDoorBell) &
+ ADAPTER_CFG_RESET) {
+
+ Delay = EFP_RESET_INTERVAL;
+ break;
+ }
+
+ DebugPrint((1,
+ "OliEsc2ResetAdapter: Reset bus succeeded after %ld us.\n",
+ EFP_RESET_DELAY + EFP_RESET_INTERVAL *
+ (EFP_RESET_LOOPS - DeviceExtension->ResetTimerCalls)
+ ));
+ }
+
+ //
+ // The following delay is necessary because the adapter,
+ // immediately after a reset, is insensitive to interrupts through
+ // the Local Doorbell Register for almost 50ms. This shouldn't be
+ // and needs to be investigated further (ESC-2 controllers).
+ //
+
+ DeviceExtension->ResetTimerCalls = 1;
+ Delay = POST_RESET_DELAY;
+ DeviceExtension->ResetInProgress++;
+ break;
+
+ //
+ // Phase 2: Small delay.
+ //
+
+ case 2:
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Remove any interrupt that was pending before issuing the reset.
+ // The controller doesn't reset these interrupts.
+ //
+
+ intpending = ScsiPortReadPortUchar(&eisaController->SystemDoorBell);
+
+ //
+ // Check if any ESC-1 type interrupt
+ //
+
+ if (intpending & ESC_INT_BIT) {
+
+ DebugPrint((3, "OliEsc2ResetAdapter: "
+ "The HP interrupt was pending.\n"));
+
+ //
+ // Acknowledge the interrupt.
+ //
+ // No need to unlock semaphore 1, because the controller already
+ // unlocks it during the reset phase.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ ESC_INT_BIT);
+ }
+
+ //
+ // Check if any EFP command complete interrupt
+ //
+
+ if (intpending & EFP_CMD_COMPL) {
+
+ DebugPrint((3, "OliEsc2ResetAdapter: "
+ "The EFP command complete interrupt was pending.\n"));
+
+ //
+ // Acknowledge interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ EFP_ACK_INT);
+ }
+
+ //
+ // Check if any EFP_TYPE_MSG interrupt
+ //
+
+ if (intpending & EFP_TYPE_MSG) {
+
+ DebugPrint((3, "OliEsc2ResetAdapter: "
+ "The EFP type message interrupt was pending.\n"));
+
+ //
+ // Acknowledge the interrupt
+ //
+ // No need to unlock semaphore 1, because the controller already
+ // unlocks it during the reset phase.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell,
+ EFP_ACK_MSG);
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Re-initialize the EFP queues, using information stored
+ // from the init-time.
+ //
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Issue EFP_SET command via I/O instruction 'TYPE SERVICE' to the
+ // BMIC mailbox registers.
+ //
+
+ DebugPrint((3, "OliEsc2ResetAdapter: "
+ "Phase 3 (EFP_SET command) max time = %ld us.\n",
+ TIMER_WAIT_INT_INTERVAL * TIMER_WAIT_INT_LOOPS
+ ));
+
+ if (!GainSemaphore0(eisaController)) {
+
+ Error = TRUE;
+ break;
+ }
+
+ //
+ // Place IRQ parameter in mailbox register 1.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->InParm1,
+ DeviceExtension->IRQ_In_Use);
+
+ //
+ // output a TYPE SERVICE request: 'efp_set'.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->InTypeService, S_EFP_SET);
+
+ //
+ // set bit 1 of the local doorbell register to generate interrupt
+ // request.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ //
+ // Request a timer call to continue the re-initialization phase.
+ //
+
+ DeviceExtension->ResetTimerCalls = TIMER_WAIT_INT_LOOPS;
+ Delay = TIMER_WAIT_INT_INTERVAL;
+ DeviceExtension->ResetInProgress++;
+ break;
+
+ //
+ // Phase 3: Waiting for the EFP_SET command to complete.
+ //
+
+ case 3:
+
+ //
+ // Check if a message interrupt is pending.
+ //
+
+ intpending = ScsiPortReadPortUchar(&eisaController->SystemDoorBell);
+
+ if ( !(intpending & EFP_TYPE_MSG)) {
+
+ Delay = TIMER_WAIT_INT_INTERVAL;
+ break;
+ }
+
+ //
+ // Check the command result.
+ //
+
+ EfpMsg = ScsiPortReadPortUchar(&eisaController->OutTypeMsg);
+
+ if (EfpMsg != M_INIT_DIAG_OK) {
+
+ DebugPrint((1,
+ "OliEsc2ResetAdapter: Error after EFP_SET: %x hex.\n",
+ EfpMsg));
+
+ Error = TRUE;
+ break;
+ }
+
+ //
+ // reset bit 1 of the system doorbell register to clear request
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_MSG);
+
+ //
+ // clear semaphore 1 after reading TYPE_MSG (RELEASE_SEM1)
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, 0);
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Reinitialize the reply queue and the associated variables.
+ //
+
+ for (i = 0; i < REPLY_Q_ENTRIES; i++) {
+ pNoncachedExt->Reply_Q[i].qnrply.nrply_flag = 0;
+ }
+
+ DeviceExtension->Reply_Q_Full_Flag = 0;
+ DeviceExtension->Reply_Q_Get = 0;
+ DeviceExtension->RQ_In_Process = 0;
+
+ //
+ // Reinitialize the command queues and the associated structures.
+ //
+
+ for (i = 0; i <= DeviceExtension->TotalAttachedDevices; i++) {
+ pNoncachedExt->Command_Qs[i].Cmd_Q_Get = 0;
+ pNoncachedExt->Command_Qs[i].Cmd_Q_Put = 0;
+ }
+
+ for (i = 0; i < HA_QUEUES; i++) { // device q's + mailbox q
+ DeviceExtension->Q_Full_Map[i] = 0;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Issue EFP_Start.
+ //
+
+ DebugPrint((3, "OliEsc2ResetAdapter: "
+ "Phase 4 (EFP_START command) max time = %ld us.\n",
+ TIMER_WAIT_INT_INTERVAL * TIMER_WAIT_INT_LOOPS
+ ));
+
+ if (!GainSemaphore0(eisaController)) {
+
+ Error = TRUE;
+ break;
+ }
+
+ //
+ // Output physical address of the queues descriptor
+ // to mailbox registers 1 - 4.
+ //
+
+ ScsiPortWritePortUlong((PULONG)&eisaController->InParm1,
+ DeviceExtension->QueuesDescriptor_PA);
+
+ //
+ // output a TYPE SERVICE request to 'efp_start'
+ //
+
+ ScsiPortWritePortUchar(&eisaController->InTypeService, S_EFP_START);
+
+ //
+ // set bit 1 of local doorbell register to generate an interrupt
+ // request.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ //
+ // Request a timer call to continue the re-initialization phase.
+ //
+
+ DeviceExtension->ResetTimerCalls = TIMER_WAIT_INT_LOOPS;
+ Delay = TIMER_WAIT_INT_INTERVAL;
+ DeviceExtension->ResetInProgress++;
+ break;
+
+ //
+ // Phase 4: Waiting for the EFP_START command to complete.
+ //
+
+ case 4:
+
+ //
+ // Check if a message interrupt is pending.
+ //
+
+ intpending = ScsiPortReadPortUchar(&eisaController->SystemDoorBell);
+
+ if ( !(intpending & EFP_TYPE_MSG)) {
+
+ Delay = TIMER_WAIT_INT_INTERVAL;
+ break;
+ }
+
+ //
+ // Check the command result.
+ //
+
+ EfpMsg = ScsiPortReadPortUchar(&eisaController->OutTypeMsg);
+
+ if (EfpMsg != M_INIT_DIAG_OK) {
+
+ DebugPrint((1,
+ "OliEsc2ResetAdapter: Error after EFP_START: %x hex.\n",
+ EfpMsg));
+
+ Error = TRUE;
+ break;
+ }
+
+ //
+ // reset bit 1 of the system doorbell register to clear request
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_MSG);
+
+ //
+ // clear semaphore 1 after reading TYPE_MSG (RELEASE_SEM1)
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResultSemaphore, 0);
+
+#if EFP_MIRRORING_ENABLED
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // We need to re-initialize all the mirroring structures.
+ //
+
+ OliEsc2MirrorInitialize(DeviceExtension, FALSE);
+
+#endif // EFP_MIRRORING_ENABLED
+
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Re-enable the controller's interrupts.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemIntEnable,
+ SYSTEM_INTS_ENABLE);
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // All done !
+ //
+
+ DeviceExtension->ResetInProgress = 0;
+ return;
+
+ default:
+
+ //
+ // Invalid reset phase number. This should never happen!
+ //
+
+ DebugPrint((1,
+ "OliEsc2ResetAdapter: Invalid reset phase number: %x hex.\n",
+ DeviceExtension->ResetInProgress ));
+
+ ASSERT(0);
+
+ Error = TRUE;
+ break;
+ }
+
+ //
+ // If no error, request a timer call.
+ //
+
+ if (!Error) {
+
+ //
+ // Check if time-out.
+ //
+
+ if (DeviceExtension->ResetTimerCalls--) {
+
+ //
+ // Request a timer call.
+ //
+
+ ScsiPortNotification(RequestTimerCall,
+ DeviceExtension,
+ OliEsc2ResetAdapter,
+ Delay);
+
+ //
+ // The "ResetNotification" variable is used to keep track of the
+ // time during the reset. If the reset is not completed before
+ // the next ESC2_RESET_NOTIFICATION usec. unit, we call the
+ // "ScsiPortNotification(ResetDetected...)" routine.
+ // After the call the ScsiPort stops the delivery of SRBs for a
+ // little bit (~4 sec.).
+ //
+
+ if (DeviceExtension->ResetNotification >= ESC2_RESET_NOTIFICATION) {
+
+ //
+ // Notify that a reset was detected on the SCSI bus.
+ //
+
+ for (Bus=0; Bus < DeviceExtension->NumberOfBuses; Bus++) {
+ ScsiPortNotification(ResetDetected, DeviceExtension, Bus);
+ }
+
+ //
+ // Reset the "reset notification timer".
+ //
+
+ DeviceExtension->ResetNotification = 0;
+ }
+
+ //
+ // Update the "reset notification timer".
+ //
+
+ DeviceExtension->ResetNotification += Delay;
+ }
+ else {
+
+ //
+ // Time-out !
+ //
+
+ DebugPrint((1,
+ "OliEsc2ResetAdapter: Time-out! Reset phase number: %x hex.\n",
+ DeviceExtension->ResetInProgress ));
+
+ Error = TRUE;
+ }
+ }
+
+ //
+ // If error, log it.
+ //
+
+ if (Error) {
+
+ //
+ // Log an error.
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ ESCX_RESET_FAILED
+ );
+
+ //
+ // We clear the "ResetInProgress" variable to force another SCSI
+ // bus reset when the driver receives the first SRB request.
+ // Note that the interrupts are left disabled at the controller level.
+ //
+
+ DeviceExtension->ResetInProgress = 0;
+ }
+
+ //
+ // Done for now.
+ //
+
+ return;
+
+} // end OliEsc2ResetAdapter
+
+
+
+BOOLEAN
+GainSemaphore0(
+ IN PEISA_CONTROLLER EisaController
+ )
+
+/*++
+
+Routine Description:
+
+ Acquires semaphore 0 (used by EFP TYPE_SERVICE requests) if the
+ semaphore is available.
+
+Arguments:
+
+ EisaController Base address of the ESC-2 registers' address space
+
+Return Value:
+
+ Returns TRUE if semaphore successfully acquired.
+ Returns FALSE if semaphore busy.
+
+--*/
+
+{
+ ULONG i; // loop counter
+ UCHAR DataByte;
+
+ BOOLEAN GotSem = FALSE;
+
+
+ for (i = 0; i < SEMAPHORE_LOOPS && !GotSem; i++) {
+ ScsiPortWritePortUchar(&EisaController->CommandSemaphore,
+ SEM_LOCK);
+ DataByte = ScsiPortReadPortUchar(&EisaController->CommandSemaphore);
+ DataByte &= 3; // we're interested in only the lower the 2 bits
+ if (DataByte == SEM_GAINED) { // did we get the semaphore?
+ GotSem = TRUE; // if we got it, we'll exit the loop
+ }
+ else {
+ ScsiPortStallExecution(SEMAPHORE_INTERVAL); // delay
+ }
+ }
+ return(GotSem);
+} // end of GainSemaphore0()
+
+
+VOID
+BuildEfpCmd(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build an EFP command structure for the ESC-2 EFP interface mode.
+
+Arguments:
+
+ DeviceExtension Pointer to the device extension for this driver.
+ Srb Pointer to the Scsi Request Block to service
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+
+ PEFP_SGL pEFP; // SRB extension pointer
+ PQ_ENTRY pCQCmd; // EFP command queue entry pointer
+ ULONG physicalAddress; // Physical address of the EFP cmd
+ ULONG i; // loop counter
+ ULONG length; // Length of contiguous memory in the
+ // data buffer, starting at the
+ // beginning of the buffer
+
+ DebugPrint((3,"OliEsc2BuildEfpCmd: Enter routine.\n"));
+
+ //
+ // Get the EFP command address
+ //
+
+ pEFP = Srb->SrbExtension;
+ pCQCmd = &pEFP->EfpCmd;
+
+ //
+ // Clear the SRB extension area.
+ //
+
+ for (i=0; i< (sizeof(EFP_SGL)/4); i++) {
+ *(((PULONG)pEFP) + i) = 0; // 4 bytes for each loop
+ }
+
+ //
+ // Save SRB back pointer in EFP_SGL (SRB extension).
+ // The Srb is used at interrupt time.
+ //
+
+ pEFP->SrbAddress = Srb;
+
+ //
+ // The following "cast" is ONLY valid in the 32 bit world.
+ //
+
+ pCQCmd->qncmd.ncmd_userid = (ULONG)Srb;
+
+ pCQCmd->qncmd.ncmd_sort = 1; // ESC-2 provide sorting
+ pCQCmd->qncmd.ncmd_prior = 0; // highest priority (ESC-2 ignores)
+
+#if EFP_MIRRORING_ENABLED
+
+ if (DeviceExtension->Esc2 == TRUE) {
+ pCQCmd->qncmd.ncmd_mod = 0x01; // 01 hex for ESC2 (not 00-normal!)
+ }
+ else {
+ pCQCmd->qncmd.ncmd_mod = 0x00; // command directed to both disks
+ }
+
+#else
+
+ pCQCmd->qncmd.ncmd_mod = 0x01; // 01 hex for ESC2 (not 00-normal!)
+
+#endif // EFP_MIRRORING_ENABLED
+
+ //
+ // Copy the Command Descriptor Block (CDB) into the EFP command
+ //
+
+ ScsiPortMoveMemory(&pCQCmd->qncmd.ncmd_cdb, Srb->Cdb, Srb->CdbLength);
+ DebugPrint((3,
+ "OliEsc2BuildEfpCmd: CDB at %lx, length=%x, SRB at %lx.\n",
+ &pCQCmd->qncmd.ncmd_cdb, Srb->CdbLength, pEFP->SrbAddress));
+
+ //
+ // Build a scatter/gather list in the SRB if necessary
+ //
+
+ if (Srb->DataTransferLength > 0) {
+
+ physicalAddress = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ Srb->DataBuffer,
+ &length));
+
+ //
+ // length contains the length of contiguous memory starting
+ // at Srb->DataBuffer
+ //
+
+ if (length >= Srb->DataTransferLength) {
+
+ //
+ // The Srb->DataBuffer is contiguous: no need of
+ // scatter/gather descriptors
+ //
+
+ //
+ // Set the CDB length and the data transfer length
+ //
+ pCQCmd->qncmd.ncmd_cdb_l = (UCHAR)Srb->CdbLength;
+ pCQCmd->qncmd.ncmd_length = Srb->DataTransferLength;
+
+ pCQCmd->qncmd.ncmd_address = physicalAddress;
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ //
+ // Adapter to system transfer
+ //
+
+ pCQCmd->qncmd.ncmd_cmd_type = NCMD_WRITE;
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ //
+ // System to adapter transfer
+ //
+
+ pCQCmd->qncmd.ncmd_cmd_type = NCMD_READ;
+
+ } else if (!Srb->SrbFlags & 0xF0) { // SRB_FLAGS_NO_DATA_TRANSFER
+
+ pCQCmd->qncmd.ncmd_cmd_type = NCMD_NODATA;
+
+ }
+
+ }
+ else { // need scatter/gather list
+ //
+ // The Srb->DataBuffer is not contiguous: we need
+ // scatter/gather descriptors
+ //
+
+ BuildSgl(DeviceExtension, Srb);
+
+ }
+ } else {
+
+ //
+ // No data transfer is requested
+ //
+
+ pCQCmd->qncmd.ncmd_cmd_type = NCMD_NODATA;
+ pCQCmd->qncmd.ncmd_address = 0;
+ pCQCmd->qncmd.ncmd_cdb_l = (UCHAR)Srb->CdbLength;
+
+ }
+
+ return;
+
+} // end BuildEfpCmd()
+
+
+BOOLEAN EnqueueEfpCmd (
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PQ_ENTRY pEfpCmd,
+ IN PCOMMAND_QUEUE qPtr,
+ IN UCHAR TarLun,
+ OUT PUCHAR pSignal
+ )
+/*++
+
+Routine Description:
+
+ Enqueue a command into an EFP command queue. Update Put pointer
+ as needed, observing possible need to wrap, if the addition of
+ this command would exceed the length of the queue. Refer to
+ algorithm in comments below. NOTE: This code assumes that a queue
+ command takes up only queue entry (ESC-2 does NOT use Long scatter
+ gather commands, 64 bytes long).
+
+ Linkage: Called from Get_Information()
+ Get_Configuration()
+
+Arguments:
+
+ DeviceExtension Device extension for this adapter
+ pEfpCmd Pointer to command to be compiled to the queue.
+ TarLun Command queue array index (TARGET/LUN combination)
+ pSignal return status signal
+
+Return Value:
+
+ TRUE Command was enqueued.
+ *pSignal = 0: the queue is now full.
+ *pSignal = 1: the queue is not full.
+
+ FALSE Error enqueuing the command.
+ *pSignal = 0: the queue was full.
+ *pSignal = 1: problem in signalling controller
+ of empty to not empty transition.
+
+Algorithm:
+ If Queue is not full (Put != Get - (1 | 2))
+ Then
+ OldPut = Put
+ copy command (@DS:SI) to Queue[Put]
+ Put = (Put + (1 for normal, 2 for long)) mod Q length
+ read current Get pointer (to prevent race condition)
+ If Queue was empty (OldPut = Get)
+ Then
+ Signal controller of empty -> not empty transition
+ Endif
+ Return
+ Endif
+ Else Queue was initially full
+ Set error flag
+ Return ; caller is responsible for awaiting not full
+ EndElse
+
+--*/
+
+{
+ PQ_ENTRY pqmem;
+ USHORT getp, orig_putp, putp; // get and put pointers
+
+ //
+ // Initialize the local pointers with the real ones.
+ //
+
+ getp = qPtr->Cmd_Q_Get;
+ putp = qPtr->Cmd_Q_Put;
+
+ orig_putp = putp; // Used to empty to not empty message.
+
+ //
+ // Check if the queue is full (Put = Get - 1 or Put = Get - 2, defined
+ // by the fact that we have both normal and dual commands).
+ //
+
+ if (putp >= getp) {
+ getp += COMMAND_Q_ENTRIES; // Make Get > Put for easier comp.
+ }
+
+ getp = (getp - putp); // Entries left
+
+
+ if (getp <= 2) { // Is the queue full ?
+ *pSignal = 0; // Yes, it is. Error !
+ return(FALSE);
+ }
+
+ // Compile our command onto the queue at position of current PUT pointer.
+
+ // First, advance queue pointer to beginning of queue (past Get and Put
+ // pointers), then on up <put pointer count> number of queue elements.
+ // IMPORTANT: Note that sizeof(NORMAL_CMD) works as a standard queue
+ // element size because all commands accepted by the ESC-2 are of the
+ // same length. This would NOT work for an EFP-2!
+
+ pqmem = &qPtr->Cmd_Entries[putp];
+
+ *pqmem = *pEfpCmd;
+
+ //
+ // Update the local Put pointer
+ //
+ // Note: the pointer is incremented only by 1 !
+ // Good only if the command is one entry in size.
+ //
+
+ putp++;
+
+ if (putp == COMMAND_Q_ENTRIES) { // Need to wrap?
+ putp -= COMMAND_Q_ENTRIES; // Yes, do it.
+ }
+
+ //
+ // update Put pointer in the Queue itself (to match local put variable)
+ //
+
+ qPtr->Cmd_Q_Put = (UCHAR)putp;
+
+ //
+ // Re-read Get pointer (to avoid race conditions, we want current info)
+ //
+
+ getp = qPtr->Cmd_Q_Get;
+
+ //
+ // Check if the queue is empty using the original Put ptr and the
+ // current Get ptr.
+ //
+
+ if (getp == orig_putp) {
+
+ //
+ // Yes, the queue is now empty. We need to sent the "empty to not
+ // empty transition" message.
+ //
+
+ *pSignal = 1; // queue is not full.
+
+ //
+ // Send message
+ //
+
+ return(EfpCommand(DeviceExtension, TarLun));
+ }
+ else {
+
+ //
+ // The queue is not empty. Check if it's full.
+ //
+
+ if (putp >= getp) {
+ getp += COMMAND_Q_ENTRIES; // Make Get > Put for easier comp.
+ }
+
+ getp = (getp - putp); // Entries left
+
+
+ if (getp <= 2) { // Is the queue full ?
+ *pSignal = 0; // Yes, it is.
+ }
+ else {
+ *pSignal = 1; // No, it isn't.
+ }
+
+ //
+ // The command has been enqueued successfully.
+ //
+
+ return(TRUE);
+ }
+
+} // end EnqueueEfpCmd
+
+
+BOOLEAN
+DequeueEfpReply (
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ Dequeue one reply entry from the reply queue.
+
+
+ Linkage: Call Near
+ Get_Information(),
+ Get_Configuration()
+Arguments:
+
+ DeviceExtension Device extension for this adapter
+
+Return Value:
+
+ TRUE Ok, the RQ_In_Process (see device extension) variable
+ is valid.
+
+ FALSE Error (in EfpReplyQNotFull), the RQ_In_Process
+ variable (see device extension) is valid.
+
+ RQ_In_Process = 0, No valid reply entry.
+ 1, Dequeued an entry.
+
+Algorithm:
+
+ 1: If GET -> nrply_flag != 0
+ 2: then
+ copy the reply entry into ACB Q_Buf
+ reset the nrply_flag
+ increment the GET pointer
+ 3: If Reply_QFull != 0
+ 4: then
+ reset the Reply_QFull to 0
+ signal the controller the respond queue is no
+ longer full ( Type_service 08H)
+ endif
+ 5: set RQ_In_Process flag
+ 6: return TRUE
+ 7: else
+ reset the RQ_In_Process flag
+ (wait for interrupt from controller to signal a valid
+ entry has been placed in the reply queue)
+ return TRUE
+ endif
+
+
+// START NOTE EFP_MIRRORING_ENABLED.
+//
+// The DequeueEfpReply routine always uses the NORMAL_REPLY struct to
+// dequeue a request. This is possible because the "flag" field is at
+// the same offset in both structures (NORMAL_REPLY and MIRROR_REPLY).
+//
+// The DequeueEfpReply routine validates the reply entry checking if the
+// "flag" field is different from zero. This is OK because a good reply
+// has the "flag" field is set to 1 in NORMAL/MAINTENANCE mode and to 3
+// in MIRRORING mode. A value of zero means reply not good for both
+// environments.
+//
+// END NOTE EFP_MIRRORING_ENABLED.
+
+--*/
+
+{
+ UCHAR reply_get;
+ PQ_ENTRY preply_entry;
+
+ reply_get = DeviceExtension->Reply_Q_Get;
+ preply_entry = &DeviceExtension->NoncachedExt->Reply_Q[reply_get];
+
+ // reply valid flag set indicates reply entry valid and in process
+
+ if (preply_entry->qnrply.nrply_flag) {
+
+ DeviceExtension->RQ_In_Process = 1; // indicate busy
+
+ // copy reply queue entry to local queue entry buffer
+ *(&DeviceExtension->Q_Buf.qnrply) = preply_entry->qnrply;
+
+ // reset reply valid flag
+ preply_entry->qnrply.nrply_flag = 0;
+
+ // update the GET pointer, wrap around if necessary
+
+ if (DeviceExtension->Reply_Q_Get == (REPLY_Q_ENTRIES - 1)) {
+ DeviceExtension->Reply_Q_Get = 0; // yes, wraparound Get ptr
+ } else {
+ DeviceExtension->Reply_Q_Get += 1; // no, just inc Get ptr
+ }
+
+ //
+ // test if the queue is(was) full, and reset reply queue full
+ // signal if needed, signalling the controller that a queue
+ // full to not full transition has occurred.
+ //
+
+ if (DeviceExtension->Reply_Q_Full_Flag == 0x1) { // full?
+ DeviceExtension->Reply_Q_Full_Flag = 0; // reset flag
+
+ // send Reply Q Not Full cmd (q was full, but not now)
+
+ if (EfpReplyQNotFull(DeviceExtension)) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+ } else {
+ return (TRUE);
+ }
+
+ } else { // valid flag did NOT indicate reply entry was valid & ready
+
+ // No valid reply entry
+
+ DeviceExtension->RQ_In_Process = 0;
+ return (TRUE);
+ }
+
+} // end DequeueEfpReply
+
+
+BOOLEAN
+EfpReplyQNotFull (
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Descriptions:
+
+ Signal controller that reply queue is no longer full
+
+ Issue efp_cmd TYPE_SERVICE request to the BMIC mailbox registers.
+ Signal the controller that the previously full reply queue is no
+ longer full.
+
+ Linkage: Called from DequeueEfpReply()
+
+Arguments:
+
+ DeviceExtension Device extension for this adapter
+
+Return Value:
+
+ returns TRUE if no error.
+ returns FALSE if error.
+
+ --*/
+
+{
+ PEISA_CONTROLLER eisaController;
+
+ eisaController = DeviceExtension->EisaController;
+
+ if (!GainSemaphore0(eisaController)) { // try to get semaphore 0.
+ return(FALSE);
+ }
+
+ // if got the semaphore, output a TYPE SERVICE request to 'efp_rqnf'
+ ScsiPortWritePortUchar(&eisaController->InTypeService, S_EFP_REPNFUL);
+
+ // set bit 1 of the local doorbell register to generate interrupt request
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ return(TRUE);
+
+} // end EfpReplyQNotFull
+
+
+BOOLEAN
+EfpCommand (
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR TarLun
+ )
+
+/*++
+
+RoutineDescriptions:
+
+ Signal the controller that at least one command has been
+ entered into a command queue.
+
+ Issue efp_cmd TYPE_SERVICE request to the BMIC mailbox registers.
+ Tell the controller the queue number of the queue to which the
+ command was added.
+
+Arguments:
+
+ DeviceExtension Device extension for this adapter
+ TarLun Command queue array index (TARGET/LUN combination)
+
+Return Value:
+
+ returns TRUE if no error.
+ returns FALSE if error.
+
+ --*/
+
+{
+ PEISA_CONTROLLER eisaController;
+ UCHAR qnumber; // the queue # associated with the TarLun
+
+ //
+ // Get the ESC-2 registers' base address
+ //
+
+ eisaController = DeviceExtension->EisaController;
+
+ if (!GainSemaphore0(eisaController)) { // try to get semaphore 0.
+ return(FALSE);
+ }
+
+ // if got the semaphore, output a TYPE SERVICE request to 'efp_rqnf'
+ qnumber = DeviceExtension->DevicesPresent[TarLun].qnumber;
+ ScsiPortWritePortUchar( &eisaController->InTypeService,
+ (UCHAR)(qnumber | S_EFP_CMD));
+
+ // set bit 1 of local doorbell register to generate interrupt request
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBell, EFP_INT_BIT);
+
+ return(TRUE);
+
+} // end EfpCommand()
+
+
+BOOLEAN
+EfpGetInformation (
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Descriptions:
+
+ Issue EFP-interface mailbox command to get information about the
+ controller and its EFP environment.
+
+ Specifically, Get Information returns:
+ 3 bytes -- Firmware release
+ 1 byte -- SCSI level supported by the controller
+ 4 bytes -- Controller ID on first - fourth SCSI bus
+ 1 byte -- Controller environment (ie. MIRRORING or NORMAL)
+ 1 byte -- Constraints on linked commands
+ 1 byte -- Maximum size of a command queue (# of entries)
+
+Arguments:
+
+ DeviceExtension Device extension for this adapter
+
+Return Value:
+
+ returns TRUE if no error.
+ returns FALSE if error.
+
+ --*/
+
+{
+ PEISA_CONTROLLER eisaController;
+ BOOLEAN GotInt = FALSE;
+ UCHAR SignalFlag;
+ ULONG i; // counter
+
+ //
+ // Get the ESC-2 registers' base address
+ //
+
+ eisaController = DeviceExtension->EisaController;
+
+ // Set up the get_information EFP mailbox command
+
+ DeviceExtension->Q_Buf.qmbc.mbc_userid = 1;
+ DeviceExtension->Q_Buf.qmbc.mbc_sort = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_prior = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_reserved = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_cmd_type = MB_GET_INFO;
+ DeviceExtension->Q_Buf.qmbc.mbc_length = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_user_data[0] = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_user_data[1] = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_user_data[2] = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_user_data[3] = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_addr = 0;
+
+
+ // Enqueue the command
+
+ if (!EnqueueEfpCmd(DeviceExtension,
+ &DeviceExtension->Q_Buf,
+ DeviceExtension->DevicesPresent[0].qPtr,
+ 0, // mailbox queue is queue #0
+ &SignalFlag)) {
+ DebugPrint((1, "Problem enqueueing Get Information EFP command.\n"));
+ return(FALSE);
+ }
+
+ // Wait for controller to respond.
+ //
+ // NOTE: On an ESC-2, the Get_Configuration at this point does not
+ // query devices. The ESC-2 does a Get Configuration early in
+ // the boot process, and simply regurgitates this information when
+ // later (now, at device driver init time) sent a Get Configuration.
+ // Contrast this with the operation of an EFP-2, which may take many
+ // seconds to perform a Get_Configuration, while it queries devices.
+
+ for (i = 0; i < WAIT_INT_LOOPS && !GotInt; i++) {
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ EFP_CMD_COMPL) { // was EFP_INTERRUPT()
+ GotInt = TRUE;
+ }
+ else {
+ ScsiPortStallExecution(WAIT_INT_INTERVAL);
+ }
+ }
+
+ if (!GotInt) {
+ DebugPrint((1, "Controller did not respond to Get_Information.\n"));
+ return(FALSE);
+ }
+
+ // Get reply to the command.
+ if ( !(DequeueEfpReply(DeviceExtension)) ) {
+ DebugPrint((1, "Problem dequeueing reply to Get Information.\n"));
+ return(FALSE);
+ }
+
+ if (!DeviceExtension->RQ_In_Process) { // was a reply properly dequeued?
+ DebugPrint((1, "RQ_In_Process not 01 after Get_Information.\n"));
+ return(FALSE);
+ }
+
+ // Collect reply information
+
+ if (DeviceExtension->Q_Buf.qmbr.mbr_status) {
+ DebugPrint((1, "Get Information command reply status was not 0.\n"));
+ return(FALSE);
+ }
+
+ // Save into the DeviceExtnesion the information obtained by
+ // Get Information.
+
+ DeviceExtension->FW_Rel[0] =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_fw_rel[0]; //minor
+ DeviceExtension->FW_Rel[1] =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_fw_rel[1]; //minor*10
+ DeviceExtension->FW_Rel[2] =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_fw_rel[2]; //major
+ DeviceExtension->SCSI_Level =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_scsi_lev; // ESC2:01
+ DeviceExtension->Adapter_ID[0] =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_id1; // channel #1
+ DeviceExtension->Adapter_ID[1] =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_id2; // channel #2
+ DeviceExtension->Adapter_ID[2] =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_id3; // channel #3
+ DeviceExtension->Adapter_ID[3] =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_id4; // channel #4
+ DeviceExtension->Link_Cmd =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_link;
+ DeviceExtension->Max_CmdQ_ents =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_maxcmds;
+
+#if EFP_MIRRORING_ENABLED
+
+ DeviceExtension->Environment =
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_env;
+
+#endif // EFP_MIRRORING_ENABLED
+
+ // reset bit 1 of the system doorbell register to clear request
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_INT);
+ // was EFP_ACK
+
+ DebugPrint((1,
+ "EfpGetInformation: 1st channel ID = %d, 2nd channel ID = %d.\n",
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_id1,
+ DeviceExtension->Q_Buf.qmbr.mbr_appl.appgi.gi_id2));
+
+ return(TRUE);
+
+} // end of EfpGetInformation()
+
+
+BOOLEAN
+EfpGetConfiguration (
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Descriptions:
+
+ Issue EFP-interface mailbox command to get configuration information
+ about each SCSI device attached to the host adapter.
+
+ Specifically, for each device, Get Configuration returns:
+ 1 byte -- Maximum size of a command queue (# of entries)
+ 1 byte -- the device type (per standard SCSI protocol)
+ 1 byte -- the device type qualifier (per std SCSI protocol)
+ 1 byte -- SCSI level supported by the device
+ 1 byte -- SCSI Channel to which dev is connected (ESC-2: 01)
+ 1 byte -- SCSI ID of the device
+ 1 byte -- SCSI LUN of the device
+ 1 byte -- reserved
+
+Arguments:
+
+ DeviceExtension Device extension for this adapter
+
+Return Value:
+
+ returns TRUE if no error.
+ returns FALSE if error.
+
+ --*/
+
+{
+ PEISA_CONTROLLER eisaController;
+ BOOLEAN GotInt = FALSE;
+ UCHAR SignalFlag;
+ ULONG i; // counter
+ ULONG length; // Length of contiguous memory in the
+ // data buffer, starting at the
+ // beginning of the buffer
+
+
+ //
+ // Get the ESC-2 registers' base address
+ //
+
+ eisaController = DeviceExtension->EisaController;
+
+ // Set up the get_configuration EFP mailbox command
+
+ DeviceExtension->Q_Buf.qmbc.mbc_userid = 2;
+ DeviceExtension->Q_Buf.qmbc.mbc_sort = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_prior = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_reserved = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_cmd_type = MB_GET_CONF;
+ DeviceExtension->Q_Buf.qmbc.mbc_length =
+ sizeof(DeviceExtension->NoncachedExt->GetConfigInfo);
+ DeviceExtension->Q_Buf.qmbc.mbc_user_data[0] = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_user_data[1] = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_user_data[2] = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_user_data[3] = 0;
+ DeviceExtension->Q_Buf.qmbc.mbc_addr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ NULL, // no SRB
+ &DeviceExtension->NoncachedExt->GetConfigInfo,
+ &length));
+
+ // Enqueue the command
+
+ if (!EnqueueEfpCmd(DeviceExtension,
+ &DeviceExtension->Q_Buf,
+ DeviceExtension->DevicesPresent[0].qPtr,
+ 0, // mailbox queue is queue #0
+ &SignalFlag)) {
+ DebugPrint((1,
+ "Problem enqueueing Get Configuration EFP command.\n"));
+ return(FALSE);
+ }
+
+ // Wait for controller to respond.
+
+ for (i = 0; i < WAIT_INT_LOOPS && !GotInt; i++) {
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBell) &
+ EFP_CMD_COMPL) { // was EFP_INTERRUPT()
+ GotInt = TRUE;
+ }
+ else {
+ ScsiPortStallExecution(WAIT_INT_INTERVAL);
+ }
+ }
+
+ if (!GotInt) {
+ DebugPrint((1, "Controller did not respond to Get Configuration.\n"));
+ return(FALSE);
+ }
+
+ // Get reply to the command.
+ if ( !(DequeueEfpReply(DeviceExtension)) ) {
+ DebugPrint((1, "Problem dequeueing reply to Get Configuration.\n"));
+ return(FALSE);
+ }
+
+ if (!DeviceExtension->RQ_In_Process) { // was a reply properly dequeued?
+ DebugPrint((1, "RQ_In_Process not 01 after Get Configuration.\n"));
+ return(FALSE);
+ }
+
+ // Collect reply information (NOTE: since we allocate such a huge buffer
+ // for Get Configuration information, due to the fixed size requirement
+ // imposed by ScsiPortGetUncachedExtension, we never expect to see the
+ // Get Configuration error message that indicates the supplied buffer
+ // was too small (and if we did, there would be nothing we could do
+ // dynamically to adjust the size of the buffer). For this reason, we
+ // do no filtering of error status from this command.
+
+ if (DeviceExtension->Q_Buf.qmbr.mbr_status) {
+ DebugPrint((1, "Get Configuration cmd reply status was not 0.\n"));
+ return(FALSE);
+ }
+
+ // reset bit 1 of the system doorbell register to clear request
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBell, EFP_ACK_INT);
+
+ return(TRUE);
+
+} // end of EfpGetConfiguration()
+
+
+#if EFP_MIRRORING_ENABLED
+
+
+VOID
+OliEsc2MirrorInitialize (
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN InitTime
+ )
+
+/*++
+
+
+Routine Description:
+
+ Initializes all the FT EFP-2 structures.
+ It assumes that information on the attached SCSI devices has already
+ been obtained by the Get Configuration call, and is stored in the
+ noncached Extension. Note that this routine doesn't log any error.
+
+
+Arguments:
+
+ DeviceExtension Device extension for this driver.
+
+
+Return Value:
+
+ none
+
+
+--*/
+
+{
+ USHORT Index;
+ UCHAR Bus, Tar, Lun, TarLun, Env;
+ PGET_CONF pGetConfigInfo;
+ PTAR_Q pDevInfo;
+
+ //
+ // Analyse the Get Configuration information.
+ //
+
+ for (Index=0; Index < DeviceExtension->TotalAttachedDevices; Index++) {
+
+ //
+ // Initialize pointer to Get Configuration data.
+ //
+
+ pGetConfigInfo = &DeviceExtension->NoncachedExt->GetConfigInfo[Index];
+
+ //
+ // Read the initial mirror state of each TID/LUN from the ctrl info.
+ //
+
+ Env = pGetConfigInfo->gc_env;
+ Bus = pGetConfigInfo->gc_channel - 1; // make it 0-based
+ Tar = pGetConfigInfo->gc_id;
+ Lun = pGetConfigInfo->gc_lun;
+
+ TarLun = GET_QINDEX( Bus, Tar, Lun );
+
+ //
+ // Initialize pointer to mirroring structures.
+ //
+
+ pDevInfo = &DeviceExtension->DevicesPresent[TarLun];
+
+ //
+ // Find out the mirroring type if any.
+ //
+
+ if (InitTime) {
+
+ //
+ // Check if this device (TID/LUN) is mirrored.
+ // Note: the following logic defaults to dual mirroring if the
+ // EFP_DUAL_MIRRORING and EFP_SINGLE_MIRRORING bits are both set.
+ //
+
+ if (Env & EFP_DUAL_MIRRORING) {
+
+ pDevInfo->Type = EfpFtDualBus;
+
+ //
+ // send a info message to the debug port.
+ //
+
+ DebugPrint((1,
+ "OliEsc2MirrorInitialize: Dual bus mirroring,"
+ " Env=%x, Bus=%x, Tid=%x, Lun=%x.\n",
+ Env, Bus, Tar, Lun ));
+
+ }
+ else if (Env & EFP_SINGLE_MIRRORING) {
+
+ pDevInfo->Type = EfpFtSingleBus;
+
+ //
+ // Send a info message to the debug port.
+ //
+
+ DebugPrint((1,
+ "OliEsc2MirrorInitialize: Single bus mirroring,"
+ " Env=%x, Bus=%x, Tid=%x, Lun=%x.\n",
+ Env, Bus, Tar, Lun ));
+
+ }
+ else {
+ pDevInfo->Type = EfpFtNone;
+ }
+
+ //
+ // At the moment we don't know any error.
+ //
+
+ pDevInfo->KnownError = FALSE;
+ }
+
+ //
+ // If this is a mirrored disk, get the states of the disks.
+ //
+
+ if (pDevInfo->Type != EfpFtNone) {
+
+ //
+ // Check if the source disk is present.
+ //
+
+ if (Env & EFP_DISK_SOURCE) {
+
+ //
+ // Source disk is present.
+ //
+
+ pDevInfo->SourceDiskState = EfpFtMemberHealthy;
+ }
+ else {
+
+ //
+ // Source disk is missing.
+ //
+
+ pDevInfo->SourceDiskState = EfpFtMemberMissing;
+ }
+
+ //
+ // Check if the mirror disk is present.
+ //
+
+ if (Env & EFP_DISK_MIRROR) {
+
+ //
+ // Mirror disk is present.
+ //
+
+ pDevInfo->MirrorDiskState = EfpFtMemberHealthy;
+ }
+ else {
+
+ //
+ // Mirror disk is missing.
+ //
+
+ pDevInfo->MirrorDiskState = EfpFtMemberMissing;
+ }
+
+ } // end if (mirroring) ...
+
+ } // end for (each TID/LUN)
+
+ //
+ // all done
+ //
+
+ return;
+
+} // end OliEsc2MirrorInitialize()
+
+#endif // EFP_MIRRORING_ENABLED
diff --git a/private/ntos/miniport/oliscsi/oliesc2.h b/private/ntos/miniport/oliscsi/oliesc2.h
new file mode 100644
index 000000000..0a11a2ee1
--- /dev/null
+++ b/private/ntos/miniport/oliscsi/oliesc2.h
@@ -0,0 +1,1400 @@
+/*++
+
+Copyright (c) Ing. C. Olivetti & C., S.p.A., 1992
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ oliesc2.h
+
+Abstract:
+
+ This module contains the structures specific to the Olivetti ESC-2
+ host bus adapter. Data structures that are part of standard ANSI
+ SCSI will be defined in a header file that will be available to all
+ SCSI device drivers.
+
+Authors:
+
+ Kris Karnos and Young-Chi Tan, 1-November-1992
+
+Revision History:
+
+ 14-Sep-1993: (v-egidis)
+ - Added support for the EFP-2 mirroring mode.
+
+--*/
+
+#include <scsi.h>
+
+
+//
+// To enable the mirroring code set the following define to 1.
+//
+
+#define EFP_MIRRORING_ENABLED 0
+//#define EFP_MIRRORING_ENABLED 1
+
+//
+// The following define controls the type of error code returned when the
+// mirror breaks for the first time. If the define is set to 1, then the
+// SrbStatus/ScsiStatus combination is SRB_STATUS_ERROR/SCSISTAT_BUSY,
+// else the SrbStatus is set to SRB_STATUS_BUS_RESET. In the first case
+// (busy) the request is retried by the scsiport, whereas in the second case
+// (bus reset) the request is retried by the class driver. The busy error
+// code is the best one but because of a bug in the scsiport's busy logic,
+// the current miniport version returns the other one.
+// This define is used only if the EFP_MIRRORING_ENABLED is set to 1.
+//
+
+#define EFP_RETURN_BUSY 0
+//#define EFP_RETURN_BUSY 1
+
+//
+// EISA controller IDs
+//
+ // hi word = card type; lo word = mfg.
+#define ESC1_BOARDID 0x2110893D // ESC-1 (which this ADD won't support)
+#define ESC2_BOARDID 0x2210893D // ESC-2 (2z10893d, where z > 1, = ESC2)
+#define REV_MASK 0xF0FFFFFF // for masking out the revision level (z).
+
+//
+// Maximum number of EISA slots in system
+//
+
+#define MAX_EISA_SLOTS_STD 16 // # of EISA slots possible (per EISA std)
+#define MAX_EISA_SLOTS 8 // max # that Oli machines support
+
+//
+// Maximum number of EISA buses.
+//
+// Note: If you change this define, you need to change also the ScsiInfo
+// variable to ...
+//
+// SCSI_INFO ScsiInfo[MAX_EISA_BUSES][MAX_EISA_SLOTS_STD];
+//
+// ... and of course all the code that uses the variable ...
+//
+// ScsiInfo[ConfigInfo->SystemIoBusNumber][Slot - 1]
+//
+// It is very uncommon for a system to have 2 buses of the same type
+// (especially old buses like ISA and EISA).
+//
+
+#define MAX_EISA_BUSES 1 // # of EISA buses supported.
+
+//
+// Number of devices and EFP queues per host adapter
+//
+// Note that this miniport assumes that the host adapter uses target ID 7.
+// The maximum # of devices that can be attached to a host adapter is therefore
+// 7 targets * 8 LUNs = 56. Because the area we reserve for our queues is fixed
+// (ScsiPortGetUncachedExtension can only be called once per host adapter),
+// we will always create queues for the maximum # of devices that COULD be
+// attached to the host adapter -- rather than the actual number of devices
+// that are attached.
+//
+
+#define HA_BUSES 2 // EFP2 has 2 buses ( ESC-2 just 1 )
+#define HA_TARGETS 7 // SCSI targets 0 - 7 (but 7 is adapter)
+#define HA_LUNS 8 // SCSI LUNs range 0 - 7
+#define HA_DEVICES (HA_TARGETS * HA_LUNS)
+ // # possible attached devices per Bus
+#define HA_QUEUES ( ( HA_DEVICES * HA_BUSES ) + 1 )
+ // queue per device + mailbox queue
+#define MAX_HAIDS 4 // max number of H.A. Ids
+
+#define GET_QINDEX(B,T,L) ( B*HA_DEVICES + T*HA_LUNS + L + 1 )
+
+//
+// Base of the EISA address space
+//
+
+#define EISA_ADDRESS_BASE 0x0C80
+
+//
+// Define constants for request completion in case of bus reset
+//
+
+#define ALL_TARGET_IDS -1
+#define ALL_LUNS -1
+
+//
+// Maximum number of scatter/gather descriptors (the ESC-2 limit is 8192,
+// because the EFP extended scatter gather command provides 16 bits to
+// describe the scatter gather descriptor table length, accessing 64KB,
+// and the size of a scatter gather table element is 8 bytes. 64K/8 = 8K)
+//
+
+//#define MAXIMUM_SGL_DESCRIPTORS 8192
+#define MAXIMUM_SGL_DESCRIPTORS 20
+
+//
+// Maximum data transfer length
+//
+
+#define MAXIMUM_TRANSFER_SIZE 0xffffffff
+
+
+#define NO_BUS_ID 0xFF
+
+//
+// ESC-2 8-bit command codes (for CCB) and configuration commands
+//
+
+#define START_CCB 0x01 // get CCB for this op. Std I/O request.
+#define SEND_CONF_INFO 0x02 // send the Host Adapter config info.
+#define RESET_TARGET 0x04 // reset a specified SCSI target
+#define SET_CONF_INFO 0x40 // set specific configuration bits
+#define GET_CONF_INFO 0x41 // get specific configuration bits
+#define GET_FW_VERSION 0x42 // read firmware revision number
+#define CHECK_DEVICE_PRESENT 0x43 // check presence of a device
+
+//
+// ESC-2 configuration registers
+//
+
+#define CFG_REGS_NUMBER 8 // 8 configuration registers
+#define ATCFG_REGISTER 0x1 // AT-compatibility configuration
+#define IRQL_REGISTER 0x2 // Interrupt level
+
+//
+// ESC-2 ATCFG_REGISTER AT-compatibility configuration byte flags/masks
+//
+
+#define AT_ENABLED 0x01 // AT-compatibility mode enabled
+#define DISK_80_MASK 0x0E // Mask for disk 80's Target ID
+#define DISK_81_MASK 0x70 // Mask for disk 81's Target ID
+
+//
+// ESC-2 IRQL-REGISTER definitions
+//
+
+#define IRQ_MASK 0x03 // Mask for IRQ line bits 0 & 1
+
+#define IRQ_0B 0x00 // ID values of bits 0 and 1 in
+#define IRQ_0A 0x01 // the IRQL-REGISTER
+#define IRQ_05 0x02
+#define IRQ_0F 0x03
+#define IRQB 0x0B // The interrupts values themselves.
+#define IRQA 0x0A
+#define IRQ5 0x05
+#define IRQF 0x0F
+
+//
+// TYPE_SERVICE command IDs and mask (for ESC-2 using EFP interface)
+//
+
+#define S_EFP_SET 0x01 // Request the EFP interface be enabled
+#define S_EFP_START 0x02 // Supply physical addr of q descriptor
+#define S_EFP_SETDLG 0x04 // Req cntrlr start on-board diagnostics
+#define S_EFP_REPNFUL 0x08 // Prev'ly full reply q no longer full
+#define S_EFP_WARN 0x10 // For EFP-2 hw, activate auto-recovery
+
+#define S_EFP_CMD 0x80 // this is OR'd with the queue number
+
+//
+// TYPE MSG messages and masks for messages (EFP interface)
+//
+
+#define M_INIT_DIAG_OK 0x00 // Successful: efp_set|_start|_set_diag
+#define M_REPLY_Q_FULL 0x01 // Reply queue is full
+
+#define M_ERR_INIT 0x40 // Error during efp_set or efp_start
+#define M_ERR_CHECKSUM 0x41 // ROM checksum error has been found
+#define M_ERR_EEPROM 0x42 // EEPROM error encountered
+#define M_ERR_ARBITER 0x45 // Arbiter error exists
+#define M_ERR_SYSBUS 0x49 // System bus cntrlr (ie. BMIC) error
+#define M_ERR_ATCOMP 0x4A // AT-compat cntrlr has fault/failure
+#define M_ERR_UART 0x4C // Failure in the UART
+#define M_ERR_CMD_REJ 0x4E // prev cmd issued by sys was rejected
+#define M_ERR_CMDQ_NFUL 0x80 // *MASK* 1xxxxxxx (xxxxxxx is queue #)
+
+//
+// EFP interface queue lengths
+//
+// Due to restrictions of the NT miniport design, we can no longer
+// adjust the length of EFP command queues according to the number
+// of attached devices. These constants can, and should, be adjusted
+// for the best performance in an "average" configuration of attached
+// devices.
+//
+
+// Testing values for queue lengths: to force queue full case.
+//#define COMMAND_Q_ENTRIES 5
+//#define REPLY_Q_ENTRIES 5
+
+#define COMMAND_Q_ENTRIES 0x20 // 32 entries
+#define REPLY_Q_ENTRIES 0x80 // 128 entries
+
+//
+// Other queue equates
+//
+
+#define Q_ENTRY_SIZE 32 // a q entry is 32 bytes (LSG = 2 entries)
+#define Q_ENTRY_DWORDS 8 // number of dwords in a Q entry (32byte)
+#define Q_ENTRY_SHIFT 5 // for shift multiplies
+
+#define USER_ID_LIMIT 0x0FFFFFFF // wrap around limit for EFP cmd UserID
+ // MSB (bit 28-31) reserved for slot #
+
+//
+// Olivetti disk geometry translation
+//
+
+#define HPC_SCSI 16 // #heads for capacity up to 504MB
+#define THPC_SCSI 64 // #heads for capacity above 504MB
+#define SPT_SCSI 63 // #sectors per track
+#define HPCxSPT HPC_SCSI*SPT_SCSI // heads x sectors (up to 504MB)
+#define THPCxSPT THPC_SCSI*SPT_SCSI // heads x sectors (above 504MB)
+
+
+// YCT I don't think we need the following CCB definition. What you think ?
+//
+// First byte of the Command Control Block:
+//
+// Drive Number / Transfer Direction
+//
+// --------------------------------------
+// | XFER Dir | Target ID | LU Number |
+// --------------------------------------
+// 7 6 5 4 3 2 1 0
+//
+//
+// Subfield constants:
+//
+
+#define CCB_DATA_XFER_ANY_DIR 0 // The adapter decides
+#define CCB_DATA_XFER_IN 0x40 // XFER Dir = 01
+#define CCB_DATA_XFER_OUT 0x80 // XFER Dir = 10
+#define CCB_DATA_XFER_NONE 0xC0 // XFER Dir = 11
+#define CCB_TARGET_ID_SHIFT 3
+
+//
+// Status Register: bit 15-8: adapter status, bits 7-0: target status
+//
+// Adapter status after a power cycle:
+
+#define DIAGNOSTICS_RUNNING 0x53
+#define DIAGNOSTICS_OK_CONFIG_RECEIVED 0x01
+#define DIAGNOSTICS_OK_NO_CONFIG_RECEIVED 0x02
+
+//
+// The ESC-2 controller (and only it) in EFP mode can return some
+// error codes that are not present in the specifications.
+//
+
+//#define NO_ERROR 0x00
+//#define INVALID_COMMAND 0x01
+//#define SELECTION_TIMEOUT_EXPIRED 0x11
+//#define DATA_OVERRUN_UNDERRUN 0x12
+//#define UNEXPECTED_BUS_FREE 0x13
+//#define SCSI_PHASE_SEQUENCE_FAILURE 0x14
+//#define COMMAND_ABORTED 0x15
+//#define COMMAND_TO_BE_ABORTED_NOT_FOUND 0x16
+//#define QUEUE_FULL 0x1F
+//#define INVALID_CONFIGURATION_COMMAND 0x20
+//#define INVALID_CONFIGURATION_REGISTER 0x21
+//#define NO_REQUEST_SENSE_ISSUED 0x3B
+
+#define AUTO_REQUEST_SENSE_FAILURE 0x80
+#define PARITY_ERROR 0x81
+#define UNEXPECTED_PHASE_CHANGE 0x82
+#define BUS_RESET_BY_TARGET 0x83
+#define PARITY_ERROR_DURING_DATA_PHASE 0x84
+#define PROTOCOL_ERROR 0x85
+
+// Codes to identify logged errors related to H/W malfunction.
+// These codes must be shifted left by 16 bits, to distinguish them from
+// the adapter status and extended status after a EFP command.
+//
+// For use with ScsiPortLogError().
+
+#define ESCX_BAD_PHYSICAL_ADDRESS (0x01 << 16)
+#define SEND_COMMAND_TIMED_OUT (0x02 << 16)
+#define ESCX_RESET_FAILED (0x06 << 16)
+#define ESCX_INIT_FAILED (0x07 << 16)
+#define ESCX_REPLY_DEQUEUE_ERROR (0x08 << 16)
+
+#if EFP_MIRRORING_ENABLED
+
+#define EFP_MISSING_SOURCE_ERROR (0x80 << 16)
+#define EFP_MISSING_MIRROR_ERROR (0x81 << 16)
+#define EFP_SOURCE_OFFLINE_ERROR (0x82 << 16)
+#define EFP_MIRROR_OFFLINE_ERROR (0x83 << 16)
+
+#endif // EFP_MIRRORING_ENABLED
+
+//
+// Define various timeouts:
+//
+// RESET_REACTION_TIME number of microseconds the adapter takes to
+// change the status register on the reset command.
+//
+// EFP_RESET_DELAY number of microseconds the driver waits for after
+// a EFP-2 reset command. For the current 6/3/93
+// revision of the EFP firmware, this is the time
+// the board needs to re-initialize itself.
+//
+// EFP_RESET_LOOPS maximum number of attempts made by the driver to
+// get the diagnostics result from the status
+// register after a EFP reset command.
+//
+// EFP_RESET_INTERVAL number of microseconds the driver waits for after
+// each read of the status register (on the reset
+// command).
+//
+// ESC_RESET_DELAY number of microseconds the driver waits for after
+// a ESC-2 reset command. The minimum value for
+// this define is RESET_REACTION_TIME.
+//
+// ESC_RESET_LOOPS maximum number of attempts made by the driver to
+// get the diagnostics result from the status
+// register after a ESC reset command.
+//
+// ESC_RESET_INTERVAL number of microseconds the driver waits for after
+// each read of the status register (on the reset
+// command).
+//
+// POST_RESET_DELAY number of microseconds the adapter needs (!) after
+// a successful reset in order to accept the first
+// command (this should not happen and needs to be
+// investigated).
+//
+// SEMAPHORE_LOOPS maximum number of attempts made by the driver to
+// get the semaphore 0 (each attempt is followed
+// by a SEMAPHORE_INTERVAL delay.
+//
+// SEMAPHRE_INTERVAL number of microseconds the driver waits for before
+// re-trying to get the semaphore #0.
+//
+// WAIT_INT_LOOPS maximum number of attempts made by the driver to
+// get a reply for a get config info etc. during the
+// initialization phase (polling mode).
+//
+// WAIT_INT_INTERVAL number of microseconds the driver waits for before
+// re-checking the interrupt pending status.
+//
+// TIMER_WAIT_INT_LOOPS maximum number of attempts made by the driver to
+// get a reply for a set/start EFP command during the
+// reset phase (polling mode with timer).
+//
+// TIMER_WAIT_INT_INTERVAL number of microseconds the driver waits for before
+// re-checking the interrupt pending status.
+//
+
+#define RESET_REACTION_TIME 80 // 80 usec.
+#define EFP_RESET_DELAY 1000000 // 1 sec.
+#define EFP_RESET_LOOPS 1200 // 2 min.
+#define EFP_RESET_INTERVAL 100000 // 100 msec.
+#define ESC_RESET_DELAY 200000 // 200 msec.
+#define ESC_RESET_LOOPS 140 // 14 sec.
+#define ESC_RESET_INTERVAL 100000 // 100 msec.
+#define POST_RESET_DELAY 50000 // 50 msec.
+#define SEMAPHORE_LOOPS 750 // 75 msec.
+#define SEMAPHORE_INTERVAL 100 // 100 usec.
+#define WAIT_INT_LOOPS 10000 // 10 sec.
+#define WAIT_INT_INTERVAL 1000 // 1 msec.
+#define TIMER_WAIT_INT_LOOPS 1000 // 10 sec.
+#define TIMER_WAIT_INT_INTERVAL 10000 // 10 msec.
+
+//
+// If the reset is not completed before the next ESC2_RESET_NOTIFICATION usec.
+// unit, we call the "ScsiPortNotification(ResetDetected...)" routine.
+// After the call the ScsiPort stops the delivery of SRBs for a little bit
+// (~4 sec.). The value of this define is lower than 4 sec. because:
+// a) it's more implementation indipendent.
+// b) we want really really to make sure that the SRBs are held at the ScsiPort
+// level during the reset phase.
+//
+
+#define ESC2_RESET_NOTIFICATION 1000000 // 1 sec. (in usec).
+
+//
+// System/Local Interrupt register
+//
+// bit 3: Adapter reset w/out reconfiguration (Local Interrupt Register only)
+// bit 4: Adapter reset w/ reconfiguration (Local Interrupt Register only)
+// bit 7: Interrupt pending (read), reset (write) See ESC_INT_BIT
+//
+
+#define ADAPTER_RESET 0x08
+#define ADAPTER_CFG_RESET 0x10
+
+//
+// Global Configuration Register bits
+//
+// Bit 3: 1 = edge-triggered interrupts
+// 0 = level-triggered interrupts
+//
+
+#define EDGE_SENSITIVE 8
+
+//
+// EFP interface register bit definitions
+//
+
+ // Local Doorbell register bits
+#define EFP_INT_BIT 0x02 // driver -> ctrlr that EFP-2 cmd ready
+
+ // System Doorbell register bits
+#define EFP_CMD_COMPL 0x01 // ctrlr -> driver: EFP-2 q cmd completed
+#define EFP_TYPE_MSG 0x02 // ctrlr wants to send special EFP message
+#define EFP_ACK_INT 0x01 // driver -> ctrlr: interrupt serviced.
+#define EFP_ACK_MSG 0x02 // driver -> ctrlr: TYPE_MSG int serviced.
+
+ // ESC-1 High Performance --
+ // System and Local Doorbell registers
+#define ESC_INT_BIT 0x80 // ESC-1 bit for both sys&local doorbells,
+ // set interrupt, acknowledge int, etc.
+ // aka INTERRUPT_PENDING
+
+//
+// System/Local Interrupt Mask Register constants
+//
+
+#define INTERRUPTS_DISABLE 0x00
+#define INTERRUPTS_ENABLE (ESC_INT_BIT | EFP_TYPE_MSG | EFP_CMD_COMPL)
+
+
+ // Values of the incoming mailbox semaphore (SEM0)
+#define SEM_LOCK 0x01 // write 01 to sem port to test if sem free
+#define SEM_GAINED 0x01 // get 01 back if it was free, is now yours
+#define SEM_IN_USE 0x03 // get 11 (3) back, if sem not available
+#define SEM_UNLOCK 0x00 // release the semaphore
+
+//
+// Command Control Block length
+//
+#define CCB_FIXED_LENGTH 18
+
+//
+// SystemIntEnable register bit definition(s)
+//
+
+#define SYSTEM_INTS_ENABLE 0x01 // for SystemIntEnable (bellinte)
+
+//
+// EFP interface Mailbox Command Set
+//
+
+#define MB_GET_INFO 0x0 // get_information
+#define MB_DOWNLOAD 0x1 // download (DIAGNOSTIC cmd)
+#define MB_UPLOAD 0x2 // upload (DIAGNOSTIC cmd)
+#define MB_FORCE_EXE 0x3 // force_execution (DIAGNOSTICS)
+#define MB_GET_CONF 0x4 // get_configuration
+#define MB_RESET_BUS 0x5 // reset_scsi_bus (For EFP-2 board only)
+#define MB_SET_COPY 0x6 // set_copy (MAINTENANCE/MIRRORING)
+#define MB_SET_VERIFY 0x7 // set_verify (MAINTENANCE/MIRRORING)
+#define MB_DOWNLOAD_FW 0x8 // download_firmware
+
+//
+// EFP read/write command type definitions
+//
+
+#define NCMD_READ 0x10 // data xfer from device to sys memory
+#define NCMD_WRITE 0x11 // data xfer from sys memory to device
+#define NCMD_NODATA 0x12 // no data xfer normal command
+
+#define SSG_READ 0x20 // short SG read from device to sys memory
+#define SSG_WRITE 0x21 // short SG write from sys memory to device
+
+#define LSG_READ 0x30 // long SG read from device to sys memory
+#define LSG_WRITE 0x31 // long SG write from sys memory to device
+
+#define ESG_READ 0x40 // extended SG read from dev to sys memory
+#define ESG_WRITE 0x41 // extended SG write from sys memory to dev
+
+//
+// EFP Reply entry global result values (see also ESC-1 host adapter statuses)
+//
+
+#define EFP_CMD_SUCC 0x00 // command successful
+#define EFP_WARN_ERR 0x01 // warning or fatal error
+#define EFP_EISA_ERR 0xFF // EISA bus transfer generic error
+// Note that the subset below are the same as their ESC-1 counterparts
+#define EFP_LINK_COMP 0x0B // linked command complete with flag
+#define EFP_SEL_TIMEOUT 0x11 // selection timeout expired
+#define EFP_DATA_RUN 0x12 // data overrun/underrun
+#define EFP_BUS_FREE 0x13 // unexpected BUS FREE phase detected
+#define EFP_PHASE_ERR 0x14 // SCSI phase sequence failure
+#define EFP_CMD_ABORT 0x15 // command aborted
+#define EFP_ABORT_LOST 0x16 // cmd to be aborted hasn't been found
+#define EFP_INT_Q_FULL 0x1F // internal q is full; wait to send cmds
+#define EFP_AUTOREC_OK 0x10 // autonomous recovery proc was OK
+#define EFP_AUTOREC_KO 0x18 // autonomous recovery proc failed
+
+//
+// EFP Reply entry Extended Status values (compare to SCSI target statuses)
+//
+
+#define EFP_NO_ERROR 0x00 // nothing to report
+#define EFP_CHK_COND 0x30 // check condition
+#define EFP_COND_MET 0x31 // condition met
+#define EFP_DEV_BUSY 0x32 // target busy
+#define EFP_INTER_GOOD 0x34 // intermediate/good
+#define EFP_INTER_COND 0x35 // intermediate/condition
+#define EFP_RESV_CONF 0x36 // reservation conflict
+#define EFP_ABORT_CMD 0x3B // abort command
+
+//
+// EFP Reset result values
+//
+
+#define EFP_RESET_OK 0x0000 // SCSI bus reset succeeded.
+#define EFP_RESET_ERROR 0x0001 // SCSI bus reset error.
+
+//
+// device LuExtension SRB-CHAIN definition
+//
+
+#define SRB_CHAIN 0x8000
+
+//
+// High Performance mode command sent flag
+//
+
+#define RESET_TARGET_SENT 0x80
+#define BUS_RESET_SENT 0x70
+
+//*******************************************************************
+//************************ STRUCTURES *****************************
+//*******************************************************************
+
+//
+// Incoming mailbox format (GetCmdBlock/SendConfInfo requests)
+//
+
+typedef struct _CMDI {
+ UCHAR mbi_taskid; // task identifier
+ UCHAR mbi_cmd; // ESC-1 command code
+ USHORT mbi_cmdlgt; // command length
+ ULONG mbi_address; // data address
+} CMDI, *PCMDI;
+
+//
+// Outgoing mailbox format (GetCmdBlock/SendConfInfo requests)
+//
+
+typedef struct _CMDO {
+ UCHAR mbo_taskid; // task identifier
+ UCHAR mbo_pad;
+ UCHAR mbo_tastat; // target status
+ UCHAR mbo_hastat; // Host Adapter status
+ ULONG mbo_address; // data address
+} CMDO, *PCMDO;
+
+//
+// Incoming mailbox format for Read Internal Configuration request
+//
+
+typedef struct _RICI {
+ UCHAR rici_taskid; // task identifier
+ UCHAR rici_cmd; // ESC-1 command code = 41H
+ UCHAR rici_reg; // internal register to read (0-7)
+} RICI, *PRICI;
+
+//
+// Outgoing mailbox format for Read Internal Configuration request
+//
+
+typedef struct _RICO {
+ UCHAR rico_taskid; // task identifier
+ UCHAR rico_pad;
+ UCHAR rico_tastat; // target status
+ UCHAR rico_hastat; // Host Adapter status
+ UCHAR rico_value; // value of requested register
+} RICO, *PRICO;
+
+//
+// Incoming mailbox format for Read Firmware Revision request
+//
+
+typedef struct _RFWI {
+ UCHAR rfwi_taskid; // task identifier
+ UCHAR rfwi_cmd; // ESC-1 command code = 42H
+} RFWI, *PRFWI;
+
+//
+// Outgoing mailbox format for Read Firmware Revision request
+//
+
+typedef struct _RFWO {
+ UCHAR rfwo_taskid; // task identifier
+ UCHAR rfwo_pad;
+ UCHAR rfwo_tastat; // target status
+ UCHAR rfwo_hastat; // Host Adapter status
+ UCHAR rfwo_minor; // minor revision, binary
+ UCHAR rfwo_major; // major revision, binary
+} RFWO, *PRFWO;
+
+// KMK Note: we've never used Check Device Present.
+//
+// Incoming mailbox format for Check Device Present request
+//
+
+typedef struct _CDPI {
+ UCHAR cdpi_taskid; // task identifier
+ UCHAR cdpi_cmd; // ESC-1 command code = 42H
+ UCHAR cdpi_target; // target ID
+} CDPI;
+
+//
+// Outgoing mailbox format for Check Device Present request
+//
+
+typedef struct _CDPO {
+ UCHAR cdpo_taskid; // task identifier
+ UCHAR cdpo_pad;
+ UCHAR cdpo_tastat; // target status
+ UCHAR cdpo_hastat; // Host Adapter status
+ UCHAR cdpo_target; // target ID
+ UCHAR cdpo_status; // 0 = non present, 1 = present
+} CDPO;
+
+//
+// MBOX structure (to facilitate MBI and MBO copies (OUTs)
+//
+
+typedef struct _MBOX {
+ ULONG mblow;
+ ULONG mbhigh;
+} MBOX, *PMBOX;
+
+//
+// Incoming mailbox command
+//
+
+typedef union _MBI {
+ CMDI cmd; // get CCB or send config info
+ RICI ric; // read internal configuration
+ RFWI rfw; // read firmware revision
+ CDPI cdp; // check device present
+ MBOX mbcopy; // for copying an MBI
+} MBI, *PMBI;
+
+//
+// Outgoing mailbox command
+//
+
+typedef union _MBO {
+ CMDO cmd; // get CCB or send config info
+ RICO ric; // read internal configuration
+ RFWO rfw; // read firmware revision
+ CDPO cdp; // check device present
+ MBOX mbcopy; // for copying an MBO
+} MBO, *PMBO;
+
+//
+// ESC-2 registers model
+// Note that this is designed to begin with EISA_ADDRESS_BASE, 0x0C80.
+// ESC-1 high performance names are in lower case;
+// EFP interface names are in upper case.
+//
+
+typedef struct _EISA_CONTROLLER {
+ UCHAR BoardId[4]; // xC80
+ UCHAR Unused[4]; // we use no register in XC84 - XC87 range.
+ UCHAR GlobalConfiguration; // xC88 - Bit 3 of this register indicates
+ // level- or edge-triggered interrupts
+ UCHAR SystemIntEnable; // xC89 - system int enab/ctrl reg (bellinte)
+ UCHAR CommandSemaphore; // xC8A - Semaphore port 0 for the Incoming
+ // Service Mailbox Regs aka: SEM0, seminc
+ UCHAR ResultSemaphore; // xC8B - Semaphore port 1 for the Outgoing
+ // Msg Mailbox Regs aka: SEM1, semout
+ UCHAR LocalDoorBellMask; // xC8C - Interrupt mask register for the
+ // Local Doorbell register (maskinc)
+ UCHAR LocalDoorBell; // xC8D - Local Doorbell register (bellinc)
+ UCHAR SystemDoorBellMask; // xC8E - Interrupt mask register for the
+ // System Doorbell register (maskout)
+ UCHAR SystemDoorBell; // xC8F - System Doorbell register (bellout)
+ UCHAR InTypeService; // xC90 - 8-bit Incoming Mbox Reg (TYPE_SERV)
+ // (aka mbi_addr)
+ // ESC-1: InTaskId
+ UCHAR InParm1; // xC91 - parameter 1 to TYPE_SERVICE request
+ // ESC-1: Command
+ UCHAR InParm2; // xC92 - parameter 2 to TYPE_SERVICE request
+ // ESC-1: USHORT CommandLength xC92-xC93
+ UCHAR InParm3; // xC93 - parameter 3 to TYPE_SERVICE request
+ UCHAR InParm4; // xC94 - parameter 4 to TYPE_SERVICE request
+ // ESC-1: ULONG InAddress xC94-xC97
+ UCHAR InReserved1; // xC95 - 8-bit mailbox register reserved
+ UCHAR InReserved2; // xC96 - 8-bit mailbox register reserved
+ UCHAR InReserved3; // xC97 - 8-bit mailbox register reserved
+ UCHAR OutTypeMsg; // xC98 - 8-bit Outgoing Mailbox reg (TYPE_MSG)
+ // (aka mbo_addr)
+ // ESC-1: OutTaskId
+ UCHAR OutReserved1; // xC99 - 8-bit mailbox register reserved
+ UCHAR OutReserved2; // xC9A - 8-bit mailbox register reserved
+ // ESC-1: USHORT Status xC9A-xC9B
+ UCHAR OutReserved3; // xC9B - 8-bit mailbox register reserved
+ UCHAR OutReserved4; // xC9C - 8-bit mailbox register reserved
+ // ESC-1: ULONG OutAddress xC9C-xC9F
+ UCHAR OutReserved5; // xC9D - 8-bit mailbox register reserved
+ UCHAR OutReserved6; // xC9E - 8-bit mailbox register reserved
+ UCHAR OutReserved7; // xC9F - 8-bit mailbox register reserved
+ } EISA_CONTROLLER, *PEISA_CONTROLLER;
+
+//
+// EFP QUEUE STRUCTURES section begins ----->
+//
+
+//
+// Queues descriptor header.
+//
+
+typedef struct _QD_HEAD { // 16 bytes
+ USHORT qdh_maint; // 0001h=MAINTENANCE env; 0000h=USER env.
+ USHORT qdh_n_cmd_q; // num of cmd queues allocated by system.
+ USHORT qdh_type_reply; // 1=Ctrlr ints @each reply entry; 0=after 1+
+ USHORT qdh_reserved1;
+ ULONG qdh_reply_q_addr; // phys addr of reply q (must be dword aligned)
+ USHORT qdh_n_ent_reply; // number of entries in the reply queue
+ USHORT qdh_reserved2;
+} QD_HEAD, *PQD_HEAD;
+
+//
+// Queues descriptor body. NOTE: There is one body element for each
+// queue, including the mailbox queue. The mailbox queue descriptor
+// is the first descriptor body and is always referred to as queue 0.
+//
+
+typedef struct _QD_BODY { // 16 bytes
+ UCHAR qdb_scsi_level; // SCSI protocol level. 01h=SCSI-1; 02h=SCSI-2.
+ UCHAR qdb_channel; // SCSI channel. 01h=1st SCSI chan; 02h=2nd.
+ UCHAR qdb_ID; // SCSI ID of the device.
+ UCHAR qdb_LUN; // SCSI LUN of the device.
+ UCHAR qdb_n_entry_cmd; // num of cmd entries in this queue (must be >=4)
+ UCHAR qdb_notfull_int; // ctrl int if q goes full to not full (01=yes)
+ UCHAR qdb_no_ars; // 01h=ARS disabled for this device
+ UCHAR qdb_timeout; // timeout in seconds (0 hex = infinite wait)
+ ULONG qdb_cmd_q_addr; // physical address of cmd queue.
+ ULONG qdb_reserved;
+} QD_BODY, *PQD_BODY;
+
+//
+// Application field definitions for the EFP Get_Information command.
+//
+
+typedef struct _GET_INFO { // 16 bytes
+ UCHAR gi_fw_rel[3]; // byte0=minor; byte1=minor*10; byte 2=major
+ UCHAR gi_scsi_lev; // SCSI level supported by the ctrlr (ESC2: 01)
+ UCHAR gi_env; // bit packed field defining mirroring environment
+ UCHAR gi_link; // defining LINKED command constraints
+ UCHAR gi_maxcmds; // max size of a cmd q; # of 32-byte cmd entries
+ UCHAR gi_res1; // reserved
+ UCHAR gi_id1; // controller ID on first SCSI bus
+ UCHAR gi_id2; // controller ID on second SCSI bus
+ UCHAR gi_id3; // controller ID on third SCSI bus
+ UCHAR gi_id4; // controller ID on fourth SCSI bus
+ ULONG gi_res2; // reserved
+} GET_INFO, *PGET_INFO;
+
+//
+// Structure of info returned from the EFP Get_Configuration cmd.
+//
+
+typedef struct _GET_CONF { // 8 bytes per structure, 1 struc per device
+ UCHAR gc_dev_type; // SCSI device type
+ UCHAR gc_dev_qual; // SCSI device type qualifier
+ UCHAR gc_scsi_level; // SCSI protocol level supported by the device
+ UCHAR gc_env; // EFP interface environment of disk device
+ UCHAR gc_channel; // SCSI channel to which device is connected
+ UCHAR gc_id; // SCSI target ID
+ UCHAR gc_lun; // SCSI Logical Unit Number
+ UCHAR gc_res; // reserved
+} GET_CONF, *PGET_CONF;
+
+
+#if EFP_MIRRORING_ENABLED
+
+//
+// defines for the gc_env of the GET_CONF struct
+//
+
+#define EFP_DUAL_MIRRORING 0x20 // dual bus mirroring
+#define EFP_SINGLE_MIRRORING 0x10 // single bus mirroring
+#define EFP_DISK_MIRROR 0x02 // mirrored disk presence
+#define EFP_DISK_SOURCE 0x01 // source disk presence
+
+#endif // EFP_MIRRORING_ENABLED
+
+//
+// Flexible structure to specific results for a mailbox command's reply
+//
+
+typedef union _MBAPPL { // see MBRPLY
+ GET_INFO appgi; // application field for get_information cmd
+ GET_CONF appgc; // application field for get_configuration cmd
+} MBAPPL, *PMBAPPL;
+
+//
+// Mailbox command entry structure (EFP spec)
+//
+
+typedef struct _MAILBOX_CMD { // 32 bytes
+ ULONG mbc_userid; // command identifier.
+ UCHAR mbc_sort; // cmd can be sorted (1=yes)
+ UCHAR mbc_prior; // cmd priority. range 00h (hi) -> FFh (lo).
+ UCHAR mbc_reserved; // reserved for future use.
+ UCHAR mbc_cmd_type; // valid mailbox command code (see EFP spec)
+ ULONG mbc_length; // length of data transfer in bytes.
+ ULONG mbc_user_data[4]; // generic parameters for the command.
+ ULONG mbc_addr; // phys addr of buffer in system ram
+} MAILBOX_CMD, *PMAILBOX_CMD; // where data is to be transferred to/from.
+
+//
+// Mailbox reply structure (EFP spec)
+//
+
+typedef struct _MAILBOX_REPLY { // 32 bytes
+ ULONG mbr_userid; // command identifier.
+ ULONG mbr_length; // length of data xfer successfully completed.
+ ULONG mbr_reserved; // reserved for future use.
+ MBAPPL mbr_appl; // specific results for each command.
+ USHORT mbr_status; // command global result (see spec).
+ UCHAR mbr_cmd_q; // command queue to which the reply refers.
+ UCHAR mbr_flag; // if controller sets to 1, response is valid;
+} MAILBOX_REPLY, *PMAILBOX_REPLY; // otherwise, response is invalid.
+
+//
+// Normal command structure. (Note: CDB defined in SCSI.H).
+//
+
+typedef struct _NORMAL_CMD { // 32 bytes
+ ULONG ncmd_userid; // command identifier.
+ UCHAR ncmd_sort; // cmd can be sorted (1=yes)
+ UCHAR ncmd_prior; // cmd priority. range 00h (hi) -> FFh (lo).
+ UCHAR ncmd_mod; // mode. 0=norm/maint on ESC-2
+ UCHAR ncmd_cmd_type; // 10h=dev->mem; 11h=mem->dev; 12h=noxfer.
+ UCHAR ncmd_cdb_l; // length of SCSI cmd block.
+ UCHAR ncmd_reserved[3]; // reserved
+ ULONG ncmd_length; // length of the data transfer.
+ CDB ncmd_cdb; // cmd descriptor block (SCSI CDB - size varies).
+ ULONG ncmd_address; // physaddr of system mem buf for data xfer.
+} NORMAL_CMD, *PNORMAL_CMD;
+
+//
+// Short scatter/gather commands definition.
+//
+
+typedef struct _SHORT_SG { // 32 bytes
+ ULONG ssg_userid; // cmd id.
+ UCHAR ssg_sort; // cmd can be sorted (1=YES)
+ UCHAR ssg_prior; // cmd priority. range 00h (hi) -> FFh (lo).
+ UCHAR ssg_mod; // mode. 0=norm/maint on ESC-2
+ UCHAR ssg_cmd_type; // cmd code. 20h=short read SG. 21h="write.
+ ULONG ssg_log_blk; // logical block address of the SCSI device.
+ UCHAR ssg_size_blk; // log. block size of the disk in 256byte units
+ UCHAR ssg_reserved; // reserved for future use
+ USHORT ssg_l1; // length of the buffer associated w/ A1
+ USHORT ssg_l2; // length of the buffer associated w/ A2
+ USHORT ssg_l3; // length of the buffer associated w/ A3
+ ULONG ssg_a1; // physical address associated with L1
+ ULONG ssg_a2; // physical address associated with L2
+ ULONG ssg_a3; // physical address associated with L3
+} SHORT_SG, *PSHORT_SG;
+
+//
+// Long scatter/gather commands definition.
+//
+
+typedef struct _LONG_SG { // 64 bytes
+ ULONG lsg_userid; // cmd id.
+ UCHAR lsg_sort; // cmd can be sorted (1=YES)
+ UCHAR lsg_prior; // cmd priority. range 00h (hi) -> FFh (lo).
+ UCHAR lsg_mod; // mode. 0=norm/maint on ESC-2
+ UCHAR lsg_cmd_type; // cmd code. 30h=long read SG; 31h="write.
+ ULONG lsg_log_blk; // logical block address of the SCSI device.
+ UCHAR lsg_size_blk; // log. block size of the disk in 256byte units
+ UCHAR lsg_reserved; // reserved for future use
+ USHORT lsg_l1; // length of the buffer associated w/ A1
+ USHORT lsg_l2; // length of the buffer associated w/ A2
+ USHORT lsg_l3; // length of the buffer associated w/ A3
+ ULONG lsg_a1; // physical address assocated with L1
+ ULONG lsg_a2; // physical address assocated with L2
+ ULONG lsg_a3; // physical address assocated with L3
+ USHORT lsg_link; // must be FFFF hex; log link to prev cmd entry.
+ USHORT lsg_l4; // length of the buffer associated w/ A4
+ USHORT lsg_l5; // length of the buffer associated w/ A5
+ USHORT lsg_l6; // length of the buffer associated w/ A6
+ USHORT lsg_l7; // length of the buffer associated w/ A7
+ USHORT lsg_l8; // length of the buffer associated w/ A8
+ ULONG lsg_a4; // physical address assocated with L4
+ ULONG lsg_a5; // physical address assocated with L5
+ ULONG lsg_a6; // physical address assocated with L6
+ ULONG lsg_a7; // physical address assocated with L7
+ ULONG lsg_a8; // physical address assocated with L8
+} LONG_SG, *PLONG_SG;
+
+//
+// Extended scatter/gather commands definition.
+//
+
+typedef struct _EXTENDED_SG { // 32 bytes
+ ULONG esg_userid; // cmd id.
+ UCHAR esg_sort; // cmd can be sorted (1=YES)
+ UCHAR esg_prior; // cmd priority. range 00h (hi) -> FFh (lo).
+ UCHAR esg_mod; // mode. 0=norm/maint on ESC-2
+ UCHAR esg_cmd_type; // cmd code. 40h=extended read SG; 41h="write.
+ UCHAR esg_cdb_l; // length of SCSI cmd block.
+ UCHAR esg_reserved1[3];
+ USHORT esg_lb; // length of the scatter gather descriptor table.
+ USHORT esg_reserved2;
+ CDB esg_cdb; // cmd descriptor block (SCSI CDB).
+ ULONG esg_address; // physaddr of scatter gather descriptor table.
+} EXTENDED_SG, *PEXTENDED_SG;
+
+//
+// Reply structure for NORMAL/MAINTENANCE environment. (NOTE: There is
+// no MIRRORING environment supported by the ESC-2). SENSE_DATA in SCSI.H.
+//
+
+typedef struct _NORMAL_REPLY { // 32 bytes
+ ULONG nrply_userid; // cmd id.
+ ULONG nrply_scsi_len; // length of data transfer.
+ SENSE_DATA nrply_sense; // extended info about error detected
+ USHORT nrply_reserved; //
+ UCHAR nrply_status; // cmd global result (0=success;1=warn/err;more)
+ UCHAR nrply_ex_stat; // extended status (see EFP spec)
+ UCHAR nrply_cmd_q; // command queue to which the reply refers.
+ UCHAR nrply_flag; // = 1 means response valid; = 0, resp invalid.
+} NORMAL_REPLY, *PNORMAL_REPLY;
+
+
+#if EFP_MIRRORING_ENABLED
+
+//
+// Reply structure for MIRRORING environment.
+//
+
+typedef struct _MIRROR_REPLY { // 32 bytes
+
+ ULONG mrply_userid; // cmd id.
+ ULONG mrply_scsi_len; // length of data transfer.
+ UCHAR mrply_valid1; // error source.
+ UCHAR mrply_sense1; // sense key.
+ UCHAR mrply_addit1; // additional sense code.
+ UCHAR mrply_qualif1; // additional sense code qualifier.
+ ULONG mrply_info1; // information bytes of request sense xdata.
+ UCHAR mrply_valid2; // error source.
+ UCHAR mrply_sense2; // sense key.
+ UCHAR mrply_addit2; // additional sense code.
+ UCHAR mrply_qualif2; // additional sense code qualifier.
+ ULONG mrply_info2; // information bytes of request sense xdata.
+ USHORT mrply_reserved; //
+ UCHAR mrply_off_attr; // "off line" device attribute.
+ UCHAR mrply_d_off; // "off line" device SCSI ID.
+ UCHAR mrply_status; // cmd global result.
+ UCHAR mrply_ex_stat; // mirroring state (0=OK, 1=KO).
+ UCHAR mrply_cmd_q; // cmd queue to which the reply refers.
+ UCHAR mrply_flag; // 3=response is valid, 0=response is invalid.
+
+} MIRROR_REPLY, *PMIRROR_REPLY;
+
+//
+// "flag" field defines
+//
+
+#define MREPLY_VALID 0x03 // mirroring reply valid
+#define NREPLY_VALID 0x01 // normal/maintenance reply valid
+
+//
+// "off_attr" field defines
+//
+
+#define EFP_SOURCE_OFFLINE 0x01 // source disk off line
+#define EFP_MIRROR_OFFLINE 0x02 // mirror disk off line
+
+//
+// "valid" field defines (specific to the mirroring environment)
+//
+
+#define EFP_SENSE_NO_INFO 0x70 // info doesn't relate to SCSI device
+#define EFP_SENSE_INFO 0xF0 // info relates to SCSI device
+
+//
+// Sense data struct for mirroring replays.
+//
+
+typedef struct _MREPLY_SDATA {
+
+ UCHAR Valid; // error source.
+ UCHAR Sense; // sense key.
+ UCHAR Addit; // additional sense code.
+ UCHAR Qualif; // additional sense code qualifier.
+ ULONG Info; // information bytes of request sense xdata.
+
+} MREPLY_SDATA, *PMREPLY_SDATA;
+
+//
+// EFP_FT_TYPE is an enumerated field that describes the FT types.
+//
+
+typedef enum _EFP_FT_TYPE {
+
+ EfpFtNone,
+ EfpFtSingleBus,
+ EfpFtDualBus
+
+} EFP_FT_TYPE, *PEFP_FT_TYPE;
+
+//
+// EFP_FT_MEMBER_STATE is an enumerated field that describes the state of
+// one member of the SCSI mirror.
+//
+
+typedef enum _EFP_FT_MEMBER_STATE {
+
+ EfpFtMemberHealthy,
+ EfpFtMemberMissing,
+ EfpFtMemberDisabled
+
+} EFP_FT_MEMBER_STATE, *PEFP_FT_MEMBER_STATE;
+
+//
+// Mirroring macros.
+//
+
+#define D_OFF_TO_LUN(x) (((x) >> 5) & 0x7)
+#define D_OFF_TO_TARGET(x) (((x) >> 2) & 0x7)
+#define D_OFF_TO_PATH(x) (((x) + 3) & 0x3)
+
+#endif // EFP_MIRRORING_ENABLED
+
+
+//
+// Flexible structure to hold an EFP queue entry (command or reply)
+//
+
+// START NOTE EFP_MIRRORING_ENABLED.
+//
+// The DequeueEfpReply routine always uses the NORMAL_REPLY struct to
+// dequeue a request. This is possible because the "flag" field is at
+// the same offset in both structures (NORMAL_REPLY and MIRROR_REPLY).
+//
+// The DequeueEfpReply routine validates the reply entry checking if the
+// "flag" field is different from zero. This is OK because a good reply
+// has the "flag" field is set to 1 in NORMAL/MAINTENANCE mode and to 3
+// in MIRRORING mode. A value of zero means reply not good for both
+// environments.
+//
+// The OliEsc2Interrupt routine always uses the "userid" field of the
+// NORMAL_REPLY struct to retrieve the SRB. This is OK because the "userid"
+// field is at the same offset in both structures (NORMAL_REPLY and
+// MIRROR_REPLY).
+//
+// END NOTE EFP_MIRRORING_ENABLED.
+
+typedef union _Q_ENTRY { // see ACB's Qbuf, work space for q cmds/replies
+ MAILBOX_CMD qmbc;
+ MAILBOX_REPLY qmbr;
+ NORMAL_CMD qncmd;
+ SHORT_SG qssg;
+ EXTENDED_SG qesg;
+ NORMAL_REPLY qnrply;
+
+#if EFP_MIRRORING_ENABLED
+
+ MIRROR_REPLY qmrply;
+
+#endif // EFP_MIRRORING_ENABLED
+
+} Q_ENTRY, *PQ_ENTRY;
+
+
+//
+// EFP Command Queue definition (for both mailbox and device command queues)
+//
+// Note: this structure need to be ULONG algned!
+//
+
+typedef struct _EFP_COMMAND_QUEUE {
+ UCHAR Cmd_Q_Get; // get pointer
+ UCHAR Cmd_Q_Res1; // reserved for future use
+ UCHAR Cmd_Q_Put; // put pointer
+ UCHAR Cmd_Q_Res2; // reserved for future use
+ Q_ENTRY Cmd_Entries[COMMAND_Q_ENTRIES];
+} EFP_COMMAND_QUEUE, *PCOMMAND_QUEUE;
+
+//
+// Used by DevicesPresent array to record which devices are attached,
+// and to aid in mapping Target/Lun (TarLun) to queue number.
+//
+
+typedef struct _TAR_Q {
+ BOOLEAN present;
+ UCHAR qnumber;
+ PCOMMAND_QUEUE qPtr;
+
+#if EFP_MIRRORING_ENABLED
+
+ BOOLEAN KnownError; // TRUE=error already logged
+ EFP_FT_TYPE Type; // Mirroring type
+ EFP_FT_MEMBER_STATE SourceDiskState; // Source disk state
+ EFP_FT_MEMBER_STATE MirrorDiskState; // Mirror disk state
+
+#endif // EFP_MIRRORING_ENABLED
+
+} TAR_Q, *PTAR_Q;
+
+
+//
+// <----- EFP QUEUE STRUCTURES section ends
+//
+
+
+//
+// Scatter Gather descriptor
+//
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Address;
+ ULONG Length;
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+//
+// Scatter Gather descriptor list (SGL)
+//
+// YCT - we may reduce the size of MAXIMUM_SGL_DESCRITORS, adjust it later.
+
+typedef struct _SG_LIST { // KMK ??
+ SG_DESCRIPTOR Descriptor[MAXIMUM_SGL_DESCRIPTORS];
+} SG_LIST, *PSG_LIST;
+
+#pragma pack(1)
+
+typedef struct _CCB { // KMK ?? Compare to our old definition
+ // We may not need this. Revisit.
+ //
+ // This first portion is the structure expected by the ESC-1.
+ // Its size is CCB_FIXED_LENGTH and does NOT include the variable
+ // length field Cdb (which can be 6, 10 or 12 bytes long).
+ //
+
+ UCHAR TaskId; // CCB byte 0 (bits 7-6: xfer dir;
+ // bits 5-3: target ID;
+ // bits 2-0: LUN)
+ UCHAR CdbLength; // CCB byte 1 SCSI Command Descriptor
+ // Block length
+ ULONG DataLength; // CCB bytes 2-5 Total data transfer
+ // length
+ ULONG DataAddress; // CCB bytes 6-9 Data segment address
+ ULONG AdditionalRequestBlockLength; // CCB bytes 10-13 Length of the
+ // scatter/gather list
+ ULONG LinkedCommandAddress; // CCB bytes 14-17 Not used
+ UCHAR Cdb[12]; // CCB bytes 18-29 SCSI Command
+ // Descriptor Block
+ //
+ // The following portion is for the miniport driver use only
+ //
+
+ //PVOID SrbAddress; // Address of the related SRB
+ //EFP_SGL Sgl; // Scatter/gather data segment list
+
+} CCB, *PCCB;
+
+#pragma pack()
+
+
+//
+// The first portion is the default EFP 32 byte command structure ( not
+// including the LSG command which is 64 bytes). The SrbAddress and Sgl
+// are needed for command reference.
+//
+typedef struct _EFP_SGL { // SRB extension for EFP command and SGL
+ Q_ENTRY EfpCmd;
+ PVOID SrbAddress; // address of the associated SRB
+ SG_LIST Sgl; // Scatter/Gather data segment list
+ USHORT SGCount; // SG descriptor count
+ PSCSI_REQUEST_BLOCK NextSrb; // linked unprocessed SRB entry
+ USHORT QueueControl; // SRB queue control field
+
+ CCB pCCB; // for RESET_TARGET ( Abort) command
+} EFP_SGL, *PEFP_SGL;
+
+
+//
+// ESC-1 Command Control Block (byte-aligned)
+//
+
+// KMK Here's our old definition, for comparison...
+//** Command control block structure (CCB)
+//typedef struct _CCB {
+// UCHAR CCB_xfer; // targetID/LUN/direction
+// UCHAR CCB_scsilgt; // SCSI command length
+// ULONG CCB_datalen; // data length
+// ULONG CCB_address; // data address
+// ULONG CCB_SG_lgt; // scatter/gather block length
+// ULONG CCB_nextcmd; // linked command address
+// ICDB CCB_cdb; // CDB area
+//} CCB;
+
+//
+// This structure is allocated on a per logical unit basis. It is necessary
+// for the Abort request handling.
+//
+
+typedef struct _LU_EXTENSION { // KMK ??
+ SHORT NumberOfPendingRequests; // Number of SRBs for a logical unit
+} LU_EXTENSION, *PLU_EXTENSION;
+
+
+//
+// The following structure is allocated from noncached memory, which
+// we can only allocate once per adapter, and can not de-allocate.
+// We use this area for the EFP command and reply queues, and associated
+// overhead.
+//
+
+typedef struct _NONCACHED_EXTENSION {
+
+ //
+ // EFP Get Configuration returned information; index: 0 to (maxdevs-1)
+ //
+
+ GET_CONF GetConfigInfo[HA_QUEUES - 1]; // entry #0 = 1st device info
+
+ //
+ // EFP Queues Descriptor
+ //
+
+ QD_HEAD QD_Head; // EFP Queues Descriptor head
+ QD_BODY QD_Bodies[HA_QUEUES]; // EFP Q Desc. body strucs; index:Q#
+
+ //
+ // EFP Reply Queue (one reply queue per host adapter)
+ //
+
+ Q_ENTRY Reply_Q[REPLY_Q_ENTRIES];
+
+ //
+ // EFP Command Queue
+ //
+
+ EFP_COMMAND_QUEUE Command_Qs[1];
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ PEISA_CONTROLLER EisaController; // SCSI I/O address
+ PNONCACHED_EXTENSION NoncachedExt; // address of the uncached extension
+ // used for EFP cmd and reply queues.
+ //
+ // Physical address of the queues descriptor
+ //
+
+ ULONG QueuesDescriptor_PA;
+
+ // Device Present array: maps which devices are connected to the
+ // controller, as reported by Get Configuration (this information can
+ // be extracted from GetConfigInfo, but is more easily accessed in this
+ // form). The TAR_Q structure also provides a field that maps the device
+ // to the corresponding device queue.
+ //
+ // Entries should be accessed by TarLun . The first entry is therefore
+ // vacant.
+ //
+
+ TAR_Q DevicesPresent[HA_QUEUES];
+
+ //
+ // General configuration information
+ //
+
+ BOOLEAN Esc2; // Controller type
+ UCHAR NumberOfBuses; // number of SCSI buses
+ BOOLEAN CfgRegsPresent[CFG_REGS_NUMBER];
+ UCHAR CfgRegs[CFG_REGS_NUMBER];
+ UCHAR IRQ_In_Use; // the IRQ used by this host adapter
+
+ //
+ // Reset variables.
+ //
+
+ ULONG ResetInProgress; // >0 if reset is in progress.
+ ULONG ResetTimerCalls; // # of timer calls before time-out.
+ ULONG ResetNotification; // Reset notification trigger.
+
+ //
+ // Enqueue/dequeue information.
+ //
+
+ Q_ENTRY Q_Buf; // scratch space for building an EFP
+ // command queue element
+ UCHAR Q_Full_Map[HA_QUEUES]; // cmd q full (1=full,0=not) index: q #
+ UCHAR Reply_Q_Full_Flag;
+ UCHAR Reply_Q_Get; // Get pointer for reply queue
+ UCHAR RQ_In_Process; // reply queue in process flag
+
+ USHORT TotalAttachedDevices; // number of SCSI devices attached to ctrl
+
+ //
+ // EFP interface's Get Information returned data
+ //
+
+ UCHAR FW_Rel[3]; // byte2: major; b1: minor*10; b0:minor
+ UCHAR SCSI_Level; // SCSI level supported by controller
+ UCHAR Adapter_ID[MAX_HAIDS]; // controller IDs on SCSI buses
+ UCHAR Link_Cmd; // ctrl's constraints on linked cmds
+ UCHAR Max_CmdQ_ents; // the max # 32-byte entries per queue
+
+#if EFP_MIRRORING_ENABLED
+
+ UCHAR Environment; // define the mirroring environment.
+
+#endif // EFP_MIRRORING_ENABLED
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+//
+// The following structures are used to pass information between phase #0
+// and phase #1 of the "FindAdapter" process.
+//
+
+typedef struct _SCSI_INFO {
+
+ UCHAR AdapterPresent; // 0 = adapter not found or in error
+ UCHAR Reserved; // To be defined!
+ USHORT NumberOfDevices; // # of SCSI devices on the adapter
+
+} SCSI_INFO, *PSCSI_INFO;
+
+
+typedef struct _ESC2_CONTEXT {
+
+ UCHAR CheckedSlot; // EISA slot number checked
+ UCHAR Phase; // phase #0 or #1
+
+ SCSI_INFO ScsiInfo[MAX_EISA_SLOTS_STD];
+
+} ESC2_CONTEXT, *PESC2_CONTEXT;
+
+#if EFP_MIRRORING_ENABLED
+
+//
+// NOTE: the following struct doesn't belong to this file!
+//
+
+//
+// Define header for I/O control SRB.
+//
+
+typedef struct _SRB_IO_CONTROL {
+ ULONG HeaderLength;
+ UCHAR Signature[8];
+ ULONG Timeout;
+ ULONG ControlCode;
+ ULONG ReturnCode;
+ ULONG Length;
+} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
+
+#endif // EFP_MIRRORING_ENABLED
diff --git a/private/ntos/miniport/oliscsi/oliscsi.rc b/private/ntos/miniport/oliscsi/oliscsi.rc
new file mode 100644
index 000000000..51a9fecd3
--- /dev/null
+++ b/private/ntos/miniport/oliscsi/oliscsi.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Olivetti SCSI Controllers Driver"
+#define VER_INTERNALNAME_STR "oliscsi.sys"
+#define VER_ORIGINALFILENAME_STR "oliscsi.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/oliscsi/sources b/private/ntos/miniport/oliscsi/sources
new file mode 100644
index 000000000..993669102
--- /dev/null
+++ b/private/ntos/miniport/oliscsi/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=oliscsi
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=oliesc1.c oliesc2.c oliscsi.rc
diff --git a/private/ntos/miniport/qlogic/isp_fw.c b/private/ntos/miniport/qlogic/isp_fw.c
new file mode 100644
index 000000000..f74347cc4
--- /dev/null
+++ b/private/ntos/miniport/qlogic/isp_fw.c
@@ -0,0 +1,1245 @@
+
+/*
+ * Version 1.27 (18:17 April 18, 1995)
+ */
+
+unsigned short risc_code_version = 1*1024+27;
+
+unsigned short risc_code_addr01 = 0x1000 ;
+
+unsigned short risc_code01[] = {
+ 0x0078, 0x102f, 0x0000, 0x267b, 0x0000, 0x2043, 0x4f50, 0x5952,
+ 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31,
+ 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320,
+ 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350,
+ 0x3130, 0x3230, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056,
+ 0x6572, 0x7369, 0x6f6e, 0x2030, 0x312e, 0x3237, 0x2020, 0x20b9,
+ 0x1212, 0x2071, 0x0010, 0x70c3, 0x0004, 0x20c9, 0x41ff, 0x2089,
+ 0x1143, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
+ 0x0001, 0x3f00, 0x70d6, 0x20c1, 0x0008, 0x2009, 0xfeff, 0x2100,
+ 0x2003, 0xa5a5, 0xa084, 0x7fff, 0x2003, 0x0a0a, 0xa084, 0x3fff,
+ 0x2003, 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040, 0x109f, 0x20c1,
+ 0x0000, 0x2100, 0x2003, 0xa5a5, 0xa084, 0x7fff, 0x2003, 0x0a0a,
+ 0xa084, 0x3fff, 0x2003, 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040,
+ 0x109f, 0x2019, 0x7fff, 0xa392, 0x41ff, 0x0048, 0x109f, 0x20c1,
+ 0x0008, 0x2009, 0x7fff, 0x2100, 0x2003, 0x0a0a, 0xa084, 0x3fff,
+ 0x2003, 0x5050, 0x2114, 0xa286, 0x0a0a, 0x0040, 0x1092, 0x2019,
+ 0x3fff, 0xa392, 0x41ff, 0x0048, 0x1092, 0x20c1, 0x0004, 0x2009,
+ 0x3fff, 0x200b, 0x5050, 0x2114, 0xa286, 0x5050, 0x0040, 0x1092,
+ 0x0078, 0x114b, 0x98c0, 0xa188, 0x1000, 0x200b, 0xa5a5, 0x2114,
+ 0xa286, 0xa5a5, 0x0040, 0x109f, 0xa18a, 0x1000, 0x98c1, 0x2130,
+ 0xa18a, 0x0040, 0x2128, 0xa1a2, 0x3700, 0x8424, 0x8424, 0x8424,
+ 0x8424, 0x8424, 0x8424, 0xa192, 0x4200, 0x2009, 0x0000, 0x2001,
+ 0x002f, 0x1078, 0x19d8, 0x2218, 0x2079, 0x3700, 0x2fa0, 0x2408,
+ 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10ba,
+ 0x7eda, 0x7dce, 0x8528, 0x7dca, 0x7cd2, 0x7bd6, 0x2031, 0x0030,
+ 0x78b3, 0x0101, 0x780b, 0x0002, 0x780f, 0x0002, 0x784f, 0x0003,
+ 0x2069, 0x3740, 0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa,
+ 0x680f, 0x0008, 0x6813, 0x0005, 0x681f, 0x0000, 0x6823, 0x0006,
+ 0x6817, 0x0008, 0x6827, 0x0000, 0x2069, 0x3800, 0x2011, 0x0020,
+ 0x2009, 0x0010, 0x680b, 0x0c19, 0x680f, 0x0019, 0x6803, 0xfd00,
+ 0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004,
+ 0x8109, 0x00c0, 0x10ea, 0x2069, 0x3880, 0x20a9, 0x0080, 0x680b,
+ 0x0040, 0x7bd8, 0xa386, 0xfeff, 0x00c0, 0x110c, 0x6817, 0x0100,
+ 0x681f, 0x0064, 0x0078, 0x1110, 0x6817, 0x0064, 0x681f, 0x0002,
+ 0xade8, 0x0010, 0x0070, 0x1116, 0x0078, 0x10ff, 0x1078, 0x1c6a,
+ 0x1078, 0x319f, 0x1078, 0x1818, 0x1078, 0x363d, 0x3200, 0xa085,
+ 0x000d, 0x2090, 0x70c3, 0x0000, 0x0090, 0x112d, 0x70c0, 0xa086,
+ 0x0002, 0x00c0, 0x112d, 0x1078, 0x1262, 0x1078, 0x116e, 0x78b0,
+ 0xa005, 0x00c0, 0x1139, 0x1078, 0x19ff, 0x0068, 0x113d, 0x1078,
+ 0x1bc6, 0x0068, 0x113d, 0x1078, 0x190b, 0x00e0, 0x112d, 0x1078,
+ 0x34db, 0x0078, 0x112d, 0x114b, 0x114d, 0x1e10, 0x1e10, 0x31ff,
+ 0x31ff, 0x1e10, 0x1e10, 0x0078, 0x114b, 0x0078, 0x114d, 0x0078,
+ 0x114f, 0x0078, 0x1151, 0x2009, 0x0022, 0x2104, 0xa086, 0x4000,
+ 0x0040, 0x1169, 0x7008, 0x800b, 0x00c8, 0x1169, 0x7007, 0x0002,
+ 0xa08c, 0x0060, 0x00c0, 0x116a, 0xa084, 0x0008, 0x0040, 0x1169,
+ 0x087a, 0x097a, 0x70c3, 0x4002, 0x0078, 0x1265, 0x2061, 0x0000,
+ 0x6018, 0xa084, 0x0001, 0x00c0, 0x11df, 0x7814, 0xa005, 0x00c0,
+ 0x117d, 0x0010, 0x11e0, 0x0078, 0x11df, 0x2009, 0x3768, 0x2104,
+ 0xa005, 0x00c0, 0x11df, 0x2009, 0x3771, 0x200b, 0x0000, 0x7914,
+ 0xa186, 0x0042, 0x00c0, 0x11a2, 0x7816, 0x2009, 0x376f, 0x2164,
+ 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca, 0x611c, 0xa18c,
+ 0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce, 0x1078, 0x180a,
+ 0x0078, 0x11dd, 0x7814, 0xa086, 0x0018, 0x00c0, 0x11a9, 0x1078,
+ 0x15ba, 0x7817, 0x0000, 0x2009, 0x376f, 0x2104, 0xa065, 0x0040,
+ 0x11cd, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x186a, 0x0c7f, 0x609f,
+ 0x0000, 0x2009, 0x376a, 0x211c, 0x8108, 0x2114, 0x8108, 0x2104,
+ 0xa210, 0xa399, 0x0000, 0x2009, 0x001c, 0x6087, 0x0103, 0x1078,
+ 0x1791, 0x00c0, 0x11d9, 0x1078, 0x180a, 0x2009, 0x376f, 0x200b,
+ 0x0000, 0x2009, 0x3769, 0x2104, 0x200b, 0x0000, 0xa005, 0x0040,
+ 0x11dd, 0x2001, 0x4005, 0x0078, 0x1264, 0x0078, 0x1262, 0x007c,
+ 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000, 0x70cf, 0x0000,
+ 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1230, 0x2038, 0x0079, 0x11f0,
+ 0x1262, 0x12bb, 0x127f, 0x12bb, 0x1324, 0x1324, 0x1276, 0x1695,
+ 0x132f, 0x126e, 0x1283, 0x1285, 0x1287, 0x1289, 0x169a, 0x126e,
+ 0x133f, 0x136a, 0x15d2, 0x168f, 0x128b, 0x1532, 0x1554, 0x156a,
+ 0x1587, 0x14ef, 0x14fd, 0x1511, 0x1525, 0x13dd, 0x126e, 0x138b,
+ 0x1391, 0x1396, 0x139b, 0x13a1, 0x13a6, 0x13ab, 0x13b0, 0x13b5,
+ 0x13b9, 0x13ce, 0x13da, 0x126e, 0x126e, 0x126e, 0x126e, 0x13e9,
+ 0x13f2, 0x1401, 0x1427, 0x1431, 0x1438, 0x145e, 0x146d, 0x147c,
+ 0x148e, 0x14cf, 0x14df, 0x126e, 0x126e, 0x126e, 0x126e, 0x14e4,
+ 0xa0bc, 0xffa0, 0x00c0, 0x126e, 0x2038, 0xa084, 0x001f, 0x0079,
+ 0x1239, 0x16b1, 0x16b4, 0x16c4, 0x1740, 0x1779, 0x126e, 0x126e,
+ 0x126e, 0x126e, 0x126e, 0x126e, 0x126e, 0x126e, 0x126e, 0x126e,
+ 0x126e, 0x12b1, 0x131a, 0x1335, 0x1360, 0x15c8, 0x126e, 0x126e,
+ 0x126e, 0x126e, 0x126e, 0x126e, 0x126e, 0x126e, 0x126e, 0x126e,
+ 0x126e, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x1264, 0x73ce,
+ 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x2061, 0x0000, 0x601b,
+ 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c, 0x70c3, 0x4001,
+ 0x0078, 0x1265, 0x70c3, 0x4006, 0x0078, 0x1265, 0x2099, 0x0041,
+ 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078, 0x1262, 0x70c4,
+ 0x70c3, 0x0004, 0x007a, 0x0078, 0x1262, 0x0078, 0x1262, 0x0078,
+ 0x1262, 0x0078, 0x1262, 0x2091, 0x8000, 0x70c3, 0x0000, 0x70c7,
+ 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0001, 0x3f00,
+ 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031, 0x0030, 0x2059,
+ 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061, 0x0472, 0x20b9,
+ 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091, 0x4080, 0x0078,
+ 0x0455, 0x1078, 0x1978, 0x00c0, 0x1272, 0x75d8, 0x74dc, 0x75da,
+ 0x74de, 0x0078, 0x12be, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8,
+ 0x73cc, 0x70c4, 0x20a0, 0x2098, 0x2031, 0x0030, 0x81ff, 0x0040,
+ 0x1262, 0x7007, 0x0004, 0x731a, 0x721e, 0x7422, 0x7526, 0x2051,
+ 0x0012, 0x2049, 0x12f9, 0x2041, 0x1262, 0x7003, 0x0002, 0xa786,
+ 0x0001, 0x0040, 0x12e1, 0xa786, 0x0050, 0x0040, 0x12e1, 0x0078,
+ 0x12e7, 0x2049, 0x1306, 0x2041, 0x1312, 0x7003, 0x0003, 0x7017,
+ 0x0000, 0x810b, 0x7112, 0x00c8, 0x12ef, 0x7017, 0x0001, 0x7007,
+ 0x0001, 0xa786, 0x0001, 0x0040, 0x1306, 0xa786, 0x0050, 0x0040,
+ 0x1306, 0x700c, 0xa084, 0x007f, 0x2009, 0x0040, 0xa102, 0x8004,
+ 0x094a, 0x20a8, 0x26a0, 0x53a6, 0x0078, 0x1153, 0x700c, 0xa084,
+ 0x007f, 0x0040, 0x1306, 0x80ac, 0x0048, 0x1306, 0x2698, 0x53a5,
+ 0x0078, 0x1153, 0x700c, 0xa084, 0x007f, 0x80ac, 0x2698, 0x53a5,
+ 0x0078, 0x1262, 0x1078, 0x1978, 0x00c0, 0x1272, 0x75d8, 0x74dc,
+ 0x75da, 0x74de, 0x0078, 0x12be, 0x71c4, 0x70c8, 0x2114, 0xa79e,
+ 0x0004, 0x00c0, 0x132c, 0x200a, 0x72ca, 0x0078, 0x1261, 0x70c7,
+ 0x0001, 0x70cb, 0x001b, 0x0078, 0x1262, 0x1078, 0x1978, 0x00c0,
+ 0x1272, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1342, 0x2029,
+ 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca,
+ 0x73ce, 0x74d2, 0xa005, 0x0040, 0x135a, 0x8001, 0x787a, 0x7a82,
+ 0x7b86, 0x7d8a, 0x7e8e, 0x7c7e, 0x78b0, 0xa084, 0xfffc, 0x78b2,
+ 0x0078, 0x135e, 0x78b0, 0xa085, 0x0001, 0x78b2, 0x0078, 0x1262,
+ 0x1078, 0x1978, 0x00c0, 0x1272, 0x75d8, 0x76dc, 0x75da, 0x76de,
+ 0x0078, 0x136d, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc,
+ 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x1385,
+ 0x8001, 0x7896, 0x7a9e, 0x7ba2, 0x7da6, 0x7eaa, 0x7c9a, 0x78b0,
+ 0xa084, 0xfcff, 0x78b2, 0x0078, 0x1389, 0x78b0, 0xa085, 0x0100,
+ 0x78b2, 0x0078, 0x1262, 0x2009, 0x375b, 0x210c, 0x7ad4, 0x0078,
+ 0x1260, 0x2009, 0x3741, 0x210c, 0x0078, 0x1261, 0x2009, 0x3742,
+ 0x210c, 0x0078, 0x1261, 0x2061, 0x3740, 0x610c, 0x6210, 0x0078,
+ 0x1260, 0x2009, 0x3745, 0x210c, 0x0078, 0x1261, 0x2009, 0x3746,
+ 0x210c, 0x0078, 0x1261, 0x2009, 0x3747, 0x210c, 0x0078, 0x1261,
+ 0x2009, 0x3748, 0x210c, 0x0078, 0x1261, 0x7908, 0x7a0c, 0x0078,
+ 0x1260, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003,
+ 0xa0e8, 0x3800, 0x6a00, 0x6804, 0xa084, 0x0008, 0x0040, 0x13cb,
+ 0x6b08, 0x0078, 0x13cc, 0x6b0c, 0x0078, 0x125f, 0x77c4, 0x1078,
+ 0x1828, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708,
+ 0x0078, 0x125f, 0x794c, 0x0078, 0x1261, 0x77c4, 0x1078, 0x1828,
+ 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091, 0x8001, 0x0078,
+ 0x125f, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x125a, 0x1078, 0x1cf0,
+ 0x0078, 0x125f, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x125a, 0x2011,
+ 0x3741, 0x2204, 0x007e, 0x2112, 0x1078, 0x1ca9, 0x017f, 0x0078,
+ 0x1261, 0x71c4, 0x2011, 0x141f, 0x20a9, 0x0008, 0x2204, 0xa106,
+ 0x0040, 0x1411, 0x8210, 0x0070, 0x140f, 0x0078, 0x1406, 0x0078,
+ 0x125a, 0xa292, 0x141f, 0x027e, 0x2011, 0x3742, 0x2204, 0x2112,
+ 0x017f, 0x007e, 0x1078, 0x1cb5, 0x017f, 0x0078, 0x1261, 0x03e8,
+ 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061,
+ 0x3740, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8, 0x6012, 0x0078,
+ 0x1260, 0x2061, 0x3740, 0x6114, 0x70c4, 0x6016, 0x0078, 0x1261,
+ 0x71c4, 0x2011, 0x0004, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040,
+ 0x1451, 0x2011, 0x0005, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040,
+ 0x1451, 0x2011, 0x0006, 0x2019, 0x2323, 0xa186, 0x003c, 0x00c0,
+ 0x125a, 0x2061, 0x3740, 0x6018, 0x007e, 0x611a, 0x23b8, 0x1078,
+ 0x1cc6, 0x1078, 0x363d, 0x017f, 0x0078, 0x1261, 0x71c4, 0xa184,
+ 0xffcf, 0x00c0, 0x125a, 0x2011, 0x3747, 0x2204, 0x2112, 0x007e,
+ 0x1078, 0x1ce8, 0x017f, 0x0078, 0x1261, 0x71c4, 0xa182, 0x0010,
+ 0x00c8, 0x125a, 0x2011, 0x3748, 0x2204, 0x007e, 0x2112, 0x1078,
+ 0x1cd7, 0x017f, 0x0078, 0x1261, 0x71c4, 0x72c8, 0xa184, 0xfffd,
+ 0x00c0, 0x1259, 0xa284, 0xfffd, 0x00c0, 0x1259, 0x2100, 0x7908,
+ 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x1260, 0x71c4, 0x8107,
+ 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x3800, 0x2019,
+ 0x0000, 0x72c8, 0x6800, 0x007e, 0xa226, 0x0040, 0x14bd, 0x6a02,
+ 0xa484, 0x2000, 0x0040, 0x14a6, 0xa39d, 0x0010, 0xa484, 0x1000,
+ 0x0040, 0x14ac, 0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x14bd,
+ 0x810f, 0xa284, 0x4000, 0x0040, 0x14b9, 0x1078, 0x1d0a, 0x0078,
+ 0x14bd, 0x1078, 0x1cfc, 0x0078, 0x14bd, 0x72cc, 0x82ff, 0x0040,
+ 0x14c8, 0x6808, 0xa206, 0x0040, 0x14c8, 0x6a0a, 0xa39d, 0x000a,
+ 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x0078, 0x125f, 0x77c4,
+ 0x1078, 0x1828, 0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001,
+ 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, 0x125f, 0x70c4,
+ 0x794c, 0x784e, 0x0078, 0x1261, 0x71c4, 0x72c8, 0x73cc, 0xa182,
+ 0x0010, 0x00c8, 0x125a, 0x1078, 0x1d18, 0x0078, 0x125f, 0x77c4,
+ 0x1078, 0x1828, 0x2091, 0x8000, 0x6a08, 0xa295, 0x0002, 0x6a0a,
+ 0x2091, 0x8001, 0x2708, 0x0078, 0x1260, 0x77c4, 0x1078, 0x1828,
+ 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005,
+ 0x0040, 0x150c, 0x1078, 0x1c4b, 0x2091, 0x8001, 0x2708, 0x0078,
+ 0x1260, 0x77c4, 0x1078, 0x1828, 0x2091, 0x8000, 0x6a08, 0xa295,
+ 0x0004, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1520, 0x1078, 0x1c4b,
+ 0x2091, 0x8001, 0x2708, 0x0078, 0x1260, 0x77c4, 0x2041, 0x0001,
+ 0x2049, 0x0005, 0x2051, 0x0020, 0x1078, 0x1835, 0x2708, 0x6a08,
+ 0x0078, 0x1260, 0x77c4, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce,
+ 0x1078, 0x18b0, 0x00c0, 0x1550, 0x6818, 0xa005, 0x0040, 0x154a,
+ 0x2708, 0x1078, 0x1d28, 0x00c0, 0x154a, 0x7817, 0x0015, 0x2091,
+ 0x8001, 0x007c, 0x2091, 0x8001, 0x2001, 0x4005, 0x0078, 0x1264,
+ 0x2091, 0x8001, 0x0078, 0x1262, 0x77c4, 0x77c6, 0x2061, 0x3740,
+ 0x60a3, 0x0003, 0x67b6, 0x60c7, 0x0005, 0x2041, 0x0021, 0x2049,
+ 0x0005, 0x2051, 0x0020, 0x1078, 0x1835, 0x7817, 0x0016, 0x1078,
+ 0x1c4b, 0x007c, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2061, 0x3740,
+ 0x60a3, 0x0002, 0x67b6, 0x60c7, 0x0005, 0x7817, 0x0017, 0x1078,
+ 0x1c4b, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x1078,
+ 0x1835, 0x8738, 0xa784, 0x0007, 0x00c0, 0x157f, 0x007c, 0x78b0,
+ 0xa084, 0x0003, 0x00c0, 0x15ab, 0x2039, 0x0000, 0x2041, 0x0021,
+ 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, 0x1828, 0x2091, 0x8000,
+ 0x6808, 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x0007,
+ 0x00c0, 0x1594, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784,
+ 0x0f00, 0x00c0, 0x1594, 0x7817, 0x0018, 0x2061, 0x3740, 0x60a3,
+ 0x0001, 0x60c7, 0x0005, 0x1078, 0x1c4b, 0x78b0, 0xa085, 0x0002,
+ 0x78b2, 0x007c, 0x78b0, 0xa084, 0xfffd, 0x78b2, 0xa084, 0x0001,
+ 0x00c0, 0x15c4, 0x1078, 0x18f2, 0x71c4, 0x71c6, 0x794a, 0x007c,
+ 0x1078, 0x1978, 0x00c0, 0x1272, 0x75d8, 0x74dc, 0x75da, 0x74de,
+ 0x0078, 0x15d5, 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8, 0x72cc,
+ 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x3700, 0x1078, 0x1801, 0x0040,
+ 0x167d, 0x20a9, 0x0005, 0x20a1, 0x3716, 0x41a1, 0x2009, 0x0040,
+ 0x1078, 0x17cb, 0x0040, 0x15f0, 0x1078, 0x180a, 0x0078, 0x167d,
+ 0x6004, 0xa084, 0xff00, 0x8007, 0x8009, 0x0040, 0x1651, 0x0c7e,
+ 0x2c68, 0x1078, 0x1801, 0x0040, 0x1620, 0x2c00, 0x689e, 0x8109,
+ 0x00c0, 0x15f8, 0x609f, 0x0000, 0x0c7f, 0x0c7e, 0x7218, 0x731c,
+ 0x7420, 0x7524, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1650, 0x2009,
+ 0x0040, 0x1078, 0x17cb, 0x00c0, 0x1639, 0x6004, 0xa084, 0x00ff,
+ 0xa086, 0x0002, 0x00c0, 0x1620, 0x2d00, 0x6002, 0x0078, 0x1606,
+ 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x186a, 0x0c7f, 0x609f,
+ 0x0000, 0x1078, 0x1681, 0x2009, 0x001c, 0x6008, 0xa085, 0x0200,
+ 0x600a, 0x6004, 0x6086, 0x1078, 0x1791, 0x1078, 0x180a, 0x0078,
+ 0x167d, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x186a, 0x0c7f,
+ 0x609f, 0x0000, 0x1078, 0x1681, 0x2009, 0x001c, 0x6087, 0x0103,
+ 0x601b, 0x0003, 0x1078, 0x1791, 0x1078, 0x180a, 0x0078, 0x167d,
+ 0x0c7f, 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x7817, 0x0012, 0x0e7e,
+ 0x2071, 0x3740, 0x70a3, 0x0005, 0x70a7, 0x0000, 0x73aa, 0x72ae,
+ 0x74b2, 0x70b6, 0x70bb, 0x0000, 0x2c00, 0x70be, 0x70c3, 0x0000,
+ 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x1671, 0x1078,
+ 0x3143, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x669a, 0x60af, 0x0000,
+ 0x60b3, 0x0000, 0x1078, 0x1c4b, 0x007c, 0x70c3, 0x4005, 0x0078,
+ 0x1265, 0x20a9, 0x0005, 0x2099, 0x3716, 0x530a, 0x2100, 0xa210,
+ 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x71c4,
+ 0x70c7, 0x0000, 0x7906, 0x0078, 0x1262, 0x71c4, 0x71c6, 0x2168,
+ 0x0078, 0x169c, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, 0xa210,
+ 0x8d68, 0x8109, 0x00c0, 0x169e, 0xa285, 0x0000, 0x00c0, 0x16ac,
+ 0x70c3, 0x4000, 0x0078, 0x16ae, 0x70c3, 0x4003, 0x70ca, 0x0078,
+ 0x1265, 0x79c8, 0x0078, 0x1261, 0x71c4, 0x71c6, 0x2198, 0x20a1,
+ 0x0042, 0x20a9, 0x0004, 0x53a3, 0x21a0, 0x2099, 0x0042, 0x20a9,
+ 0x0004, 0x53a3, 0x0078, 0x1262, 0x70c4, 0x2068, 0x2079, 0x3700,
+ 0x1078, 0x1801, 0x0040, 0x173c, 0x6007, 0x0001, 0x600b, 0x0000,
+ 0x602b, 0x0000, 0x601b, 0x0006, 0x6a10, 0xa28c, 0x0007, 0xa284,
+ 0x00f0, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x6016, 0xa284,
+ 0x0800, 0x0040, 0x16e7, 0x601b, 0x000a, 0x0078, 0x16ed, 0xa284,
+ 0x1000, 0x0040, 0x16ed, 0x601b, 0x000c, 0xa284, 0x0300, 0x0040,
+ 0x16f6, 0x602b, 0x0001, 0x8004, 0x8004, 0x8004, 0xa085, 0x0001,
+ 0x601e, 0x6023, 0x0000, 0x6027, 0x000a, 0xa284, 0x0400, 0x0040,
+ 0x1703, 0x602b, 0x0000, 0x20a9, 0x0006, 0xac80, 0x000b, 0x20a0,
+ 0xad80, 0x0005, 0x2098, 0x53a3, 0xa284, 0x0300, 0x00c0, 0x1718,
+ 0x6046, 0x604a, 0x604e, 0x6052, 0x6096, 0x609a, 0x0078, 0x1722,
+ 0x6800, 0x6046, 0x6804, 0x604a, 0x6e08, 0x664e, 0x6d0c, 0x6552,
+ 0x6596, 0x669a, 0x6014, 0x7817, 0x0042, 0x2c08, 0x2061, 0x3740,
+ 0x60a3, 0x0005, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x60af, 0x0000,
+ 0x60b3, 0x0000, 0x60b6, 0x61be, 0xa284, 0x0400, 0x60c2, 0x1078,
+ 0x312e, 0x1078, 0x1c4b, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1265,
+ 0x78e0, 0xa005, 0x0040, 0x126e, 0x2091, 0x8000, 0x70c4, 0x800a,
+ 0x2011, 0x0010, 0x810c, 0x0048, 0x1752, 0x3a00, 0xa084, 0xfff7,
+ 0x0078, 0x1755, 0x3a00, 0xa085, 0x0008, 0x20d0, 0x0005, 0x0005,
+ 0xa084, 0xfffb, 0x20d0, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005,
+ 0x0005, 0x0005, 0x0005, 0xa085, 0x0004, 0x20d0, 0x0005, 0x0005,
+ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x8211, 0x00c0,
+ 0x174a, 0x3a00, 0xa085, 0x0008, 0x20d0, 0x2091, 0x8001, 0x0078,
+ 0x1262, 0x2011, 0x04fd, 0x2204, 0xa082, 0x0004, 0x0048, 0x178d,
+ 0x78e3, 0x0001, 0x2009, 0xff01, 0x200a, 0x2001, 0x000c, 0x20d8,
+ 0x2001, 0x000c, 0x20d0, 0x0078, 0x1262, 0x2001, 0x4005, 0x0078,
+ 0x1264, 0x700c, 0xa084, 0x00ff, 0x0040, 0x179d, 0x7007, 0x0004,
+ 0x7004, 0xa084, 0x0004, 0x00c0, 0x1798, 0x7017, 0x0000, 0x7112,
+ 0x721a, 0x731e, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, 0x810c,
+ 0x81a9, 0x8098, 0x20a1, 0x0030, 0x6084, 0x20a2, 0x53a6, 0x780c,
+ 0xa085, 0x0000, 0x7002, 0x7007, 0x0001, 0x2009, 0x0022, 0x2104,
+ 0xa084, 0x4000, 0x00c0, 0x17b5, 0x7108, 0x8103, 0x00c8, 0x17b5,
+ 0x7014, 0xa005, 0x0040, 0x17b5, 0x7007, 0x0002, 0xa184, 0x0060,
+ 0x7003, 0x0000, 0x007c, 0x700c, 0xa084, 0x00ff, 0x0040, 0x17d7,
+ 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x17d2, 0x7017,
+ 0x0000, 0x7112, 0x721a, 0x7422, 0x7526, 0x731e, 0x2099, 0x0030,
+ 0x8108, 0x81ac, 0x780c, 0xa085, 0x0001, 0x7002, 0x7007, 0x0001,
+ 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x17e8, 0x7008,
+ 0x800b, 0x00c8, 0x17e8, 0x7007, 0x0002, 0xa08c, 0x0060, 0x00c0,
+ 0x17fe, 0xac80, 0x0001, 0x20a0, 0x53a5, 0xa006, 0x7003, 0x0000,
+ 0x007c, 0x7850, 0xa065, 0x0040, 0x1809, 0x2c04, 0x7852, 0x2063,
+ 0x0000, 0x007c, 0x0f7e, 0x2079, 0x3700, 0x7850, 0x2062, 0x2c00,
+ 0xa005, 0x00c0, 0x1815, 0x1078, 0x1e01, 0x7852, 0x0f7f, 0x007c,
+ 0x2011, 0x4200, 0x7a52, 0x7bd4, 0x8319, 0x0040, 0x1825, 0xa280,
+ 0x002f, 0x2012, 0x2010, 0x0078, 0x181c, 0x2013, 0x0000, 0x007c,
+ 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, 0x8003, 0x8003,
+ 0x8003, 0xa105, 0xa0e8, 0x3880, 0x007c, 0x1078, 0x1828, 0x2900,
+ 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xffef, 0xa80d, 0x690a,
+ 0x2091, 0x8000, 0x2009, 0x374f, 0x210c, 0x6804, 0xa005, 0x0040,
+ 0x1852, 0xa116, 0x00c0, 0x1852, 0x2060, 0x6000, 0x6806, 0x017e,
+ 0x0078, 0x1855, 0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040,
+ 0x1864, 0x6000, 0x6806, 0x1078, 0x1877, 0x1078, 0x197e, 0x6810,
+ 0x8001, 0x6812, 0x00c0, 0x1855, 0x017f, 0x6902, 0x6906, 0x2091,
+ 0x8001, 0x007c, 0xa065, 0x0040, 0x1876, 0x609c, 0x609f, 0x0000,
+ 0x2008, 0x1078, 0x180a, 0x2100, 0x0078, 0x186a, 0x007c, 0x6007,
+ 0x0103, 0x20a9, 0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000,
+ 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022, 0x007c, 0x0e7e, 0x2071,
+ 0x3740, 0x7040, 0xa08c, 0x0080, 0x00c0, 0x1894, 0xa088, 0x3780,
+ 0x2d0a, 0x8000, 0x7042, 0xa006, 0x0e7f, 0x007c, 0x0e7e, 0x2071,
+ 0x3740, 0x2009, 0x3780, 0x7240, 0x8221, 0x8211, 0x0048, 0x18ae,
+ 0x2104, 0x8108, 0xad06, 0x00c0, 0x189d, 0x8119, 0x211e, 0x8108,
+ 0x8318, 0x8211, 0x00c8, 0x18a6, 0x7442, 0xa006, 0x0e7f, 0x007c,
+ 0x1078, 0x1828, 0x2091, 0x8000, 0x6804, 0x781e, 0xa065, 0x0040,
+ 0x18f1, 0x0078, 0x18c1, 0x2c00, 0x781e, 0x6000, 0xa065, 0x0040,
+ 0x18f1, 0x6010, 0xa306, 0x00c0, 0x18bb, 0x600c, 0xa206, 0x00c0,
+ 0x18bb, 0x2c28, 0x6804, 0xac06, 0x00c0, 0x18d8, 0x6000, 0x2060,
+ 0x6806, 0xa005, 0x00c0, 0x18d8, 0x6803, 0x0000, 0x0078, 0x18e2,
+ 0x6400, 0x781c, 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x18e2,
+ 0x2c00, 0x6802, 0x2560, 0x1078, 0x1877, 0x601b, 0x0005, 0x6023,
+ 0x0020, 0x1078, 0x197e, 0x6810, 0x8001, 0x6812, 0x2001, 0xffff,
+ 0xa005, 0x007c, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004,
+ 0x2051, 0x0008, 0x1078, 0x1835, 0x8738, 0xa784, 0x0007, 0x00c0,
+ 0x18fa, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00,
+ 0x00c0, 0x18fa, 0x007c, 0x2061, 0x0000, 0x6018, 0xa084, 0x0001,
+ 0x00c0, 0x191c, 0x2091, 0x8001, 0x78c4, 0x78c7, 0x0000, 0x2091,
+ 0x8001, 0xa005, 0x00c0, 0x191d, 0x007c, 0xa08c, 0xfff0, 0x0040,
+ 0x1923, 0x1078, 0x1e01, 0x0079, 0x1925, 0x1935, 0x1937, 0x193d,
+ 0x1941, 0x1935, 0x1945, 0x1935, 0x194c, 0x1950, 0x1954, 0x1935,
+ 0x1935, 0x1935, 0x1935, 0x1935, 0x1935, 0x1078, 0x1e01, 0x1078,
+ 0x18f2, 0x2001, 0x8001, 0x0078, 0x1264, 0x2001, 0x8003, 0x0078,
+ 0x1264, 0x2001, 0x8004, 0x0078, 0x1264, 0x1078, 0x18f2, 0x2001,
+ 0x8006, 0x007c, 0x0078, 0x1264, 0x2001, 0x8008, 0x0078, 0x1264,
+ 0x2001, 0x8009, 0x0078, 0x1264, 0x2091, 0x8000, 0x2069, 0x3740,
+ 0x6800, 0xa086, 0x0000, 0x0040, 0x1962, 0x2091, 0x8001, 0x78c7,
+ 0x0009, 0x007c, 0x68b4, 0xa0bc, 0xff00, 0x2091, 0x8000, 0x2041,
+ 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x1078, 0x1835, 0x8738,
+ 0xa784, 0x0007, 0x00c0, 0x196d, 0x2001, 0x800a, 0x0078, 0x1264,
+ 0x2001, 0x04fd, 0x2004, 0xa086, 0x0004, 0x007c, 0x6004, 0x6086,
+ 0x2c08, 0x2063, 0x0000, 0x786c, 0x8000, 0x786e, 0x7870, 0xa005,
+ 0x7972, 0x0040, 0x198e, 0x2c02, 0x0078, 0x198f, 0x7976, 0x007c,
+ 0x0c7e, 0x2061, 0x3700, 0x6887, 0x0103, 0x2d08, 0x206b, 0x0000,
+ 0x606c, 0x8000, 0x606e, 0x6070, 0xa005, 0x6172, 0x0040, 0x19a3,
+ 0x2d02, 0x0078, 0x19a4, 0x6176, 0x0c7f, 0x007c, 0x1078, 0x19b7,
+ 0x0040, 0x19b6, 0x0c7e, 0x609c, 0xa065, 0x0040, 0x19b1, 0x1078,
+ 0x186a, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x180a, 0x007c, 0x7874,
+ 0xa065, 0x0040, 0x19c9, 0x2091, 0x8000, 0x786c, 0x8001, 0x786e,
+ 0x2c04, 0x7876, 0xa005, 0x00c0, 0x19c7, 0x7872, 0x8000, 0x2091,
+ 0x8001, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e,
+ 0x00c8, 0x19d3, 0xa200, 0x00f0, 0x19ce, 0x8086, 0x818e, 0x007c,
+ 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x19f9, 0xa11a, 0x00c8,
+ 0x19f9, 0x8213, 0x818d, 0x0048, 0x19ec, 0xa11a, 0x00c8, 0x19ed,
+ 0x00f0, 0x19e1, 0x0078, 0x19f1, 0xa11a, 0x2308, 0x8210, 0x00f0,
+ 0x19e1, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f,
+ 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x19f5, 0x797c,
+ 0x70d0, 0xa106, 0x0040, 0x1a4d, 0x2091, 0x8000, 0x2071, 0x0020,
+ 0x7004, 0xa005, 0x00c0, 0x1a4d, 0x7008, 0x7208, 0xa206, 0x00c0,
+ 0x1a4d, 0xa084, 0x4000, 0x00c0, 0x1a4d, 0x2071, 0x0010, 0x1078,
+ 0x1801, 0x0040, 0x1a4d, 0x7a84, 0x7b80, 0x7c8c, 0x7d88, 0x8107,
+ 0x8004, 0x8004, 0xa210, 0xa399, 0x0000, 0x2009, 0x0040, 0x1078,
+ 0x17cb, 0x2091, 0x8001, 0x0040, 0x1a44, 0x1078, 0x180a, 0x7890,
+ 0x8000, 0x7892, 0xa086, 0x0002, 0x00c0, 0x1a4d, 0x2091, 0x8000,
+ 0x78c7, 0x0002, 0x7893, 0x0000, 0x78b0, 0xa085, 0x0003, 0x78b2,
+ 0x2091, 0x8001, 0x0078, 0x1a4d, 0x7893, 0x0000, 0x1078, 0x1b8f,
+ 0x6004, 0xa084, 0x000f, 0x0079, 0x1a52, 0x2071, 0x0010, 0x2091,
+ 0x8001, 0x007c, 0x1a62, 0x1a77, 0x1a9d, 0x1a62, 0x1aaf, 0x1a62,
+ 0x1a62, 0x1a62, 0x1a62, 0x1a71, 0x1a97, 0x1a62, 0x1a62, 0x1a62,
+ 0x1a62, 0x1a62, 0x2039, 0x0400, 0x78c0, 0xa705, 0x78c2, 0x6008,
+ 0xa705, 0x600a, 0x1078, 0x1aed, 0x609c, 0x78be, 0x1078, 0x1b77,
+ 0x007c, 0x1078, 0x1978, 0x00c0, 0x1a62, 0x1078, 0x1ba9, 0x78c0,
+ 0xa084, 0x0100, 0x0040, 0x1a7e, 0x0078, 0x1a62, 0x78c3, 0x0000,
+ 0x6004, 0x8007, 0xa084, 0x00ff, 0x78b6, 0x8001, 0x609f, 0x0000,
+ 0x0040, 0x1a94, 0x1078, 0x1aed, 0x0040, 0x1a94, 0x78c0, 0xa085,
+ 0x0100, 0x78c2, 0x0078, 0x1a96, 0x1078, 0x1b11, 0x007c, 0x1078,
+ 0x1978, 0x00c0, 0x1a62, 0x1078, 0x1ba5, 0x78c0, 0xa08c, 0x0e00,
+ 0x00c0, 0x1aa6, 0xa084, 0x0100, 0x00c0, 0x1aa8, 0x0078, 0x1a62,
+ 0x1078, 0x1aed, 0x00c0, 0x1aae, 0x1078, 0x1b11, 0x007c, 0x78c0,
+ 0xa084, 0x0100, 0x0040, 0x1ab6, 0x0078, 0x1a62, 0x78c3, 0x0000,
+ 0x6714, 0x20a9, 0x0001, 0x6018, 0xa005, 0x0040, 0x1ad1, 0xa7bc,
+ 0xff00, 0x20a9, 0x0008, 0xa08e, 0x0001, 0x0040, 0x1ad1, 0x2039,
+ 0x0000, 0x20a9, 0x0080, 0xa08e, 0x0002, 0x0040, 0x1ad1, 0x0078,
+ 0x1aea, 0x1078, 0x1828, 0x2d00, 0xa088, 0x0002, 0x2091, 0x8000,
+ 0x2168, 0x682b, 0x0000, 0x682f, 0x0000, 0x2104, 0xa084, 0xffde,
+ 0x200a, 0x2100, 0xa088, 0x0010, 0x2091, 0x8001, 0x0070, 0x1aea,
+ 0x0078, 0x1ad6, 0x1078, 0x180a, 0x007c, 0x78b8, 0xa06d, 0x00c0,
+ 0x1af8, 0x2c00, 0x78ba, 0x78be, 0x609f, 0x0000, 0x0078, 0x1b04,
+ 0x2c00, 0x689e, 0x609f, 0x0000, 0x78ba, 0x2d00, 0x6002, 0x78bc,
+ 0xad06, 0x00c0, 0x1b04, 0x6002, 0x78b4, 0x8001, 0x78b6, 0x00c0,
+ 0x1b10, 0x78c0, 0xa084, 0x0000, 0x78c2, 0x78bc, 0x2060, 0xa006,
+ 0x007c, 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0xf9ff, 0x601e,
+ 0xa184, 0x0060, 0x0040, 0x1b20, 0x0e7e, 0x1078, 0x3143, 0x0e7f,
+ 0x6596, 0x669a, 0x6714, 0x1078, 0x1828, 0x2091, 0x8000, 0x6808,
+ 0xa084, 0x0001, 0x0040, 0x1b3c, 0x2091, 0x8001, 0x1078, 0x1877,
+ 0x2091, 0x8000, 0x1078, 0x197e, 0x2091, 0x8001, 0x78bb, 0x0000,
+ 0x78bf, 0x0000, 0x0078, 0x1b76, 0x6024, 0xa096, 0x0001, 0x00c0,
+ 0x1b43, 0x8000, 0x6026, 0x6a10, 0x6814, 0x2091, 0x8001, 0xa202,
+ 0x0048, 0x1b52, 0x0040, 0x1b52, 0x2039, 0x0200, 0x1078, 0x1b77,
+ 0x0078, 0x1b76, 0x2c08, 0x2091, 0x8000, 0x6800, 0xa065, 0x0040,
+ 0x1b5a, 0x6102, 0x6902, 0x00c0, 0x1b5e, 0x6906, 0x2160, 0x6003,
+ 0x0000, 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808, 0xa08c,
+ 0x0040, 0x0040, 0x1b70, 0xa086, 0x0040, 0x680a, 0x1078, 0x1886,
+ 0x1078, 0x1c4b, 0x78bf, 0x0000, 0x78bb, 0x0000, 0x007c, 0x6008,
+ 0xa705, 0x600a, 0x2091, 0x8000, 0x1078, 0x197e, 0x2091, 0x8001,
+ 0x78bc, 0xa065, 0x0040, 0x1b8a, 0x609c, 0x78be, 0x609f, 0x0000,
+ 0x0078, 0x1b7a, 0x78bb, 0x0000, 0x78bf, 0x0000, 0x007c, 0x7978,
+ 0x787c, 0x8000, 0xa10a, 0x00c8, 0x1b96, 0xa006, 0x787e, 0x70d2,
+ 0x7804, 0xa005, 0x0040, 0x1ba4, 0x8001, 0x7806, 0x00c0, 0x1ba4,
+ 0x0068, 0x1ba4, 0x2091, 0x4080, 0x007c, 0x2039, 0x1bbd, 0x0078,
+ 0x1bab, 0x2039, 0x1bc3, 0x2704, 0xa005, 0x0040, 0x1bbc, 0xac00,
+ 0x2068, 0x6b08, 0x6c0c, 0x6910, 0x6a14, 0x690a, 0x6a0e, 0x6b12,
+ 0x6c16, 0x8738, 0x0078, 0x1bab, 0x007c, 0x0003, 0x0009, 0x000f,
+ 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x0068, 0x1bde,
+ 0x2029, 0x0000, 0x7874, 0xa065, 0x0040, 0x1bd9, 0x1078, 0x1bdf,
+ 0x0040, 0x1bd9, 0x1078, 0x1bee, 0x00c0, 0x1bd9, 0x8528, 0x0078,
+ 0x1bca, 0x85ff, 0x0040, 0x1bde, 0x2091, 0x4080, 0x007c, 0x7b94,
+ 0x7998, 0x70d4, 0xa102, 0x00c0, 0x1be8, 0x2300, 0xa005, 0x007c,
+ 0x0048, 0x1bec, 0xa302, 0x007c, 0x8002, 0x007c, 0x2091, 0x8000,
+ 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1c32, 0x7008, 0x7208,
+ 0xa206, 0x00c0, 0x1c32, 0xa084, 0x4000, 0x00c0, 0x1c32, 0x2071,
+ 0x0010, 0x1078, 0x1c37, 0x2009, 0x001c, 0x6028, 0xa005, 0x0040,
+ 0x1c0b, 0x2009, 0x0040, 0x1078, 0x1791, 0x0040, 0x1c24, 0x78ac,
+ 0x8000, 0x78ae, 0xa086, 0x0002, 0x00c0, 0x1c32, 0x2091, 0x8000,
+ 0x78c7, 0x0003, 0x78af, 0x0000, 0x78b0, 0xa085, 0x0300, 0x78b2,
+ 0x2091, 0x8001, 0x0078, 0x1c32, 0x78af, 0x0000, 0x1078, 0x19a6,
+ 0x7994, 0x7898, 0x8000, 0xa10a, 0x00c8, 0x1c2f, 0xa006, 0x789a,
+ 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x8107,
+ 0x8004, 0x8004, 0x7aa0, 0x7b9c, 0x7ca8, 0x7da4, 0xa210, 0xa399,
+ 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x2009, 0x3768,
+ 0x2091, 0x8000, 0x200a, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3740,
+ 0x2091, 0x8000, 0x2104, 0xa086, 0x0000, 0x00c0, 0x1c66, 0x2009,
+ 0x3712, 0x2104, 0xa005, 0x00c0, 0x1c66, 0x7830, 0xa084, 0x00c0,
+ 0x00c0, 0x1c66, 0x0018, 0x1c66, 0x781b, 0x0045, 0x2091, 0x8001,
+ 0x0f7f, 0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x3740, 0x2079,
+ 0x0100, 0x784b, 0x000f, 0x2019, 0x3041, 0x20a1, 0x012b, 0x2304,
+ 0xa005, 0x0040, 0x1c84, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398,
+ 0x53a6, 0x3318, 0x0078, 0x1c77, 0x789b, 0x0020, 0x20a9, 0x0010,
+ 0x78af, 0x0000, 0x78af, 0x0020, 0x0070, 0x1c90, 0x0078, 0x1c88,
+ 0x7003, 0x0000, 0x1078, 0x1d95, 0x7004, 0xa084, 0x000f, 0xa085,
+ 0x6280, 0x7806, 0x780f, 0x9200, 0x7843, 0x00d8, 0x7853, 0x0080,
+ 0x780b, 0x0008, 0x7047, 0x377f, 0x7043, 0x0000, 0x127f, 0x2000,
+ 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204, 0xa084, 0xfff0,
+ 0xa105, 0x2012, 0x1078, 0x1d95, 0x007c, 0x2011, 0x0101, 0x20a9,
+ 0x0009, 0x810b, 0x0070, 0x1cbe, 0x0078, 0x1cb9, 0xa18c, 0x0e00,
+ 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009, 0x0101,
+ 0x20a9, 0x0005, 0x8213, 0x0070, 0x1ccf, 0x0078, 0x1cca, 0xa294,
+ 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c, 0x2011,
+ 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, 0x1ce0, 0x0078, 0x1cdb,
+ 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x007c,
+ 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x007c,
+ 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, 0x609a,
+ 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022,
+ 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae,
+ 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061,
+ 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f, 0x007c,
+ 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100, 0x609a,
+ 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f, 0x007c,
+ 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040, 0x1d71, 0x2061, 0x4180,
+ 0x1078, 0x1d77, 0x0040, 0x1d5b, 0x20a9, 0x0000, 0x2061, 0x4080,
+ 0x0c7e, 0x1078, 0x1d77, 0x0040, 0x1d45, 0x0c7f, 0x8c60, 0x0070,
+ 0x1d43, 0x0078, 0x1d38, 0x0078, 0x1d71, 0x007f, 0xa082, 0x4080,
+ 0x2071, 0x3740, 0x70ba, 0x6020, 0xa085, 0x0800, 0x6022, 0x2091,
+ 0x8001, 0x71b6, 0x2001, 0x0004, 0x70a2, 0x70c7, 0x0005, 0x1078,
+ 0x1c46, 0x0078, 0x1d6d, 0x2071, 0x3740, 0x6020, 0xa085, 0x0800,
+ 0x6022, 0x2091, 0x8001, 0x71b6, 0x2c00, 0x70be, 0x2001, 0x0006,
+ 0x70a2, 0x70c7, 0x0005, 0x1078, 0x1c46, 0x2001, 0x0000, 0x0078,
+ 0x1d73, 0x2001, 0x0001, 0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2091,
+ 0x8000, 0x2c04, 0xa005, 0x0040, 0x1d90, 0x2060, 0x6010, 0xa306,
+ 0x00c0, 0x1d8d, 0x600c, 0xa206, 0x00c0, 0x1d8d, 0x6014, 0xa106,
+ 0x00c0, 0x1d8d, 0xa006, 0x0078, 0x1d94, 0x6000, 0x0078, 0x1d7a,
+ 0xa085, 0x0001, 0x2091, 0x8001, 0x007c, 0x2011, 0x3741, 0x220c,
+ 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084, 0x0100, 0x0040,
+ 0x1dab, 0x2021, 0xff00, 0x2122, 0x810b, 0x810b, 0x810b, 0x810b,
+ 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, 0x68e4, 0xa08c, 0x0020,
+ 0x0040, 0x1dff, 0xa084, 0x0006, 0x00c0, 0x1dff, 0x6014, 0x8007,
+ 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0, 0x3800, 0x7004,
+ 0xa084, 0x000a, 0x00c0, 0x1dff, 0x7108, 0xa194, 0xff00, 0x0040,
+ 0x1dff, 0xa18c, 0x00ff, 0x2001, 0x000c, 0xa106, 0x0040, 0x1de6,
+ 0x2001, 0x0012, 0xa106, 0x0040, 0x1dea, 0x2001, 0x0014, 0xa106,
+ 0x0040, 0x1dee, 0x2001, 0x0019, 0xa106, 0x0040, 0x1df2, 0x2001,
+ 0x0032, 0xa106, 0x0040, 0x1df6, 0x0078, 0x1dfa, 0x2009, 0x0012,
+ 0x0078, 0x1dfc, 0x2009, 0x0014, 0x0078, 0x1dfc, 0x2009, 0x0019,
+ 0x0078, 0x1dfc, 0x2009, 0x0020, 0x0078, 0x1dfc, 0x2009, 0x003f,
+ 0x0078, 0x1dfc, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, 0x0e7f,
+ 0x007c, 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002,
+ 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x1e0e,
+ 0x107e, 0x007e, 0x127e, 0x2091, 0x2300, 0x7f3c, 0x7e58, 0x7c30,
+ 0x7d38, 0x2009, 0x3774, 0x78a0, 0x200a, 0x8108, 0x250a, 0x8108,
+ 0x240a, 0x8108, 0x260a, 0x8108, 0x270a, 0xa594, 0x003f, 0xa484,
+ 0x4000, 0x0040, 0x1e31, 0xa784, 0x007c, 0x00c0, 0x2fcb, 0x1078,
+ 0x1e01, 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x1e39, 0x1078,
+ 0x1e01, 0x8507, 0xa084, 0x000f, 0x0079, 0x1e3e, 0x2272, 0x2311,
+ 0x232e, 0x2572, 0x27b6, 0x27f9, 0x2842, 0x28a0, 0x2908, 0x2995,
+ 0x1e66, 0x1e4e, 0x20db, 0x21a0, 0x2795, 0x1e4e, 0x1078, 0x1e01,
+ 0x0018, 0x1e15, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c,
+ 0x7003, 0x0000, 0x703f, 0x0000, 0x7030, 0xa005, 0x0040, 0x1e62,
+ 0x7033, 0x0000, 0x1078, 0x2fa6, 0x0018, 0x1e15, 0x2009, 0x370f,
+ 0x200b, 0x0000, 0x705c, 0xa005, 0x00c0, 0x1f2e, 0x70a0, 0xa084,
+ 0x0007, 0x0079, 0x1e73, 0x1f51, 0x1e7b, 0x1e89, 0x1ea4, 0x1ec4,
+ 0x1f0c, 0x1ee8, 0x1e7b, 0x7808, 0xa084, 0xfffd, 0x780a, 0x2009,
+ 0x0047, 0x1078, 0x269a, 0x00c0, 0x1e87, 0x7003, 0x0004, 0x0078,
+ 0x1e50, 0x1078, 0x2f8d, 0x00c0, 0x1ea2, 0x70b4, 0x8007, 0x7882,
+ 0x789b, 0x0010, 0x78ab, 0x000c, 0x789b, 0x0060, 0x78ab, 0x0001,
+ 0x785b, 0x0004, 0x2009, 0x00f8, 0x1078, 0x2698, 0x00c0, 0x1ea2,
+ 0x7003, 0x0004, 0x0078, 0x1e50, 0x1078, 0x2f8d, 0x00c0, 0x1ec2,
+ 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d,
+ 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002,
+ 0x785b, 0x0004, 0x2009, 0x00f8, 0x1078, 0x2698, 0x00c0, 0x1ec2,
+ 0x7003, 0x0004, 0x0078, 0x1e50, 0x1078, 0x2f8d, 0x00c0, 0x1ee6,
+ 0x71b4, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d,
+ 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x71b8, 0x79aa, 0x78ab, 0x000d,
+ 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009, 0x00f8,
+ 0x1078, 0x2698, 0x00c0, 0x1ee6, 0x7003, 0x0004, 0x0078, 0x1e50,
+ 0x1078, 0x2f8d, 0x00c0, 0x1f0a, 0x71b4, 0x8107, 0x789b, 0x0010,
+ 0xa18c, 0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b,
+ 0x0060, 0x78ab, 0x0002, 0x785b, 0x0004, 0x2009, 0x00f8, 0x1078,
+ 0x2698, 0x00c0, 0x1f0a, 0x70bc, 0x70bf, 0x0000, 0x2068, 0x703e,
+ 0x7003, 0x0002, 0x0078, 0x1e50, 0x1078, 0x2f8d, 0x00c0, 0x1e50,
+ 0x70bc, 0x2068, 0x1078, 0x302f, 0x789b, 0x0010, 0x6814, 0xa084,
+ 0x0007, 0xa085, 0x0080, 0x007e, 0x007f, 0x78aa, 0x6e1c, 0x067e,
+ 0x067f, 0x2041, 0x0001, 0x70c0, 0xa084, 0x0400, 0x2001, 0x0004,
+ 0x0040, 0x1f2c, 0x2001, 0x0006, 0x0078, 0x202d, 0x1078, 0x2f8d,
+ 0x00c0, 0x1e50, 0x789b, 0x0010, 0x705c, 0x2068, 0x1078, 0x302f,
+ 0x6f14, 0x1078, 0x2ed5, 0x6008, 0xa085, 0x0010, 0x600a, 0xad80,
+ 0x0009, 0x2003, 0x0005, 0x6814, 0xa084, 0x0007, 0xa085, 0x0080,
+ 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001, 0x0003, 0x0078,
+ 0x202d, 0x0018, 0x1e15, 0x7440, 0xa485, 0x0000, 0x0040, 0x1f6b,
+ 0xa080, 0x3780, 0x2030, 0x7144, 0x8108, 0xa12a, 0x0048, 0x1f62,
+ 0x2009, 0x3780, 0x2164, 0x6504, 0x85ff, 0x00c0, 0x1f78, 0x8421,
+ 0x00c0, 0x1f5c, 0x7146, 0x7003, 0x0000, 0x703f, 0x0000, 0x0078,
+ 0x1e50, 0x7640, 0xa6b0, 0x3780, 0x7144, 0x2600, 0x0078, 0x1f67,
+ 0x7146, 0x2568, 0x2558, 0x753e, 0x2c50, 0x6708, 0x7736, 0xa784,
+ 0x013f, 0x0040, 0x1fa5, 0xa784, 0x0021, 0x00c0, 0x1f75, 0xa784,
+ 0x0002, 0x0040, 0x1f92, 0xa784, 0x0004, 0x0040, 0x1f75, 0xa7bc,
+ 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0, 0x1f75, 0xa784, 0x0010,
+ 0x00c0, 0x1f75, 0xa784, 0x0100, 0x0040, 0x1fa5, 0x6018, 0xa005,
+ 0x00c0, 0x1f75, 0xa7bc, 0xfeff, 0x670a, 0x6823, 0x0000, 0x6e1c,
+ 0xa684, 0x000e, 0x6118, 0x0040, 0x1fb5, 0x601c, 0xa102, 0x0048,
+ 0x1fb8, 0x0040, 0x1fb8, 0x0078, 0x1f71, 0x81ff, 0x00c0, 0x1f71,
+ 0xa784, 0x0080, 0x00c0, 0x1fbe, 0x700c, 0x6022, 0x1078, 0x302f,
+ 0x0018, 0x1e15, 0x789b, 0x0010, 0xa046, 0x1078, 0x2f8d, 0x00c0,
+ 0x1e50, 0x6b14, 0xa39c, 0x0007, 0xa39d, 0x00c0, 0x704c, 0xa084,
+ 0x8000, 0x0040, 0x1fd7, 0xa684, 0x0001, 0x0040, 0x1fd9, 0xa39c,
+ 0xffbf, 0xa684, 0x0010, 0x0040, 0x1fdf, 0xa39d, 0x0020, 0x7baa,
+ 0x8840, 0xa684, 0x000e, 0x00c0, 0x1fea, 0xa7bd, 0x0010, 0x670a,
+ 0x0078, 0x202b, 0x714c, 0xa18c, 0x0800, 0x0040, 0x2b77, 0x2011,
+ 0x0021, 0x8004, 0x8004, 0x0048, 0x2001, 0x2011, 0x0022, 0x8004,
+ 0x0048, 0x2001, 0x2011, 0x0020, 0x8004, 0x0048, 0x2001, 0x0040,
+ 0x202b, 0x7aaa, 0x8840, 0x1078, 0x2fa6, 0x6a14, 0x610c, 0x8108,
+ 0xa18c, 0x00ff, 0xa1e0, 0x4080, 0x2c64, 0x8cff, 0x0040, 0x2022,
+ 0x6014, 0xa206, 0x00c0, 0x200c, 0x60b8, 0x8001, 0x60ba, 0x00c0,
+ 0x2007, 0x0c7e, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f,
+ 0x0078, 0x1f51, 0x1078, 0x2f8d, 0x00c0, 0x1e50, 0x2a60, 0x610e,
+ 0x79aa, 0x8840, 0x712e, 0x2001, 0x0001, 0x007e, 0x7150, 0xa184,
+ 0x0018, 0x0040, 0x2048, 0xa184, 0x0010, 0x0040, 0x203b, 0x1078,
+ 0x2d2d, 0x00c0, 0x2055, 0xa184, 0x0008, 0x0040, 0x2048, 0x69a0,
+ 0xa184, 0x0600, 0x00c0, 0x2048, 0x1078, 0x2c2b, 0x0078, 0x2055,
+ 0x69a0, 0xa184, 0x0200, 0x0040, 0x2051, 0x1078, 0x2c79, 0x0078,
+ 0x2055, 0xa184, 0x0400, 0x00c0, 0x2044, 0x007f, 0x7002, 0xa68c,
+ 0x0060, 0xa684, 0x0060, 0x0040, 0x2063, 0xa086, 0x0060, 0x00c0,
+ 0x2063, 0xa18d, 0x4000, 0x88ff, 0x0040, 0x2068, 0xa18d, 0x0004,
+ 0x795a, 0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061,
+ 0x6818, 0xa085, 0x8000, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040,
+ 0x2b82, 0xa18c, 0x00f8, 0x00c0, 0x2b82, 0x157e, 0x137e, 0x147e,
+ 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b,
+ 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882,
+ 0x6d94, 0x7dd6, 0x7dde, 0x6e98, 0x7ed2, 0x7eda, 0x7830, 0xa084,
+ 0x00c0, 0x00c0, 0x209d, 0x0098, 0x20a5, 0x6008, 0xa084, 0xffef,
+ 0x600a, 0x1078, 0x2fa6, 0x0078, 0x1e58, 0x7200, 0xa284, 0x0007,
+ 0xa086, 0x0001, 0x00c0, 0x20b2, 0x781b, 0x004a, 0x1078, 0x2fa6,
+ 0x0078, 0x20c3, 0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x004a,
+ 0x1078, 0x2fa6, 0x7200, 0x2500, 0xa605, 0x0040, 0x20c3, 0xa284,
+ 0x0007, 0x1079, 0x20d1, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0,
+ 0x1e50, 0x6018, 0x8000, 0x601a, 0xad80, 0x0009, 0x7032, 0x0078,
+ 0x1e50, 0x20d9, 0x33b6, 0x33b6, 0x33a5, 0x33b6, 0x20d9, 0x33a5,
+ 0x20d9, 0x1078, 0x1e01, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e,
+ 0x2079, 0x3700, 0x78b0, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x2101,
+ 0x70a0, 0xa086, 0x0001, 0x00c0, 0x20f0, 0x70a2, 0x0078, 0x2184,
+ 0x70a0, 0xa086, 0x0005, 0x00c0, 0x20ff, 0x70bc, 0x2068, 0x681b,
+ 0x0004, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x70a3,
+ 0x0000, 0x157e, 0x2011, 0x0004, 0x71a0, 0xa186, 0x0001, 0x0040,
+ 0x211f, 0xa186, 0x0007, 0x00c0, 0x2113, 0x2009, 0x3731, 0x200b,
+ 0x0005, 0x0078, 0x211f, 0x2009, 0x3713, 0x2104, 0x2009, 0x3712,
+ 0x200a, 0x2009, 0x3731, 0x200b, 0x0001, 0x0078, 0x2121, 0x70a3,
+ 0x0000, 0x1078, 0x312e, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078,
+ 0x2de4, 0xa7b8, 0x0100, 0x0070, 0x212f, 0x0078, 0x2127, 0x7000,
+ 0x0079, 0x2132, 0x2160, 0x2149, 0x2149, 0x213c, 0x2160, 0x2160,
+ 0x2160, 0x213a, 0x1078, 0x1e01, 0x2021, 0x3757, 0x2404, 0xa005,
+ 0x0040, 0x2160, 0xad06, 0x00c0, 0x2149, 0x6800, 0x2022, 0x0078,
+ 0x2159, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2155, 0x6f14, 0x1078,
+ 0x2ed5, 0x1078, 0x2b44, 0x0078, 0x2159, 0x7054, 0x2060, 0x6800,
+ 0x6002, 0x6a1a, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x1990,
+ 0x2021, 0x4180, 0x1078, 0x218a, 0x2021, 0x3757, 0x1078, 0x218a,
+ 0x20a9, 0x0000, 0x2021, 0x4080, 0x1078, 0x218a, 0x8420, 0x0070,
+ 0x2173, 0x0078, 0x216c, 0x20a9, 0x0080, 0x2061, 0x3880, 0x6018,
+ 0x6110, 0xa102, 0x6012, 0x601b, 0x0000, 0xace0, 0x0010, 0x0070,
+ 0x2183, 0x0078, 0x2177, 0x157f, 0x7003, 0x0000, 0x703f, 0x0000,
+ 0x0078, 0x1e50, 0x047e, 0x2404, 0xa005, 0x0040, 0x219c, 0x2068,
+ 0x6800, 0x007e, 0x6a1a, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078,
+ 0x1990, 0x007f, 0x0078, 0x218c, 0x047f, 0x2023, 0x0000, 0x007c,
+ 0xa282, 0x0003, 0x0050, 0x21a6, 0x1078, 0x1e01, 0x2300, 0x0079,
+ 0x21a9, 0x21ac, 0x2213, 0x2230, 0xa282, 0x0002, 0x0040, 0x21b2,
+ 0x1078, 0x1e01, 0x70a0, 0x70a3, 0x0000, 0x0079, 0x21b7, 0x21bf,
+ 0x21bf, 0x21c1, 0x21f3, 0x21f1, 0x21bf, 0x21f3, 0x21bf, 0x1078,
+ 0x1e01, 0x77b4, 0x1078, 0x2de4, 0x77b4, 0xa7bc, 0x0f00, 0x1078,
+ 0x2ed5, 0x6018, 0xa005, 0x0040, 0x21ea, 0x2021, 0x4180, 0x1078,
+ 0x224b, 0x0040, 0x21ea, 0x157e, 0x20a9, 0x0000, 0x2021, 0x4080,
+ 0x047e, 0x1078, 0x224b, 0x047f, 0x0040, 0x21e3, 0x8420, 0x0070,
+ 0x21e3, 0x0078, 0x21d8, 0x157f, 0x2021, 0x3757, 0x1078, 0x224b,
+ 0x0040, 0x21ea, 0x8738, 0xa784, 0x0007, 0x00c0, 0x21c7, 0x0078,
+ 0x1e58, 0x0078, 0x1e58, 0x77b4, 0x1078, 0x2ed5, 0x6018, 0xa005,
+ 0x0040, 0x2211, 0x2021, 0x4180, 0x1078, 0x224b, 0x0040, 0x2211,
+ 0x157e, 0x20a9, 0x0000, 0x2021, 0x4080, 0x047e, 0x1078, 0x224b,
+ 0x047f, 0x0040, 0x2210, 0x8420, 0x0070, 0x2210, 0x0078, 0x2205,
+ 0x157f, 0x0078, 0x1e58, 0x2200, 0x0079, 0x2216, 0x2219, 0x221b,
+ 0x221b, 0x1078, 0x1e01, 0x2009, 0x0012, 0x70a0, 0xa086, 0x0002,
+ 0x0040, 0x2224, 0x2009, 0x000e, 0x6818, 0xa084, 0x8000, 0x0040,
+ 0x222a, 0x691a, 0x70a3, 0x0000, 0x70a7, 0x0001, 0x0078, 0x2f58,
+ 0x2200, 0x0079, 0x2233, 0x2238, 0x221b, 0x2236, 0x1078, 0x1e01,
+ 0x1078, 0x26a7, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2b1a, 0x1078,
+ 0x2b5a, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2b0d, 0x0040,
+ 0x2b1a, 0x0078, 0x1f51, 0x2404, 0xa005, 0x0040, 0x226e, 0x2068,
+ 0x2d04, 0x007e, 0x6814, 0xa706, 0x0040, 0x225a, 0x2d20, 0x007f,
+ 0x0078, 0x224c, 0x007f, 0x2022, 0x681b, 0x0004, 0x6820, 0xa085,
+ 0x0010, 0x6822, 0x1078, 0x1990, 0x6010, 0x8001, 0x6012, 0x6008,
+ 0xa084, 0xffef, 0x600a, 0x1078, 0x2b5a, 0x007c, 0xa085, 0x0001,
+ 0x0078, 0x226d, 0x2300, 0x0079, 0x2275, 0x227a, 0x2278, 0x22c6,
+ 0x1078, 0x1e01, 0x78e4, 0xa005, 0x00d0, 0x228e, 0x0018, 0x228e,
+ 0xa084, 0x0007, 0x0079, 0x2284, 0x229f, 0x22ac, 0x2292, 0x228c,
+ 0x2f80, 0x2f80, 0x228c, 0x22b9, 0x1078, 0x1e01, 0x2001, 0x0003,
+ 0x0078, 0x2586, 0x6818, 0xa084, 0x8000, 0x0040, 0x2299, 0x681b,
+ 0x001d, 0x1078, 0x2dc7, 0x781b, 0x0053, 0x0078, 0x1e50, 0x6818,
+ 0xa084, 0x8000, 0x0040, 0x22a6, 0x681b, 0x001d, 0x1078, 0x2dc7,
+ 0x781b, 0x00db, 0x0078, 0x1e50, 0x6818, 0xa084, 0x8000, 0x0040,
+ 0x22b3, 0x681b, 0x001d, 0x1078, 0x2dc7, 0x781b, 0x00e2, 0x0078,
+ 0x1e50, 0x6818, 0xa084, 0x8000, 0x0040, 0x22c0, 0x681b, 0x001d,
+ 0x1078, 0x2dc7, 0x781b, 0x009c, 0x0078, 0x1e50, 0xa584, 0x000f,
+ 0x00c0, 0x22e5, 0x1078, 0x26a7, 0x7000, 0x0079, 0x22cf, 0x22d7,
+ 0x22d9, 0x22d7, 0x2b1a, 0x2b1a, 0x2b1a, 0x2b1a, 0x22d7, 0x1078,
+ 0x1e01, 0x1078, 0x2b5a, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078,
+ 0x2b0d, 0x0040, 0x2b1a, 0x0078, 0x1f51, 0x79e4, 0xa005, 0x00d0,
+ 0x228e, 0x0018, 0x228e, 0xa184, 0x0007, 0x0079, 0x22ef, 0x22ff,
+ 0x2305, 0x22f9, 0x22f7, 0x2f80, 0x2f80, 0x22f7, 0x2f78, 0x1078,
+ 0x1e01, 0x1078, 0x2dcf, 0x781b, 0x0053, 0x0078, 0x1e50, 0x1078,
+ 0x2dcf, 0x781b, 0x00db, 0x0078, 0x1e50, 0x1078, 0x2dcf, 0x781b,
+ 0x00e2, 0x0078, 0x1e50, 0x1078, 0x2dcf, 0x781b, 0x009c, 0x0078,
+ 0x1e50, 0x2300, 0x0079, 0x2314, 0x2319, 0x2317, 0x231b, 0x1078,
+ 0x1e01, 0x0078, 0x28a0, 0x681b, 0x0008, 0x78a3, 0x0000, 0x79e4,
+ 0xa184, 0x0007, 0x0079, 0x2324, 0x232c, 0x2305, 0x2292, 0x2f58,
+ 0x2f80, 0x2f80, 0x232c, 0x2f78, 0x1078, 0x1e01, 0xa282, 0x0005,
+ 0x0050, 0x2334, 0x1078, 0x1e01, 0x2300, 0x0079, 0x2337, 0x233a,
+ 0x2537, 0x2543, 0x2200, 0x0079, 0x233d, 0x2357, 0x2344, 0x2357,
+ 0x2342, 0x251c, 0x1078, 0x1e01, 0x789b, 0x0018, 0x78a8, 0xa084,
+ 0x00ff, 0xa082, 0x0020, 0x0048, 0x2db3, 0xa08a, 0x0004, 0x00c8,
+ 0x2db3, 0x0079, 0x2353, 0x2db3, 0x2db3, 0x2db3, 0x2d6d, 0x789b,
+ 0x0018, 0x79a8, 0xa184, 0x0080, 0x0040, 0x236c, 0xa184, 0x0018,
+ 0x0040, 0x2368, 0x0078, 0x2db3, 0x7000, 0xa005, 0x00c0, 0x2362,
+ 0x2011, 0x0004, 0x0078, 0x29a3, 0xa184, 0x00ff, 0xa08a, 0x0010,
+ 0x00c8, 0x2db3, 0x0079, 0x2374, 0x2386, 0x2384, 0x239e, 0x23a2,
+ 0x2433, 0x2db3, 0x2db3, 0x2435, 0x2db3, 0x2db3, 0x2518, 0x2518,
+ 0x2db3, 0x2db3, 0x2db3, 0x251a, 0x1078, 0x1e01, 0xa684, 0x1000,
+ 0x0040, 0x2393, 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, 0x781b,
+ 0x0099, 0x0078, 0x1e50, 0x6818, 0xa084, 0x8000, 0x0040, 0x239c,
+ 0x681b, 0x001d, 0x0078, 0x238a, 0x0078, 0x2f58, 0x681b, 0x001d,
+ 0x0078, 0x2dbf, 0x6920, 0xa184, 0x8000, 0x00c0, 0x23ae, 0x68af,
+ 0x0000, 0x68b3, 0x0000, 0xa18d, 0x8000, 0x6922, 0xa684, 0x1800,
+ 0x00c0, 0x23c6, 0x6820, 0xa084, 0x0001, 0x00c0, 0x23cc, 0x6818,
+ 0xa086, 0x0008, 0x00c0, 0x23be, 0x681b, 0x0000, 0xa684, 0x0400,
+ 0x0040, 0x242f, 0x781b, 0x0056, 0x0078, 0x1e50, 0xa684, 0x1000,
+ 0x0040, 0x23cc, 0x0078, 0x1e50, 0xa684, 0x0060, 0x0040, 0x242b,
+ 0xa684, 0x0800, 0x0040, 0x242b, 0xa684, 0x8000, 0x00c0, 0x23dc,
+ 0x69b0, 0x6aac, 0x0078, 0x23f6, 0xa6b4, 0x7fff, 0x7e5a, 0x6eb6,
+ 0x789b, 0x0074, 0x7aac, 0x79ac, 0x78ac, 0x801b, 0x00c8, 0x23e9,
+ 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100,
+ 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0xa684, 0x4000,
+ 0x0040, 0x23fe, 0xa6b4, 0xbfff, 0x7e5a, 0x6eb6, 0xa006, 0x1078,
+ 0x3474, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040,
+ 0x240d, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x6ba6,
+ 0x7bd6, 0x2300, 0xa405, 0x00c0, 0x241d, 0xa6b5, 0x4000, 0x7e5a,
+ 0x6eb6, 0x781b, 0x0065, 0x0078, 0x1e50, 0x781b, 0x0065, 0x2200,
+ 0xa115, 0x00c0, 0x2427, 0x1078, 0x33b6, 0x0078, 0x1e50, 0x1078,
+ 0x33eb, 0x0078, 0x1e50, 0x781b, 0x0068, 0x0078, 0x1e50, 0x781b,
+ 0x0056, 0x0078, 0x1e50, 0x1078, 0x1e01, 0x0078, 0x248a, 0x6920,
+ 0xa184, 0x0100, 0x0040, 0x2449, 0xa18c, 0xfeff, 0x6922, 0x0c7e,
+ 0x7048, 0x2060, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078,
+ 0x2479, 0xa184, 0x0200, 0x0040, 0x2479, 0xa18c, 0xfdff, 0x6922,
+ 0x0c7e, 0x7048, 0x2060, 0x6004, 0xa084, 0xffef, 0x6006, 0x2008,
+ 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2479, 0x1078, 0x2ed1,
+ 0x1078, 0x2c2b, 0x88ff, 0x0040, 0x2479, 0x789b, 0x0060, 0x2800,
+ 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0,
+ 0x2475, 0x781b, 0x0053, 0x0078, 0x1e50, 0x781b, 0x0067, 0x0078,
+ 0x1e50, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x2482, 0x781b, 0x0056,
+ 0x0078, 0x1e50, 0x781b, 0x0068, 0x0078, 0x1e50, 0x0078, 0x2db9,
+ 0x0078, 0x2db9, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040,
+ 0x2488, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001,
+ 0x00c0, 0x24ad, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040,
+ 0x24a5, 0x0048, 0x24a5, 0x0078, 0x24a7, 0x0078, 0x2437, 0x24a8,
+ 0x7aa8, 0x00f0, 0x24a7, 0x0078, 0x2493, 0xa284, 0x00f0, 0xa086,
+ 0x0020, 0x00c0, 0x2509, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040,
+ 0x24bd, 0x0048, 0x24bd, 0x0078, 0x2506, 0xa286, 0x0023, 0x0040,
+ 0x2488, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1,
+ 0xa085, 0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010, 0x600a,
+ 0x0c7e, 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184,
+ 0x0010, 0x0040, 0x24e1, 0x1078, 0x2ed1, 0x1078, 0x2d2d, 0x0078,
+ 0x24f0, 0x0c7e, 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f,
+ 0xa184, 0x0008, 0x0040, 0x2479, 0x1078, 0x2ed1, 0x1078, 0x2c2b,
+ 0x88ff, 0x0040, 0x2479, 0x789b, 0x0060, 0x2800, 0x78aa, 0xa6b5,
+ 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2502, 0x781b, 0x0053,
+ 0x0078, 0x1e50, 0x781b, 0x0067, 0x0078, 0x1e50, 0x7aa8, 0x0078,
+ 0x2493, 0x8318, 0x2300, 0xa102, 0x0040, 0x2512, 0x0048, 0x2512,
+ 0x0078, 0x2493, 0xa284, 0x0080, 0x00c0, 0x2dbf, 0x0078, 0x2db9,
+ 0x0078, 0x2dbf, 0x0078, 0x2db3, 0x789b, 0x0018, 0x78a8, 0xa084,
+ 0x00ff, 0xa08e, 0x0001, 0x0040, 0x2527, 0x1078, 0x1e01, 0x7aa8,
+ 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8,
+ 0x2db3, 0x0079, 0x2533, 0x2db3, 0x2b9b, 0x2db3, 0x2cc8, 0xa282,
+ 0x0000, 0x00c0, 0x253d, 0x1078, 0x1e01, 0x1078, 0x2dc7, 0x781b,
+ 0x0067, 0x0078, 0x1e50, 0xa282, 0x0003, 0x00c0, 0x2549, 0x1078,
+ 0x1e01, 0xa484, 0x8000, 0x00c0, 0x256c, 0x70a0, 0xa005, 0x0040,
+ 0x2553, 0x1078, 0x1e01, 0x6f14, 0x77b6, 0xa7bc, 0x0f00, 0x1078,
+ 0x2ed5, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x0007,
+ 0x00c0, 0x2557, 0x1078, 0x2dcb, 0x70a3, 0x0002, 0x2009, 0x3731,
+ 0x200b, 0x0009, 0x0078, 0x256e, 0x1078, 0x2dd7, 0x781b, 0x0067,
+ 0x0078, 0x1e50, 0xa282, 0x0004, 0x0050, 0x2578, 0x1078, 0x1e01,
+ 0x2300, 0x0079, 0x257b, 0x257e, 0x265a, 0x2682, 0xa286, 0x0003,
+ 0x0040, 0x2584, 0x1078, 0x1e01, 0x2001, 0x0000, 0x703a, 0x7000,
+ 0xa084, 0x0007, 0x0079, 0x258c, 0x2594, 0x2596, 0x2596, 0x274a,
+ 0x277b, 0x1e58, 0x277b, 0x2594, 0x1078, 0x1e01, 0xa684, 0x1000,
+ 0x00c0, 0x259e, 0x1078, 0x312e, 0x0040, 0x2634, 0x7868, 0xa08c,
+ 0x00ff, 0x0040, 0x25e6, 0xa186, 0x0008, 0x00c0, 0x25b5, 0x1078,
+ 0x2b5a, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2b0d, 0x0040,
+ 0x25e6, 0x1078, 0x312e, 0x0078, 0x25cd, 0xa186, 0x0028, 0x00c0,
+ 0x25e6, 0x1078, 0x312e, 0x6008, 0xa084, 0xffef, 0x600a, 0x6018,
+ 0xa005, 0x0040, 0x25cd, 0x8001, 0x601a, 0xa005, 0x0040, 0x25cd,
+ 0x8001, 0xa005, 0x0040, 0x25cd, 0x601e, 0x6820, 0xa084, 0x0001,
+ 0x0040, 0x1e58, 0x6820, 0xa084, 0xfffe, 0x6822, 0x7054, 0x0c7e,
+ 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802, 0xa005, 0x2d00,
+ 0x00c0, 0x25e3, 0x6002, 0x6006, 0x0078, 0x1e58, 0x017e, 0x1078,
+ 0x26a7, 0x017f, 0xa684, 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14,
+ 0x81ff, 0x0040, 0x2634, 0xa186, 0x0002, 0x00c0, 0x262c, 0xa684,
+ 0x0800, 0x00c0, 0x2603, 0xa684, 0x0060, 0x0040, 0x2603, 0x78d8,
+ 0x7adc, 0x682e, 0x6a32, 0x6820, 0xa084, 0x0800, 0x00c0, 0x2634,
+ 0x8717, 0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xa290, 0x3800,
+ 0xa290, 0x0000, 0x221c, 0x8210, 0x2204, 0xa085, 0x0018, 0x2012,
+ 0x8211, 0xa384, 0x0400, 0x0040, 0x2626, 0x68a0, 0xa084, 0x0100,
+ 0x00c0, 0x2626, 0x1078, 0x2709, 0x0078, 0x1e58, 0x6008, 0xa085,
+ 0x0002, 0x600a, 0x0078, 0x2634, 0xa186, 0x0018, 0x0040, 0x2634,
+ 0xa186, 0x0014, 0x0040, 0x1e58, 0x6916, 0x6818, 0xa084, 0x8000,
+ 0x0040, 0x263c, 0x7038, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078,
+ 0x2b4b, 0x1078, 0x2b5a, 0x00c0, 0x2649, 0x6008, 0xa084, 0xffef,
+ 0x600a, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2652, 0x1078, 0x2b44,
+ 0x0078, 0x2656, 0x7054, 0x2060, 0x6800, 0x6002, 0x1078, 0x1990,
+ 0x0078, 0x1e58, 0xa282, 0x0004, 0x0048, 0x2660, 0x1078, 0x1e01,
+ 0x2200, 0x0079, 0x2663, 0x265e, 0x2667, 0x266d, 0x2667, 0x1078,
+ 0x2dc7, 0x781b, 0x0067, 0x0078, 0x1e50, 0x7890, 0x8007, 0x8001,
+ 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff,
+ 0xa186, 0x0003, 0x0040, 0x267e, 0x0078, 0x2db3, 0x781b, 0x0068,
+ 0x0078, 0x1e50, 0x6820, 0xa085, 0x0004, 0x6822, 0x82ff, 0x00c0,
+ 0x268d, 0x1078, 0x2dc7, 0x0078, 0x2694, 0x8211, 0x0040, 0x2692,
+ 0x1078, 0x1e01, 0x1078, 0x2dd7, 0x781b, 0x0067, 0x0078, 0x1e50,
+ 0x1078, 0x2fa6, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x26a4, 0x0018,
+ 0x26a4, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684,
+ 0x0060, 0x00c0, 0x26b1, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078,
+ 0x2708, 0xa684, 0x0800, 0x00c0, 0x26c1, 0x6998, 0x6a94, 0x692e,
+ 0x6a32, 0x7000, 0xa086, 0x0006, 0x0040, 0x26c0, 0x1078, 0x312e,
+ 0x007c, 0xa684, 0x0020, 0x0040, 0x26db, 0xa684, 0x4000, 0x0040,
+ 0x26cf, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x26b9, 0x7038,
+ 0xa005, 0x00c0, 0x26d5, 0x703b, 0x0015, 0x79d8, 0x7adc, 0x692e,
+ 0x6a32, 0x0078, 0x26b9, 0xa684, 0x4000, 0x0040, 0x26e5, 0x682f,
+ 0x0000, 0x6833, 0x0000, 0x0078, 0x26b9, 0x7038, 0xa005, 0x00c0,
+ 0x26eb, 0x703b, 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8,
+ 0x26f2, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e,
+ 0x6a32, 0x2100, 0xa205, 0x00c0, 0x26ff, 0x0078, 0x26b9, 0x7000,
+ 0xa086, 0x0006, 0x0040, 0x2708, 0x1078, 0x3474, 0x0078, 0x26b9,
+ 0x007c, 0xa384, 0x0200, 0x0040, 0x2711, 0x6008, 0xa085, 0x0002,
+ 0x600a, 0x681b, 0x0006, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f,
+ 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b,
+ 0x0020, 0x7000, 0x0079, 0x2724, 0x272c, 0x272e, 0x2737, 0x272c,
+ 0x272c, 0x272c, 0x272c, 0x272c, 0x1078, 0x1e01, 0x6820, 0xa084,
+ 0x0001, 0x00c0, 0x2737, 0x1078, 0x2b44, 0x0078, 0x273d, 0x7054,
+ 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, 0x2021, 0x3757, 0x2404,
+ 0xa005, 0x0040, 0x2746, 0x2020, 0x0078, 0x273f, 0x2d22, 0x206b,
+ 0x0000, 0x007c, 0x1078, 0x2b4b, 0x1078, 0x2b5a, 0x682b, 0x0000,
+ 0x789b, 0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, 0x34ac, 0xa684,
+ 0x0800, 0x0040, 0x275f, 0x691c, 0xa18d, 0x2000, 0x691e, 0x6818,
+ 0xa084, 0x8000, 0x0040, 0x276f, 0x7868, 0xa08c, 0x00ff, 0x0040,
+ 0x276d, 0x681b, 0x001e, 0x0078, 0x276f, 0x681b, 0x0000, 0x2021,
+ 0x3757, 0x6800, 0x2022, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078,
+ 0x1990, 0x0078, 0x1e58, 0x1078, 0x26a7, 0x682b, 0x0000, 0x789b,
+ 0x000e, 0x6f14, 0x1078, 0x2fab, 0xa08c, 0x00ff, 0x6916, 0x6818,
+ 0xa084, 0x8000, 0x0040, 0x278e, 0x7038, 0x681a, 0xa68c, 0xdf00,
+ 0x691e, 0x70a3, 0x0000, 0x0078, 0x1e58, 0xa006, 0x1078, 0x312e,
+ 0x6817, 0x0000, 0x681b, 0x0001, 0xa68c, 0xdf00, 0x691e, 0x682b,
+ 0x0000, 0x7000, 0x0079, 0x27a4, 0x27ac, 0x27ae, 0x27ae, 0x27b0,
+ 0x27b0, 0x27b0, 0x27b0, 0x27ac, 0x1078, 0x1e01, 0x1078, 0x2b5a,
+ 0x6008, 0xa084, 0xffef, 0x600a, 0x0078, 0x2b25, 0x2300, 0x0079,
+ 0x27b9, 0x27bc, 0x27be, 0x27f7, 0x1078, 0x1e01, 0x7000, 0x0079,
+ 0x27c1, 0x27c9, 0x27cb, 0x27cb, 0x27e6, 0x27cb, 0x27f3, 0x27e6,
+ 0x27c9, 0x1078, 0x1e01, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0,
+ 0x27e2, 0xa6b4, 0xffdf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a,
+ 0x681c, 0xa084, 0xffdf, 0x681e, 0x1078, 0x312e, 0x1078, 0x33b6,
+ 0x0078, 0x2f58, 0xa684, 0x2000, 0x0040, 0x27d5, 0x6818, 0xa084,
+ 0x8000, 0x0040, 0x27f3, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040,
+ 0x27f3, 0x681b, 0x0007, 0x781b, 0x00dc, 0x0078, 0x1e50, 0x1078,
+ 0x1e01, 0x2300, 0x0079, 0x27fc, 0x27ff, 0x2801, 0x2834, 0x1078,
+ 0x1e01, 0x7000, 0x0079, 0x2804, 0x280c, 0x280e, 0x280e, 0x2829,
+ 0x280e, 0x2830, 0x2829, 0x280c, 0x1078, 0x1e01, 0xa684, 0x0060,
+ 0xa086, 0x0060, 0x00c0, 0x2825, 0xa6b4, 0xffbf, 0xa6b4, 0xbfff,
+ 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffbf, 0x681e, 0x1078,
+ 0x312e, 0x1078, 0x33b6, 0x0078, 0x2f58, 0xa684, 0x2000, 0x0040,
+ 0x2818, 0x6818, 0xa084, 0x8000, 0x0040, 0x2830, 0x681b, 0x0007,
+ 0x781b, 0x00e3, 0x0078, 0x1e50, 0x6820, 0xa085, 0x0004, 0x6822,
+ 0x1078, 0x2f23, 0xa6b5, 0x0800, 0x1078, 0x2dc7, 0x781b, 0x0067,
+ 0x0078, 0x1e50, 0x2300, 0x0079, 0x2845, 0x2848, 0x284a, 0x284c,
+ 0x1078, 0x1e01, 0x1078, 0x1e01, 0x782b, 0x3009, 0xa684, 0x0400,
+ 0x00c0, 0x2866, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb,
+ 0x785a, 0x79e4, 0xa184, 0x0020, 0x00c0, 0x2862, 0x2001, 0x0014,
+ 0x0078, 0x2586, 0xa184, 0x0007, 0x0079, 0x2896, 0x7a90, 0xa294,
+ 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0040, 0x2894, 0x789b,
+ 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, 0x288d, 0x7ba8, 0x7ba8,
+ 0xa386, 0x0001, 0x00c0, 0x2880, 0x2009, 0xfff7, 0x0078, 0x2886,
+ 0xa386, 0x0003, 0x00c0, 0x288d, 0x2009, 0xffef, 0x0c7e, 0x7048,
+ 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab,
+ 0x0000, 0xa684, 0xfffb, 0x785a, 0x0078, 0x2f58, 0x229f, 0x22ac,
+ 0x2f60, 0x2f60, 0x289e, 0x289e, 0x289e, 0x2f60, 0x1078, 0x1e01,
+ 0x79e4, 0xa184, 0x0030, 0x00c0, 0x28b6, 0x70a0, 0xa086, 0x0002,
+ 0x00c0, 0x28ae, 0x2011, 0x0002, 0x0078, 0x21a0, 0x6818, 0xa085,
+ 0x8000, 0x681a, 0x2001, 0x0014, 0x0078, 0x2586, 0xa18c, 0x0007,
+ 0xa186, 0x0002, 0x00c0, 0x2f80, 0xa684, 0x0400, 0x00c0, 0x28fd,
+ 0x6820, 0xa084, 0x0001, 0x0040, 0x2f60, 0xa68c, 0x0060, 0xa684,
+ 0x0060, 0x0040, 0x28d1, 0xa086, 0x0060, 0x00c0, 0x28d1, 0xa18d,
+ 0x4000, 0xa18c, 0xfffb, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab,
+ 0x0000, 0x789b, 0x0061, 0x6818, 0xa085, 0x8000, 0x681a, 0x78aa,
+ 0x8008, 0x810c, 0x0040, 0x2b82, 0xa18c, 0x00f8, 0x00c0, 0x2b82,
+ 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000,
+ 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f,
+ 0x6814, 0x8007, 0x7882, 0x0078, 0x2f60, 0x6818, 0xa084, 0x8000,
+ 0x0040, 0x2904, 0x681b, 0x0008, 0x781b, 0x00d7, 0x0078, 0x1e50,
+ 0x2300, 0x0079, 0x290b, 0x2910, 0x2993, 0x290e, 0x1078, 0x1e01,
+ 0x7000, 0xa084, 0x0007, 0x0079, 0x2915, 0x291d, 0x291f, 0x293b,
+ 0x291d, 0x291d, 0x1e58, 0x291d, 0x291d, 0x1078, 0x1e01, 0x6920,
+ 0xa18d, 0x0001, 0x6922, 0x6800, 0x6006, 0xa005, 0x00c0, 0x2929,
+ 0x6002, 0x681c, 0xa084, 0x000e, 0x0040, 0x2935, 0x7014, 0x68ba,
+ 0x712c, 0xa188, 0x4080, 0x0078, 0x2937, 0x2009, 0x4180, 0x2104,
+ 0x6802, 0x2d0a, 0x7156, 0x6920, 0xa184, 0x8000, 0x00c0, 0x2947,
+ 0x68af, 0x0000, 0x68b3, 0x0000, 0xa18d, 0x8000, 0x6922, 0x6eb6,
+ 0xa684, 0x0060, 0x0040, 0x2991, 0xa684, 0x0800, 0x00c0, 0x2958,
+ 0x6894, 0x68a6, 0x6898, 0x68aa, 0x1078, 0x312e, 0x0078, 0x2991,
+ 0xa684, 0x0020, 0x0040, 0x2965, 0xa006, 0x1078, 0x3474, 0x79d8,
+ 0x7adc, 0x69aa, 0x6aa6, 0x0078, 0x296b, 0x1078, 0x2ee2, 0x69aa,
+ 0x6aa6, 0x1078, 0x3474, 0xa684, 0x8000, 0x0040, 0x2991, 0xa684,
+ 0x7fff, 0x68b6, 0x789b, 0x0074, 0x1078, 0x2fab, 0x2010, 0x1078,
+ 0x2fab, 0x2008, 0xa684, 0x0020, 0x00c0, 0x2989, 0x1078, 0x2fab,
+ 0x801b, 0x00c8, 0x2984, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291,
+ 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303,
+ 0x68ae, 0x0078, 0x1e58, 0x0078, 0x2dbf, 0x7033, 0x0000, 0xa282,
+ 0x0006, 0x0050, 0x299d, 0x1078, 0x1e01, 0x2300, 0x0079, 0x29a0,
+ 0x29a3, 0x29c9, 0x29ed, 0x2200, 0x0079, 0x29a6, 0x29ac, 0x2dbf,
+ 0x29ae, 0x29ac, 0x2a17, 0x2a68, 0x1078, 0x1e01, 0x7003, 0x0005,
+ 0x2001, 0x4190, 0x2068, 0x703e, 0x157e, 0x20a9, 0x002f, 0x2003,
+ 0x0000, 0x8000, 0x0070, 0x29be, 0x0078, 0x29b7, 0x157f, 0x6817,
+ 0x0000, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x0078,
+ 0x2db3, 0x7000, 0xa086, 0x0001, 0x00c0, 0x29d6, 0x1078, 0x2b5a,
+ 0x1078, 0x312e, 0x7034, 0x600a, 0x0078, 0x29db, 0x7000, 0xa086,
+ 0x0003, 0x0040, 0x29d0, 0x7003, 0x0005, 0x2001, 0x4190, 0x2068,
+ 0x703e, 0x7032, 0x2200, 0x0079, 0x29e5, 0x2dbf, 0x29eb, 0x29eb,
+ 0x2a17, 0x29eb, 0x2dbf, 0x1078, 0x1e01, 0x7000, 0xa086, 0x0001,
+ 0x00c0, 0x29fa, 0x1078, 0x2b5a, 0x1078, 0x312e, 0x7034, 0x600a,
+ 0x0078, 0x29ff, 0x7000, 0xa086, 0x0003, 0x0040, 0x29f4, 0x7003,
+ 0x0005, 0x2001, 0x4190, 0x2068, 0x703e, 0x7032, 0x2200, 0x0079,
+ 0x2a09, 0x2a11, 0x2a0f, 0x2a0f, 0x2a11, 0x2a0f, 0x2a11, 0x1078,
+ 0x1e01, 0x1078, 0x2dd7, 0x781b, 0x0067, 0x0078, 0x1e50, 0x7000,
+ 0xa086, 0x0001, 0x00c0, 0x2a24, 0x1078, 0x2b5a, 0x1078, 0x312e,
+ 0x7034, 0x600a, 0x0078, 0x2a29, 0x7000, 0xa086, 0x0003, 0x0040,
+ 0x2a1e, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018,
+ 0x7ca8, 0xa484, 0x0007, 0xa215, 0x2069, 0x4180, 0x2d04, 0x2d08,
+ 0x7156, 0x2068, 0xa005, 0x0040, 0x2a44, 0x6814, 0xa206, 0x0040,
+ 0x2a5d, 0x6800, 0x0078, 0x2a37, 0x7003, 0x0005, 0x2001, 0x4190,
+ 0x2068, 0x703e, 0x7032, 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000,
+ 0x8000, 0x0070, 0x2a55, 0x0078, 0x2a4e, 0x157f, 0x6a16, 0x68b7,
+ 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820,
+ 0xa084, 0x0c00, 0x0040, 0x2ac6, 0x1078, 0x2dcf, 0x0078, 0x2ac6,
+ 0x7000, 0xa086, 0x0001, 0x00c0, 0x2a75, 0x1078, 0x2b5a, 0x1078,
+ 0x312e, 0x7034, 0x600a, 0x0078, 0x2a7a, 0x7000, 0xa086, 0x0003,
+ 0x0040, 0x2a6f, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b,
+ 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, 0x79a8, 0x79a8, 0xa18c,
+ 0x00ff, 0xa1e8, 0x4080, 0x2d04, 0x2d08, 0x7156, 0x2068, 0xa005,
+ 0x0040, 0x2a99, 0x6814, 0xa206, 0x0040, 0x2ab1, 0x6800, 0x0078,
+ 0x2a8c, 0x7003, 0x0005, 0x2001, 0x4190, 0x2068, 0x703e, 0x157e,
+ 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070, 0x2aa9, 0x0078,
+ 0x2aa2, 0x157f, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827,
+ 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x2ac6,
+ 0xa084, 0x0800, 0x0040, 0x2ac0, 0x1078, 0x2dd3, 0x0078, 0x2ac6,
+ 0x1078, 0x2dcf, 0x70bf, 0x0000, 0x0078, 0x2ac6, 0x027e, 0x8207,
+ 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3800, 0x2060,
+ 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0xa684, 0x0060, 0x0040,
+ 0x2adf, 0x68a8, 0x78d2, 0x78da, 0x68a4, 0x78d6, 0x78de, 0x077f,
+ 0x1078, 0x2ed5, 0x2009, 0x0068, 0xa684, 0x0008, 0x0040, 0x2aea,
+ 0x2009, 0x0067, 0xa6b5, 0x2000, 0x7e5a, 0x791a, 0xa684, 0x0060,
+ 0x0040, 0x2b00, 0xa684, 0x0800, 0x00c0, 0x2afa, 0x1078, 0x33b6,
+ 0x0078, 0x2b00, 0xa684, 0x4000, 0x00c0, 0x2b00, 0x1078, 0x3347,
+ 0x2d00, 0x703e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003,
+ 0xa080, 0x3800, 0x2048, 0x0078, 0x1e50, 0x6020, 0xa005, 0x0040,
+ 0x2b19, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, 0x7010,
+ 0x6026, 0x007c, 0xa006, 0x1078, 0x312e, 0x6817, 0x0000, 0x681b,
+ 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x0007,
+ 0x0079, 0x2b2a, 0x2b32, 0x2b34, 0x2b34, 0x2b40, 0x2b3c, 0x2b32,
+ 0x2b3c, 0x2b32, 0x1078, 0x1e01, 0x1078, 0x2b4b, 0x1078, 0x2b44,
+ 0x1078, 0x1990, 0x0078, 0x1e58, 0x70a3, 0x0000, 0x0078, 0x1e58,
+ 0x681b, 0x0000, 0x0078, 0x274a, 0x6800, 0xa005, 0x00c0, 0x2b49,
+ 0x6002, 0x6006, 0x007c, 0x6010, 0xa005, 0x0040, 0x2b54, 0x8001,
+ 0x00d0, 0x2b54, 0x1078, 0x1e01, 0x6012, 0x6008, 0xa084, 0xffef,
+ 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x2b60, 0x8001, 0x601a,
+ 0x007c, 0x1078, 0x2fa6, 0x6818, 0xa084, 0x8000, 0x0040, 0x2b6a,
+ 0x681b, 0x0018, 0x0078, 0x2b8f, 0x1078, 0x2fa6, 0x6818, 0xa084,
+ 0x8000, 0x0040, 0x2b75, 0x681b, 0x0019, 0x0078, 0x2b8f, 0x1078,
+ 0x2fa6, 0x6818, 0xa084, 0x8000, 0x0040, 0x2b80, 0x681b, 0x001a,
+ 0x0078, 0x2b8f, 0x1078, 0x2fa6, 0x681b, 0x0003, 0x0078, 0x2b8f,
+ 0x6818, 0xa084, 0x8000, 0x0040, 0x2b8f, 0x681b, 0x0005, 0x681f,
+ 0x0000, 0x6823, 0x0020, 0x1078, 0x2b4b, 0x1078, 0x2b44, 0x1078,
+ 0x1990, 0x0078, 0x1e58, 0xa282, 0x0003, 0x00c0, 0x2db3, 0x7da8,
+ 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, 0xa18d, 0x0080,
+ 0x6922, 0xa184, 0x0100, 0x0040, 0x2bde, 0xa18c, 0xfeff, 0x6922,
+ 0xa6b4, 0x00ff, 0x0040, 0x2bc8, 0xa682, 0x000c, 0x0048, 0x2bbc,
+ 0x0040, 0x2bbc, 0x2031, 0x000c, 0x852b, 0x852b, 0x1078, 0x2e62,
+ 0x0040, 0x2bc6, 0x1078, 0x2c94, 0x0078, 0x2bd1, 0x1078, 0x2e1d,
+ 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x2cb8,
+ 0x0c7f, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x2bda, 0x781b, 0x0056,
+ 0x0078, 0x1e50, 0x781b, 0x0068, 0x0078, 0x1e50, 0x0c7e, 0x7048,
+ 0x2060, 0x6100, 0xa18c, 0x1000, 0x0040, 0x2c1e, 0x6208, 0x8217,
+ 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x2bf2, 0x0040, 0x2bf2,
+ 0x2011, 0x000c, 0x2600, 0xa202, 0x00c8, 0x2bf7, 0x2230, 0x6208,
+ 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0, 0x2c07, 0xa282,
+ 0x0019, 0x00c8, 0x2c0d, 0x2011, 0x0019, 0x0078, 0x2c0d, 0xa282,
+ 0x000c, 0x00c8, 0x2c0d, 0x2011, 0x000c, 0x2200, 0xa502, 0x00c8,
+ 0x2c12, 0x2228, 0x1078, 0x2e21, 0x852b, 0x852b, 0x1078, 0x2e62,
+ 0x0040, 0x2c1e, 0x1078, 0x2c94, 0x0078, 0x2c22, 0x1078, 0x2e1d,
+ 0x1078, 0x2cb8, 0x7858, 0xa085, 0x0004, 0x785a, 0x0c7f, 0x781b,
+ 0x0067, 0x0078, 0x1e50, 0x0c7e, 0x2960, 0x6000, 0xa084, 0x1000,
+ 0x00c0, 0x2c42, 0x6010, 0xa084, 0x000f, 0x00c0, 0x2c3c, 0xa18c,
+ 0xfff5, 0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000,
+ 0x0078, 0x2c69, 0x68a0, 0xa084, 0x0200, 0x00c0, 0x2c3c, 0x6208,
+ 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0, 0x2c57, 0xa282,
+ 0x0019, 0x00c8, 0x2c5d, 0x2011, 0x0019, 0x0078, 0x2c5d, 0xa282,
+ 0x000c, 0x00c8, 0x2c5d, 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c,
+ 0x00ff, 0xa382, 0x000c, 0x0048, 0x2c69, 0x0040, 0x2c69, 0x2019,
+ 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa,
+ 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f,
+ 0x007c, 0x0c7e, 0x2960, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032,
+ 0x2019, 0x0000, 0x0078, 0x2c84, 0x78ab, 0x0001, 0x78ab, 0x0003,
+ 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085,
+ 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7148, 0x2160, 0x2008,
+ 0xa084, 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612,
+ 0x78a4, 0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016,
+ 0x788a, 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff,
+ 0xa605, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c,
+ 0x0c7e, 0x7048, 0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0,
+ 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, 0x0c7f, 0x007c,
+ 0xa282, 0x0002, 0x00c0, 0x2db3, 0x7aa8, 0x6920, 0xa18d, 0x0080,
+ 0x6922, 0xa184, 0x0200, 0x0040, 0x2d0d, 0xa18c, 0xfdff, 0x6922,
+ 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, 0x2db3, 0x1078, 0x2d54,
+ 0x1078, 0x2cb8, 0xa980, 0x0001, 0x200c, 0x1078, 0x2ed1, 0x1078,
+ 0x2c2b, 0x88ff, 0x0040, 0x2d00, 0x789b, 0x0060, 0x2800, 0x78aa,
+ 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2cfc,
+ 0x781b, 0x0053, 0x0078, 0x1e50, 0x781b, 0x0067, 0x0078, 0x1e50,
+ 0x7e58, 0xa684, 0x0400, 0x00c0, 0x2d09, 0x781b, 0x0056, 0x0078,
+ 0x1e50, 0x781b, 0x0068, 0x0078, 0x1e50, 0xa282, 0x0002, 0x00c8,
+ 0x2d15, 0xa284, 0x0001, 0x0040, 0x2d1f, 0x7148, 0xa188, 0x0000,
+ 0x210c, 0xa18c, 0x2000, 0x00c0, 0x2d1f, 0x2011, 0x0000, 0x1078,
+ 0x2e0f, 0x1078, 0x2d54, 0x1078, 0x2cb8, 0x7858, 0xa085, 0x0004,
+ 0x785a, 0x781b, 0x0067, 0x0078, 0x1e50, 0x0c7e, 0x027e, 0x2960,
+ 0x6000, 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x2d44, 0x6014,
+ 0xa084, 0x0040, 0x00c0, 0x2d42, 0xa18c, 0xffef, 0x6106, 0xa006,
+ 0x0078, 0x2d51, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002,
+ 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085, 0x0200,
+ 0x6822, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x82ff,
+ 0x0040, 0x2d5c, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a,
+ 0x78a4, 0xa084, 0xffbf, 0xa205, 0x78a6, 0x6016, 0x788a, 0x6004,
+ 0xa084, 0xffef, 0x6006, 0x0c7f, 0x007c, 0xa684, 0x0020, 0x0040,
+ 0x2daf, 0x7888, 0xa084, 0x0040, 0x0040, 0x2daf, 0x7bb8, 0xa384,
+ 0x003f, 0x831b, 0x00c8, 0x2d7d, 0x8000, 0xa005, 0x0040, 0x2d96,
+ 0x831b, 0x00c8, 0x2d86, 0x8001, 0x0040, 0x2dab, 0xa684, 0x4000,
+ 0x0040, 0x2d96, 0x78b8, 0x801b, 0x00c8, 0x2d8f, 0x8000, 0xa084,
+ 0x003f, 0x00c0, 0x2dab, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc,
+ 0x2001, 0x0001, 0xa108, 0x00c8, 0x2d9f, 0xa291, 0x0000, 0x79d2,
+ 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x3474, 0x781b, 0x0065, 0x1078,
+ 0x3347, 0x0078, 0x1e50, 0x781b, 0x0065, 0x0078, 0x1e50, 0x781b,
+ 0x0068, 0x0078, 0x1e50, 0x1078, 0x2ddb, 0x781b, 0x0067, 0x0078,
+ 0x1e50, 0x1078, 0x2dc7, 0x781b, 0x0067, 0x0078, 0x1e50, 0x6827,
+ 0x0002, 0x1078, 0x2dcf, 0x781b, 0x0067, 0x0078, 0x1e50, 0x2001,
+ 0x0005, 0x0078, 0x2ddd, 0x2001, 0x000c, 0x0078, 0x2ddd, 0x2001,
+ 0x0006, 0x0078, 0x2ddd, 0x2001, 0x000d, 0x0078, 0x2ddd, 0x2001,
+ 0x0009, 0x0078, 0x2ddd, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa,
+ 0xa6b5, 0x0008, 0x7e5a, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f,
+ 0x873b, 0x873b, 0x8703, 0xa0e0, 0x3800, 0xa7b8, 0x0020, 0x7f9a,
+ 0x79a4, 0xa184, 0x000f, 0x0040, 0x2dfd, 0xa184, 0xfff0, 0x78a6,
+ 0x6012, 0x6004, 0xa085, 0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a,
+ 0x79a4, 0xa184, 0x0040, 0x0040, 0x2e0d, 0xa184, 0xffbf, 0x78a6,
+ 0x6016, 0x6004, 0xa085, 0x0010, 0x6006, 0x077f, 0x007c, 0x789b,
+ 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa,
+ 0x789b, 0x0060, 0x78ab, 0x0004, 0x007c, 0x2031, 0x0000, 0x2029,
+ 0x0032, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab,
+ 0x0001, 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x007c,
+ 0x157e, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020,
+ 0x789a, 0x79a4, 0xa18c, 0xfff0, 0x2001, 0x3746, 0x2004, 0xa082,
+ 0x0028, 0x0040, 0x2e4b, 0x2021, 0x2eb8, 0x2019, 0x0014, 0x20a9,
+ 0x000c, 0x0078, 0x2e51, 0x2021, 0x2ec4, 0x2019, 0x0019, 0x20a9,
+ 0x000d, 0x2011, 0x0064, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040,
+ 0x2e60, 0x8420, 0x2300, 0xa210, 0x0070, 0x2e60, 0x0078, 0x2e53,
+ 0x157f, 0x007c, 0x157e, 0x2011, 0x3746, 0x2214, 0xa282, 0x0032,
+ 0x0048, 0x2e76, 0x0040, 0x2e7a, 0x2021, 0x2eaa, 0x2019, 0x0011,
+ 0x20a9, 0x000e, 0x2011, 0x0032, 0x0078, 0x2e8c, 0xa282, 0x0028,
+ 0x0040, 0x2e84, 0x2021, 0x2eb8, 0x2019, 0x0014, 0x20a9, 0x000c,
+ 0x2011, 0x0064, 0x0078, 0x2e8c, 0x2021, 0x2ec4, 0x2019, 0x0019,
+ 0x20a9, 0x000d, 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x2e9c,
+ 0x0048, 0x2e9c, 0x8420, 0x2300, 0xa210, 0x0070, 0x2e99, 0x0078,
+ 0x2e8c, 0x157f, 0xa006, 0x007c, 0x157f, 0x7a08, 0xa582, 0x00c8,
+ 0x00c8, 0x2ea7, 0xa285, 0x0040, 0x780a, 0x0078, 0x2ea7, 0x2404,
+ 0xa005, 0x007c, 0x2002, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404,
+ 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0a07, 0x0c07, 0x0e07,
+ 0x3202, 0x4202, 0x5202, 0x6202, 0x7202, 0x6605, 0x7605, 0x7805,
+ 0x7a05, 0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202, 0x4202, 0x5202,
+ 0x5404, 0x6404, 0x7404, 0x7604, 0x7804, 0x7a04, 0x7c04, 0x7e04,
+ 0x7f04, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, 0x800c,
+ 0xa784, 0x0007, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e0,
+ 0x3880, 0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b, 0x00c8, 0x2ee9,
+ 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x007c, 0x0f7e,
+ 0x2079, 0x0100, 0x2009, 0x3740, 0x2091, 0x8000, 0x2104, 0x0079,
+ 0x2ef9, 0x2f1f, 0x2f03, 0x2f03, 0x2f03, 0x2f03, 0x2f03, 0x2f03,
+ 0x2f01, 0x1078, 0x1e01, 0x784b, 0x0004, 0x68b4, 0xa085, 0x4000,
+ 0x68b6, 0x7858, 0xa085, 0x4000, 0x785a, 0x7830, 0xa084, 0x0080,
+ 0x00c0, 0x2f1f, 0x0018, 0x2f1f, 0x681c, 0xa084, 0x0020, 0x00c0,
+ 0x2f1d, 0x781b, 0x00dc, 0x0078, 0x2f1f, 0x781b, 0x00e3, 0x2091,
+ 0x8001, 0x0f7f, 0x007c, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f,
+ 0x8003, 0x8003, 0x8003, 0xa0e0, 0x3800, 0x6004, 0xa084, 0x000a,
+ 0x00c0, 0x2f56, 0x6108, 0xa194, 0xff00, 0x0040, 0x2f56, 0xa18c,
+ 0x00ff, 0x2001, 0x0019, 0xa106, 0x0040, 0x2f45, 0x2001, 0x0032,
+ 0xa106, 0x0040, 0x2f49, 0x0078, 0x2f4d, 0x2009, 0x0020, 0x0078,
+ 0x2f4f, 0x2009, 0x003f, 0x0078, 0x2f4f, 0x2011, 0x0000, 0x2100,
+ 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, 0x007c,
+ 0x781b, 0x0068, 0x0078, 0x1e50, 0x781b, 0x0067, 0x0078, 0x1e50,
+ 0x781b, 0x0056, 0x0078, 0x1e50, 0x781b, 0x0053, 0x0078, 0x1e50,
+ 0x781b, 0x00dc, 0x0078, 0x1e50, 0x781b, 0x00db, 0x0078, 0x1e50,
+ 0x781b, 0x00e3, 0x0078, 0x1e50, 0x781b, 0x00e2, 0x0078, 0x1e50,
+ 0x781b, 0x009d, 0x0078, 0x1e50, 0x781b, 0x009c, 0x0078, 0x1e50,
+ 0x6818, 0xa084, 0x8000, 0x0040, 0x2f87, 0x681b, 0x001d, 0x70a3,
+ 0x0001, 0x781b, 0x0047, 0x0078, 0x1e50, 0x007e, 0x7830, 0xa084,
+ 0x00c0, 0x00c0, 0x2fa4, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005,
+ 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, 0x2fa4,
+ 0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0x7808, 0xa085,
+ 0x0002, 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, 0x00c0, 0x2fab,
+ 0x0098, 0x2fb4, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a,
+ 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040,
+ 0x2fc3, 0x0098, 0x2fc1, 0x78ac, 0x007e, 0x7808, 0xa085, 0x0002,
+ 0x780a, 0x007f, 0x007c, 0xa784, 0x0070, 0x0040, 0x2fd7, 0x0c7e,
+ 0x2d60, 0x2f68, 0x1078, 0x1dac, 0x2d78, 0x2c68, 0x0c7f, 0xa784,
+ 0x0008, 0x0040, 0x2fe4, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003,
+ 0x0040, 0x1e58, 0x0078, 0x2f58, 0xa784, 0x0004, 0x0040, 0x3017,
+ 0x78b8, 0xa084, 0x4001, 0x0040, 0x3017, 0x784b, 0x0008, 0x78ec,
+ 0xa084, 0x0003, 0x0040, 0x1e58, 0x78e4, 0xa084, 0x0007, 0xa086,
+ 0x0001, 0x00c0, 0x3017, 0x78c0, 0xa685, 0x4800, 0x2030, 0x7e5a,
+ 0x781b, 0x00e3, 0x0078, 0x1e50, 0x784b, 0x0008, 0x6818, 0xa084,
+ 0x8000, 0x0040, 0x3013, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040,
+ 0x3013, 0x681b, 0x0007, 0x781b, 0x00dc, 0x0078, 0x1e50, 0x681b,
+ 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833,
+ 0x0000, 0x784b, 0x0008, 0x78e4, 0xa005, 0x00d0, 0x228e, 0xa084,
+ 0x0020, 0x0040, 0x228e, 0x0018, 0x228e, 0x0078, 0x2db9, 0x6b14,
+ 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3800,
+ 0x2060, 0x2048, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0x2a60,
+ 0x007c, 0x0020, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+ 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+ 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+ 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+ 0x0020, 0x0000, 0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9848,
+ 0x0014, 0x0014, 0x98f6, 0x98e6, 0x0014, 0x0014, 0x0080, 0x00bd,
+ 0x0100, 0x0402, 0x2008, 0xf880, 0x0018, 0xa20a, 0x0014, 0x300b,
+ 0xa20c, 0x0014, 0xa200, 0x8838, 0x3806, 0x8839, 0x28c2, 0x9cc2,
+ 0xa805, 0x0864, 0xa83d, 0x3008, 0x28c1, 0x9cc2, 0xa201, 0x300c,
+ 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808,
+ 0x28e2, 0x9c9f, 0xa8f3, 0x0864, 0xa82b, 0x300c, 0xa801, 0x3008,
+ 0x28e1, 0x9c9f, 0x280d, 0xa204, 0x64c0, 0x67a0, 0x6fc0, 0x1814,
+ 0x883b, 0x7023, 0x8576, 0x8677, 0xa80f, 0x786e, 0x883e, 0xa80c,
+ 0x282b, 0xa205, 0x64a0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023,
+ 0x8576, 0x8677, 0xa801, 0x883e, 0x206b, 0x28c1, 0x9cc2, 0x2044,
+ 0x2103, 0x20a2, 0x2081, 0xa8dc, 0xa207, 0x2901, 0xa80a, 0x0014,
+ 0xa203, 0x8000, 0x85a4, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601,
+ 0xa208, 0x856e, 0x866f, 0x0704, 0x3008, 0x9c9f, 0x0014, 0xa202,
+ 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf848, 0x8174, 0x86eb,
+ 0x85eb, 0x872e, 0x87a9, 0x883f, 0x08e6, 0xa8f1, 0xf861, 0xa8e8,
+ 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2,
+ 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0,
+ 0x1fe6, 0x0014, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823,
+ 0x0016, 0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a,
+ 0xf021, 0x3008, 0x84a8, 0x1dc6, 0x20d7, 0x8822, 0x0016, 0x8000,
+ 0x2848, 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2802, 0x1011,
+ 0xa8fd, 0xa886, 0x3008, 0x283d, 0x1011, 0xa8fd, 0xa209, 0x0017,
+ 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0xd301, 0x0014,
+ 0x26e0, 0x873a, 0xfaa2, 0x19f2, 0x1fe2, 0x0014, 0xa20b, 0x0014,
+ 0xa20d, 0x3806, 0x0210, 0x9ccc, 0x0704, 0x0000, 0x127e, 0x2091,
+ 0x2200, 0x2049, 0x312e, 0x7000, 0x7204, 0xa205, 0x720c, 0xa215,
+ 0x7008, 0xa084, 0xfff7, 0xa205, 0x0040, 0x3140, 0x1078, 0x31b9,
+ 0x127f, 0x2000, 0x007c, 0x6428, 0x84ff, 0x0040, 0x316f, 0x2c70,
+ 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x317f, 0x273c, 0x87fb, 0x00c0,
+ 0x315d, 0x0048, 0x3155, 0x1078, 0x1e01, 0x609c, 0xa075, 0x0040,
+ 0x316f, 0x0078, 0x3148, 0x2039, 0x3174, 0x2704, 0xae68, 0x6808,
+ 0xa630, 0x680c, 0xa529, 0x8421, 0x0040, 0x316f, 0x8738, 0x2704,
+ 0xa005, 0x00c0, 0x315e, 0x709c, 0xa075, 0x00c0, 0x3148, 0x007c,
+ 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d,
+ 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000,
+ 0x3174, 0x3171, 0x0000, 0x0000, 0x8000, 0x0000, 0x3174, 0x0000,
+ 0x317c, 0x3179, 0x0000, 0x0000, 0x0000, 0x0000, 0x317c, 0x0000,
+ 0x3177, 0x3177, 0x0000, 0x0000, 0x8000, 0x0000, 0x3177, 0x0000,
+ 0x317d, 0x317d, 0x0000, 0x0000, 0x0000, 0x0000, 0x317d, 0x127e,
+ 0x2091, 0x2200, 0x2079, 0x3700, 0x2071, 0x0010, 0x7007, 0x000a,
+ 0x7007, 0x0002, 0x7003, 0x0000, 0x2071, 0x0020, 0x7007, 0x000a,
+ 0x7007, 0x0002, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000,
+ 0x007c, 0x2049, 0x31b9, 0x2019, 0x0000, 0x7004, 0x8004, 0x00c8,
+ 0x31eb, 0x7007, 0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x31c3,
+ 0xa184, 0x01e0, 0x0040, 0x31ce, 0x1078, 0x1e01, 0xa184, 0x4000,
+ 0x00c0, 0x31c3, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x31e0,
+ 0xa386, 0x0008, 0x0040, 0x31eb, 0xa386, 0x200c, 0x00c0, 0x31c3,
+ 0x7200, 0x8204, 0x0048, 0x31eb, 0x730c, 0xa384, 0x00ff, 0x0040,
+ 0x31eb, 0x1078, 0x1e01, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004,
+ 0xa084, 0x0008, 0x00c0, 0x31ef, 0x7007, 0x0012, 0x7108, 0x8103,
+ 0x0048, 0x31f4, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e,
+ 0x007e, 0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x320f,
+ 0x157f, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204,
+ 0x7500, 0x730c, 0xa384, 0x0300, 0x00c0, 0x324e, 0xa184, 0x0060,
+ 0x00c0, 0x3287, 0x7008, 0x7108, 0xa106, 0x00c0, 0x321a, 0xa184,
+ 0x01e0, 0x00c0, 0x3287, 0xa184, 0x4000, 0x00c0, 0x321a, 0xa986,
+ 0x3474, 0x00c0, 0x3242, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040,
+ 0x3239, 0xa386, 0x0008, 0x0040, 0x3242, 0xa386, 0x200c, 0x00c0,
+ 0x321a, 0x7200, 0x8204, 0x0048, 0x3242, 0x730c, 0xa384, 0x00ff,
+ 0x00c0, 0x324e, 0xa184, 0x0007, 0x0079, 0x3246, 0x3250, 0x327b,
+ 0x324e, 0x327b, 0x324e, 0x32d4, 0x324e, 0x32d2, 0x1078, 0x1e01,
+ 0x7007, 0x0002, 0x8aff, 0x00c0, 0x3259, 0x2049, 0x0000, 0x0078,
+ 0x325d, 0x1078, 0x344b, 0x00c0, 0x3259, 0x2704, 0xac00, 0xa088,
+ 0x0002, 0x2104, 0x8108, 0x6892, 0x2104, 0x688e, 0x8a07, 0x077e,
+ 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x3272, 0xa7ba, 0x3179,
+ 0x0078, 0x3274, 0xa7ba, 0x3171, 0x007f, 0xa73d, 0x2c00, 0x6886,
+ 0x6f8a, 0x077f, 0x007c, 0x7007, 0x0002, 0x8aff, 0x00c0, 0x3282,
+ 0x0078, 0x3286, 0x1078, 0x344b, 0x00c0, 0x3282, 0x007c, 0x7108,
+ 0x7008, 0xa106, 0x00c0, 0x3287, 0xa184, 0x4000, 0x00c0, 0x3287,
+ 0x7007, 0x0012, 0x7108, 0x7008, 0xa106, 0x00c0, 0x3292, 0xa184,
+ 0x4000, 0x00c0, 0x3292, 0x00e0, 0x329b, 0x2091, 0x6000, 0x00e0,
+ 0x329f, 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004,
+ 0xa084, 0x0008, 0x00c0, 0x32a7, 0x7007, 0x0012, 0x7108, 0x8103,
+ 0x0048, 0x32ac, 0x7003, 0x0000, 0x7000, 0xa005, 0x00c0, 0x32c0,
+ 0x7004, 0xa005, 0x00c0, 0x32c0, 0x700c, 0xa005, 0x0040, 0x32c2,
+ 0x0078, 0x32a3, 0x2049, 0x0000, 0x1078, 0x2eef, 0x6818, 0xa084,
+ 0x8000, 0x0040, 0x32cd, 0x681b, 0x0002, 0x007c, 0x1078, 0x1e01,
+ 0x1078, 0x1e01, 0x1078, 0x3332, 0x7210, 0x7114, 0x700c, 0xa09c,
+ 0x00ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x3332,
+ 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100,
+ 0xa31b, 0x2400, 0xa305, 0x0040, 0x32f7, 0x00c8, 0x32f7, 0x8412,
+ 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x32de, 0x2b60,
+ 0x8a07, 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x3303, 0xa7ba,
+ 0x3179, 0x0078, 0x3305, 0xa7ba, 0x3171, 0x007f, 0xa73d, 0x2c00,
+ 0x6886, 0x6f8a, 0x6c92, 0x6b8e, 0x1078, 0x31b9, 0x007c, 0x8738,
+ 0x2704, 0xa005, 0x00c0, 0x3322, 0x609c, 0xa005, 0x0040, 0x332f,
+ 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x317f, 0x203c, 0x87fb,
+ 0x1040, 0x1e01, 0x8a51, 0x0040, 0x332e, 0x7008, 0x7508, 0xa52e,
+ 0x00c0, 0x3325, 0xa084, 0x0003, 0xa086, 0x0003, 0x007c, 0x2051,
+ 0x0000, 0x007c, 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x3346,
+ 0x6000, 0xa064, 0x00c0, 0x333d, 0x2d60, 0x6004, 0xa084, 0x000f,
+ 0xa080, 0x318f, 0x203c, 0x87fb, 0x1040, 0x1e01, 0x007c, 0x127e,
+ 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c,
+ 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, 0x6804,
+ 0xa084, 0x0008, 0x007f, 0x0040, 0x3361, 0xa0b8, 0x3179, 0x0078,
+ 0x3363, 0xa0b8, 0x3171, 0x7e08, 0xa6b5, 0x000c, 0x681c, 0xa084,
+ 0x0040, 0x0040, 0x336d, 0xa6b5, 0x0001, 0x7007, 0x0004, 0x7004,
+ 0xa084, 0x0004, 0x00c0, 0x336f, 0x2400, 0xa305, 0x00c0, 0x337a,
+ 0x0078, 0x339e, 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400,
+ 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, 0x0008, 0x0040, 0x338e,
+ 0x6010, 0xa001, 0x7022, 0x6014, 0xa001, 0x7026, 0x6208, 0x2400,
+ 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007,
+ 0x0001, 0x2b60, 0x1078, 0x330f, 0x0078, 0x33a0, 0x1078, 0x344b,
+ 0x00c0, 0x339e, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091,
+ 0x2200, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+ 0x33ac, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e,
+ 0x2091, 0x2200, 0x0d7f, 0x2049, 0x33b6, 0x7007, 0x0004, 0x7004,
+ 0xa084, 0x0004, 0x00c0, 0x33bf, 0x7e08, 0xa6b5, 0x000c, 0x681c,
+ 0xa084, 0x0020, 0x00c0, 0x33ce, 0xa6b5, 0x0001, 0x6828, 0x2050,
+ 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x317f, 0x273c, 0x87fb,
+ 0x00c0, 0x33e4, 0x0048, 0x33de, 0x1078, 0x1e01, 0x689c, 0xa065,
+ 0x0040, 0x33e8, 0x0078, 0x33d1, 0x1078, 0x344b, 0x00c0, 0x33e4,
+ 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e, 0x0d7e, 0x2091,
+ 0x2200, 0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5, 0x000c, 0x681c,
+ 0xa084, 0x0040, 0x0040, 0x33fe, 0xa6b5, 0x0001, 0x2049, 0x33eb,
+ 0x6828, 0xa055, 0x0040, 0x3448, 0x2d70, 0x2e60, 0x7004, 0xa0bc,
+ 0x000f, 0xa7b8, 0x317f, 0x273c, 0x87fb, 0x00c0, 0x341a, 0x0048,
+ 0x3413, 0x1078, 0x1e01, 0x709c, 0xa075, 0x2060, 0x0040, 0x3448,
+ 0x0078, 0x3406, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b,
+ 0x0048, 0x3435, 0x8a51, 0x00c0, 0x3427, 0x1078, 0x1e01, 0x8738,
+ 0x2704, 0xa005, 0x00c0, 0x341b, 0x709c, 0xa075, 0x2060, 0x0040,
+ 0x3448, 0x2039, 0x3171, 0x0078, 0x3406, 0x8422, 0x8420, 0x831a,
+ 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b,
+ 0x00c8, 0x3444, 0x1078, 0x1e01, 0x2071, 0x0020, 0x0078, 0x336d,
+ 0x127f, 0x2000, 0x007c, 0x7008, 0x7508, 0xa52e, 0x00c0, 0x344b,
+ 0xa084, 0x0003, 0xa086, 0x0003, 0x0040, 0x3473, 0x2704, 0xac08,
+ 0x2104, 0x701a, 0x8108, 0x2104, 0x701e, 0x8108, 0x2104, 0x7012,
+ 0x8108, 0x2104, 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, 0x346e,
+ 0x8108, 0x2104, 0x7022, 0x8108, 0x2104, 0x7026, 0x7602, 0x7007,
+ 0x0001, 0x1078, 0x330f, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091,
+ 0x2200, 0x2049, 0x3474, 0x0d7f, 0x087f, 0x7108, 0x7008, 0xa106,
+ 0x00c0, 0x347d, 0xa184, 0x4000, 0x00c0, 0x347d, 0xa184, 0x0003,
+ 0x00c0, 0x3492, 0x6828, 0xa005, 0x0040, 0x34a0, 0x1078, 0x32d4,
+ 0x0078, 0x34a0, 0x00a0, 0x3499, 0x7108, 0x1078, 0x320f, 0x0078,
+ 0x347d, 0x7007, 0x0010, 0x00a0, 0x349b, 0x7108, 0x1078, 0x320f,
+ 0x7008, 0xa086, 0x0008, 0x00c0, 0x347d, 0x7003, 0x0000, 0x2049,
+ 0x0000, 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e,
+ 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x34ac, 0xad80, 0x0011,
+ 0x20a0, 0x2099, 0x0031, 0x700c, 0xa084, 0x00ff, 0x682a, 0x7007,
+ 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, 0x34ca, 0x8000,
+ 0x80ac, 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+ 0x34cc, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f,
+ 0x127f, 0x2000, 0x007c, 0x2091, 0x6000, 0x78b0, 0xa005, 0x0040,
+ 0x34f0, 0x797c, 0x70d0, 0xa106, 0x00c0, 0x34f0, 0x7804, 0xa005,
+ 0x0040, 0x34f0, 0x7807, 0x0000, 0x0068, 0x34f0, 0x2091, 0x4080,
+ 0x7820, 0x8001, 0x7822, 0x00c0, 0x3550, 0x7824, 0x7822, 0x2091,
+ 0x8000, 0x78e0, 0xa005, 0x0040, 0x351d, 0x78c4, 0xa005, 0x00c0,
+ 0x351d, 0x3a10, 0xa284, 0x0002, 0x00c0, 0x350d, 0x78c7, 0x0007,
+ 0x2009, 0xff01, 0x200a, 0x0078, 0x351d, 0xa284, 0x0001, 0x00c0,
+ 0x3515, 0x78df, 0x0000, 0x0078, 0x351d, 0x78dc, 0xa005, 0x00c0,
+ 0x351d, 0x78c7, 0x0008, 0x78df, 0x0001, 0x2069, 0x3740, 0x6800,
+ 0xa084, 0x0007, 0x0040, 0x3534, 0xa086, 0x0002, 0x0040, 0x3534,
+ 0x6830, 0xa00d, 0x0040, 0x3534, 0x2104, 0xa005, 0x0040, 0x3534,
+ 0x8001, 0x200a, 0x0040, 0x35f2, 0x7848, 0xa005, 0x0040, 0x3550,
+ 0x8001, 0x784a, 0x00c0, 0x3550, 0x0f7e, 0x2079, 0x0100, 0x1078,
+ 0x2fa6, 0x0f7f, 0x1078, 0x1c4b, 0x68c4, 0xa005, 0x0040, 0x3550,
+ 0x8001, 0x68c6, 0x00c0, 0x3550, 0x68a3, 0x0000, 0x68a7, 0x0001,
+ 0x1078, 0x3557, 0x1078, 0x357c, 0x2091, 0x8001, 0x007c, 0x7834,
+ 0x8001, 0x7836, 0x00c0, 0x357b, 0x7838, 0x7836, 0x2091, 0x8000,
+ 0x7844, 0xa005, 0x00c0, 0x3566, 0x2001, 0x0101, 0x8001, 0x7846,
+ 0xa080, 0x4080, 0x2040, 0x2004, 0xa065, 0x0040, 0x357b, 0x6024,
+ 0xa005, 0x0040, 0x3577, 0x8001, 0x6026, 0x0040, 0x35ab, 0x6000,
+ 0x2c40, 0x0078, 0x356c, 0x007c, 0x7828, 0x8001, 0x782a, 0x00c0,
+ 0x35aa, 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, 0x3589, 0x2001,
+ 0x0080, 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, 0x8003, 0xa090,
+ 0x3880, 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, 0x0040, 0x35aa,
+ 0xa290, 0x0009, 0x2204, 0xa005, 0x0040, 0x35a2, 0x8001, 0x2012,
+ 0x00c0, 0x35aa, 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080, 0x201a,
+ 0x1078, 0x1c4b, 0x007c, 0x2069, 0x3740, 0x6800, 0xa005, 0x0040,
+ 0x35b5, 0x683c, 0xac06, 0x0040, 0x35f2, 0x601b, 0x0006, 0x60b4,
+ 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060,
+ 0x6022, 0x6000, 0x2042, 0x6714, 0x6fb6, 0x1078, 0x1828, 0x6818,
+ 0xa005, 0x0040, 0x35cd, 0x8001, 0x681a, 0x6808, 0xa084, 0xffef,
+ 0x680a, 0x6810, 0x8001, 0x00d0, 0x35d7, 0x1078, 0x1e01, 0x6812,
+ 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x1990, 0x2069,
+ 0x3740, 0x2001, 0x0006, 0x68a2, 0x7944, 0xa184, 0x0100, 0x00c0,
+ 0x35ed, 0x69ba, 0x2001, 0x0004, 0x68a2, 0x1078, 0x1c46, 0x2091,
+ 0x8001, 0x007c, 0x2009, 0x374f, 0x2164, 0x2069, 0x0100, 0x1078,
+ 0x1dac, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e, 0x6020,
+ 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033,
+ 0x0000, 0x6830, 0xa084, 0x0040, 0x0040, 0x362e, 0x684b, 0x0004,
+ 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, 0x0040, 0x361b, 0x0070,
+ 0x361b, 0x0078, 0x3612, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848,
+ 0xa084, 0x0001, 0x0040, 0x3628, 0x0070, 0x3628, 0x0078, 0x361f,
+ 0x20a9, 0x00fa, 0x0070, 0x362e, 0x0078, 0x362a, 0x6808, 0xa084,
+ 0xfffd, 0x680a, 0x681b, 0x0047, 0x2009, 0x3768, 0x200b, 0x0007,
+ 0x784c, 0x784a, 0x2091, 0x8001, 0x007c, 0x2079, 0x3700, 0x1078,
+ 0x3668, 0x1078, 0x364c, 0x1078, 0x365a, 0x7833, 0x0000, 0x7847,
+ 0x0000, 0x784b, 0x0000, 0x007c, 0x2019, 0x000c, 0x2011, 0x3746,
+ 0x2204, 0xa086, 0x003c, 0x0040, 0x3657, 0x2019, 0x0008, 0x7b2a,
+ 0x7b2e, 0x007c, 0x2019, 0x0039, 0x2011, 0x3746, 0x2204, 0xa086,
+ 0x003c, 0x0040, 0x3665, 0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c,
+ 0x2019, 0x3971, 0x2011, 0x3746, 0x2204, 0xa086, 0x003c, 0x0040,
+ 0x3673, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x783f, 0x0000, 0x7843,
+ 0x000a, 0x007c, 0x3f42
+};
+unsigned short risc_code_length01 = 0x267b;
+
diff --git a/private/ntos/miniport/qlogic/makedsk.bat b/private/ntos/miniport/qlogic/makedsk.bat
new file mode 100644
index 000000000..900260f9f
--- /dev/null
+++ b/private/ntos/miniport/qlogic/makedsk.bat
@@ -0,0 +1,4 @@
+copy oemsetup.inf a:\
+copy ql10wnt.sys a:\
+copy qlscsi a:\
+copy txtsetup.oem a:\
diff --git a/private/ntos/miniport/qlogic/makefile b/private/ntos/miniport/qlogic/makefile
new file mode 100644
index 000000000..58189757d
--- /dev/null
+++ b/private/ntos/miniport/qlogic/makefile
@@ -0,0 +1,7 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/qlogic/oemsetup.inf b/private/ntos/miniport/qlogic/oemsetup.inf
new file mode 100644
index 000000000..8ec7286f1
--- /dev/null
+++ b/private/ntos/miniport/qlogic/oemsetup.inf
@@ -0,0 +1,571 @@
+;-----------------------------------------------------------------------
+; OPTION TYPE
+; -----------
+; This identifies the Option type we are dealing with. The different
+; possible types are:
+;
+; COMPUTER, VIDEO, POINTER, KEYBOARD, LAYOUT, SCSI, TAPE, PRINTER, ...
+;-----------------------------------------------------------------------
+
+[Identification]
+ OptionType = SCSI
+
+;-----------------------------------------------------------------------
+; LANGUAGES SUPPORTED
+; -------------------
+;
+; The languages supported by the INF, For every language supported
+; we need to have a separate text section for every displayable text
+; section.
+;
+;-----------------------------------------------------------------------
+
+[LanguagesSupported]
+ ENG
+
+
+;-----------------------------------------------------------------------
+; OPTION LIST
+; -----------
+; This section lists the Option key names. These keys are locale
+; independent and used to represent the option in a locale independent
+; manner.
+;
+;-----------------------------------------------------------------------
+
+[Options]
+ "QLA100" = ql10wnt
+ "QLA10035" = ql10nt35
+
+;-----------------------------------------------------------------------
+; OPTION TEXT SECTION
+; -------------------
+; These are text strings used to identify the option to the user. There
+; are separate sections for each language supported. The format of the
+; section name is "OptionsText" concatenated with the Language represented
+; by the section.
+;
+;-----------------------------------------------------------------------
+
+[OptionsTextENG]
+ "QLA100" = "QLogic Fast!SCSI/QLA100 (Windows NT V3.1)"
+ "QLA10035" = "QLogic Fast!SCSI/QLA100 (Windows NT V3.5)"
+
+;-----------------------------------------------------------------------------------------
+; SCSI MINIPORT DRIVERS:
+;
+; Order of the information:
+;
+; Class driver = Type, Group, ErrorControl, Tag, EventMessageFile, TypesSupported
+;
+;-----------------------------------------------------------------------------------------
+
+[MiniportDrivers]
+ ql10wnt = !SERVICE_KERNEL_DRIVER, "SCSI Miniport", !SERVICE_ERROR_NORMAL, 31, %SystemRoot%\System32\IoLogMsg.dll , 7
+ ql10nt35 = !SERVICE_KERNEL_DRIVER, "SCSI Miniport", !SERVICE_ERROR_NORMAL, 31, %SystemRoot%\System32\IoLogMsg.dll , 7
+
+;---------------------------------------------------------------------------
+; 1. Identify
+;
+; DESCRIPTION: To verify that this INF deals with the same type of options
+; as we are choosing currently.
+;
+; INPUT: None
+;
+; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL
+; $($R1): Option Type (COMPUTER ...)
+; $($R2): Diskette description
+;---------------------------------------------------------------------------
+
+[Identify]
+ ;
+ ;
+ read-syms Identification
+
+ set Status = STATUS_SUCCESSFUL
+ set Identifier = $(OptionType)
+ set Media = #("Source Media Descriptions", 1, 1)
+
+ Return $(Status) $(Identifier) $(Media)
+
+
+
+;------------------------------------------------------------------------
+; 2. ReturnOptions:
+;
+; DESCRIPTION: To return the option list supported by this INF and the
+; localised text list representing the options.
+;
+;
+; INPUT: $($0): Language used. ( ENG | FRN | ... )
+;
+; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL |
+; STATUS_NOLANGUAGE
+; STATUS_FAILED
+;
+; $($R1): Option List
+; $($R2): Option Text List
+;------------------------------------------------------------------------
+
+[ReturnOptions]
+ ;
+ ;
+ set Status = STATUS_FAILED
+ set OptionList = {}
+ set OptionTextList = {}
+
+ ;
+ ; Check if the language requested is supported
+ ;
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) in $(LanguageList)
+ goto returnoptions
+ else
+ set Status = STATUS_NOLANGUAGE
+ goto finish_ReturnOptions
+ endif
+
+ ;
+ ; form a list of all the options and another of the text representing
+ ;
+
+returnoptions = +
+ set OptionList = ^(Options, 0)
+ set OptionTextList = ^(OptionsText$($0), 1)
+ set Status = STATUS_SUCCESSFUL
+
+finish_ReturnOptions = +
+ Return $(Status) $(OptionList) $(OptionTextList)
+
+
+;
+; 3. InstallOption:
+;
+; FUNCTION: To copy files representing Options
+; To configure the installed option
+; To update the registry for the installed option
+;
+; INPUT: $($0): Language to use
+; $($1): OptionID to install
+; $($2): SourceDirectory
+; $($3): AddCopy (YES | NO)
+; $($4): DoCopy (YES | NO)
+; $($5): DoConfig (YES | NO)
+;
+; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL |
+; STATUS_NOLANGUAGE |
+; STATUS_USERCANCEL |
+; STATUS_FAILED
+;
+
+[InstallOption]
+
+ ;
+ ; Set default values for
+ ;
+ set Status = STATUS_FAILED
+ set DrivesToFree = {}
+
+ ;
+ ; extract parameters
+ ;
+ set Option = $($1)
+ set SrcDir = $($2)
+ set AddCopy = $($3)
+ set DoCopy = $($4)
+ set DoConfig = $($5)
+
+ ;
+ ; Check if the language requested is supported
+ ;
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) in $(LanguageList)
+ else
+ set Status = STATUS_NOLANGUAGE
+ goto finish_InstallOption
+ endif
+ read-syms Strings$($0)
+
+ ;
+ ; check to see if Option is supported.
+ ;
+
+ set OptionList = ^(Options, 0)
+ ifcontains $(Option) in $(OptionList)
+ else
+ Debug-Output "SCSI.INF: SCSI option is not supported."
+ goto finish_InstallOption
+ endif
+ set OptionList = ""
+
+ ;
+ ; Option has been defined already
+ ;
+
+ set MiniportDriver = #(Options, $(Option), 1)
+ set Type = $(#(MiniportDrivers, $(MiniportDriver), 1))
+ set Group = #(MiniportDrivers, $(MiniportDriver), 2)
+ set ErrorControl = $(#(MiniportDrivers, $(MiniportDriver), 3))
+ set Tag = #(MiniportDrivers, $(MiniportDriver), 4)
+ set EventMessageFile = #(MiniportDrivers, $(MiniportDriver), 5)
+ set TypesSupported = #(MiniportDrivers, $(MiniportDriver), 6)
+
+ set Start = $(!SERVICE_BOOT_START)
+
+installtheoption = +
+
+ ;
+ ; Code to add files to copy list
+ ;
+
+ ifstr(i) $(AddCopy) == "YES"
+ set DoActualCopy = NO
+ set FileToCheck = #(Files-ScsiMiniportDrivers, $(MiniportDriver), 2)
+ LibraryProcedure STATUS,$(!LIBHANDLE),CheckFileExistance $(!STF_WINDOWSSYSPATH)"\drivers\"$(FileToCheck)
+ ifstr(i) $(STATUS) == NO
+ set DoActualCopy = YES
+ endif
+
+ ifstr(i) $(DoActualCopy) == NO
+ shell "subroutn.inf" DriversExist $($0) $(String1)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "SCSI.INF: shelling DriversExist failed"
+ goto finish_InstallOption
+ endif
+
+ ifstr(i) $($R0) == STATUS_CURRENT
+ else-ifstr(i) $($R0) == STATUS_NEW
+ set DoActualCopy = YES
+ else-ifstr(i) $($R0) == STATUS_USERCANCEL
+ Debug-Output "SCSI.INF: User cancelled SCSI installation"
+ goto finish_InstallOption
+ else
+ Debug-Output "SCSI.INF: Error reported in DriversExist routine in SUBROUTN.INF"
+ goto finish_InstallOption
+ endif
+ endif
+
+ ifstr(i) $(DoActualCopy) == YES
+
+ shell "subroutn.inf" DoAskSourceEx $(SrcDir) $(String2)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "SCSI.INF: shelling DoAskSourceEx failed"
+ goto finish_InstallOption
+ endif
+
+ ifstr(i) $($R0) == STATUS_SUCCESSFUL
+ set SrcDir = $($R1)
+ ifstr(i) $($R2) != ""
+ set DrivesToFree = >($(DrivesToFree), $($R2))
+ endif
+ else
+ Debug-Output "SCSI.INF: User cancelled asking source."
+ goto finish_InstallOption
+ endif
+
+ install Install-AddCopyOption
+ ifstr(i) $(STF_INSTALL_OUTCOME) != "STF_SUCCESS"
+ Debug-Output "Adding SCSI files to copy list failed"
+ goto finish_InstallOption
+ endif
+ else
+ set DoCopy = NO
+ endif
+
+ endif
+
+ ifstr(i) $(DoCopy) == "YES"
+ read-syms ProgressCopy$($0)
+ install Install-DoCopyOption
+ ifstr(i) $(STF_INSTALL_OUTCOME) == "STF_FAILURE"
+ Debug-Output "Copying files failed"
+ goto finish_InstallOption
+ else-ifstr(i) $(STF_INSTALL_OUTCOME) == "STF_USERQUIT"
+ set Status = STATUS_USERCANCEL
+ goto finish_InstallOption
+ endif
+ endif
+
+ ifstr(i) $(DoConfig) == "YES"
+ ;
+ ; first run a privilege check on modifying the setup node
+ ;
+
+ shell "registry.inf" CheckSetupModify
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto finish_InstallOption
+ endif
+
+ ifstr(i) $($R0) != STATUS_SUCCESSFUL
+ goto finish_InstallOption
+ endif
+
+ ;
+ ; then make a new SCSI entry, the entry is created automatically
+ ; enabled
+ ;
+
+ set ServiceNode = $(MiniportDriver)
+ set ServiceBinary = System32\drivers\#(Files-ScsiMiniportDrivers, $(MiniportDriver), 2)
+
+ set ServicesValues = { +
+ {Type, 0, $(!REG_VT_DWORD), $(Type) }, +
+ {Start, 0, $(!REG_VT_DWORD), $(Start) }, +
+ {Group, 0, $(!REG_VT_SZ), $(Group) }, +
+ {ErrorControl, 0, $(!REG_VT_DWORD), $(ErrorControl) }, +
+ {Tag, 0, $(!REG_VT_DWORD), $(Tag) }, +
+ {BinaryPathName, 0, $(!REG_VT_EXPAND_SZ), $(ServiceBinary) } +
+ }
+ set ParametersValues = ""
+ set DeviceValues = {}
+ set EventLogValues = { +
+ {EventMessageFile, 0, $(!REG_VT_EXPAND_SZ), $(EventMessageFile) }, +
+ {TypesSupported, 0, $(!REG_VT_DWORD), $(TypesSupported) } +
+ }
+
+ shell "registry.inf" MakeServicesEntry $(ServiceNode) +
+ $(ServicesValues) +
+ $(ParametersValues) +
+ $(DeviceValues) +
+ $(EventLogValues) +
+ Parameters
+
+
+
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "Couldn't execute MakeServicesEntry in registry.inf"
+ goto finish_InstallOption
+ endif
+
+ ifstr(i) $($R0) != STATUS_SUCCESSFUL
+ Debug-Output "MakeServicesEntry failed for SCSI"
+ goto finish_InstallOption
+ endif
+
+ endif
+
+ set Status = STATUS_SUCCESSFUL
+finish_InstallOption = +
+ ForListDo $(DrivesToFree)
+ LibraryProcedure STATUS,$(!LIBHANDLE), DeleteNetConnection $($) "TRUE"
+ EndForListDo
+
+ Return $(Status)
+
+
+[Install-AddCopyOption]
+
+ ;
+ ; Add the files to the copy list
+ ;
+ AddSectionKeyFileToCopyList Files-ScsiMiniportDrivers +
+ $(MiniportDriver) +
+ $(SrcDir) +
+ $(!STF_WINDOWSSYSPATH)\drivers
+
+ exit
+
+
+[Install-DoCopyOption]
+
+ ;
+ ; Copy files in the copy list
+ ;
+ CopyFilesInCopyList
+ exit
+
+;-------------------------------------------------------------------------
+; 4. DeInstallOption:
+;
+; FUNCTION: To remove files representing Option
+; To remove the registry entry corresponding to the Option
+;
+; INPUT: $($0): Language to use
+; $($1): OptionID to install
+;
+; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL |
+; STATUS_NOLANGUAGE |
+; STATUS_USERCANCEL |
+; STATUS_FAILED
+;-------------------------------------------------------------------------
+[DeInstallOption]
+ ;
+ ; Set default values for
+ ;
+ set Status = STATUS_FAILED
+ ;
+ ; extract parameters
+ ;
+ set Option = $($1)
+
+ ;
+ ; Check if the language requested is supported
+ ;
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) in $(LanguageList)
+ else
+ set Status = STATUS_NOLANGUAGE
+ goto finish_DeInstallOption
+ endif
+ read-syms Strings$($0)
+
+ ;
+ ; check to see if Option is supported.
+ ;
+
+ set OptionList = ^(Options, 0)
+ ifcontains $(Option) in $(OptionList)
+ else
+ goto finish_DeInstallOption
+ endif
+ set OptionList = ""
+
+ ;
+ ; fetch details about option
+ ;
+
+ set MiniportDriver = #(Options, $(Option), 1)
+ set MiniportFile = #(Files-ScsiMiniportDrivers, $(MiniportDriver), 2)
+ set FilePath = $(!STF_WINDOWSSYSPATH)"\drivers\"$(MiniportFile)
+
+ ;
+ ; check to see if file is installed
+ ; if not give success
+ ;
+
+ LibraryProcedure STATUS,$(!LIBHANDLE),CheckFileExistance $(FilePath)
+ ifstr(i) $(STATUS) == "NO"
+ set Status = STATUS_SUCCESSFUL
+ goto finish_DeInstallOption
+ endif
+
+ shell "registry.inf" GetServicesEntryStart $(MiniportDriver)
+ ifstr(i) $($R0) != "STATUS_SUCCESSFUL"
+ ; this could happen if there is no start value or there is no
+ ; key, in which case the option is not installed
+ set Status = STATUS_SUCCESSFUL
+ goto finish_DeInstallOption
+ endif
+
+ ifstr(i) $($R1) == $(!SERVICE_BOOT_START)
+ shell "subroutn.inf" SetupMessage $(!STF_LANGUAGE) "WARNING" $(String3)
+ ifstr(i) $($R0) != STATUS_SUCCESSFUL
+ goto do_removal
+ endif
+ ifstr(i) $($R1) == "CANCEL"
+ goto finish_DeInstallOption
+ endif
+ endif
+
+do_removal =+
+ ;
+ ; disable the registry entry
+ ;
+
+ shell "registry.inf" RemoveServicesEntry $(MiniportDriver)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "SCSI.INF: Failed to shell RemoveServicesEntry"
+ goto finish_DeInstallOption
+ endif
+
+ ifstr(i) $($R0) != STATUS_SUCCESSFUL
+ Debug-Output "SCSI.INF: Failed to disable services entry"
+ goto finish_DeInstallOption
+ endif
+
+ ;
+ ; we won't remove the file because we can only do so during the next boot.
+ ; if the user chooses to reinstall the same driver during this boot
+ ; he will still end up deleting the driver on next boot. if the file
+ ; should be deleted a warning should be put up saying that the user should
+ ; not try to reinstall the driver during this boot
+ ;
+ ; AddFileToDeleteList $(FilePath)
+
+ set Status = STATUS_SUCCESSFUL
+
+finish_DeInstallOption =+
+ return $(Status)
+
+
+;-------------------------------------------------------------------------
+; 5. GetInstalledOptions:
+;
+; FUNCTION: To find out the list of options which are installed
+;
+; INPUT: $($0): Language to Use
+;
+; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL |
+; STATUS_FAILED
+;
+; $($R1): List of options installed
+; $($R2): Option installed Text List
+;-------------------------------------------------------------------------
+[GetInstalledOptions]
+ set Status = STATUS_FAILED
+ set InstalledOptions = {}
+ set InstalledOptionsText = {}
+
+ ;
+ ; Check if the language requested is supported
+ ;
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) in $(LanguageList)
+ else
+ set Status = STATUS_NOLANGUAGE
+ goto finish_GetInstalledOptions
+ endif
+
+ set OptionList = ^(Options, 0)
+ ForListDo $(OptionList)
+ set MiniportDriver = #(Options, $($), 1)
+ set MiniportFile = #(Files-ScsiMiniportDrivers, $(MiniportDriver), 2)
+ set FilePath = $(!STF_WINDOWSSYSPATH)"\drivers\"$(MiniportFile)
+ LibraryProcedure STATUS,$(!LIBHANDLE),CheckFileExistance $(FilePath)
+ ifstr(i) $(STATUS) == "YES"
+ shell "registry.inf" GetServicesEntryStart $(MiniportDriver)
+ ifint $($ShellCode) == $(!SHELL_CODE_OK)
+ ifstr(i) $($R0) == STATUS_SUCCESSFUL
+ ifstr(i) $($R1) != $(!SERVICE_DISABLED)
+
+ set OptionText = #(OptionsText$($0), $($), 1)
+ set InstalledOptions = >($(InstalledOptions), $($))
+ set InstalledOptionsText = >($(InstalledOptionsText), $(OptionText))
+
+ endif
+ endif
+ endif
+ endif
+ EndForListDo
+ set Status = STATUS_SUCCESSFUL
+finish_GetInstalledOptions =+
+ Return $(Status) $(InstalledOptions) $(InstalledOptionsText)
+
+
+;**************************************************************************
+; PROGRESS GUAGE VARIABLES
+;**************************************************************************
+
+[ProgressCopyENG]
+ ProCaption = "Windows NT Setup"
+ ProCancel = "Cancel"
+ ProCancelMsg = "Windows NT is not correcly installed. Are you sure you want "+
+ "to cancel copying files?"
+ ProCancelCap = "Setup Message"
+ ProText1 = "Copying:"
+ ProText2 = "To:"
+
+[StringsENG]
+ String1 = "SCSI Adapter"
+ String2 = "Please enter the full path to the OEM SCSI "+
+ "Adapter files. Then choose Continue."
+ String3 = "The SCSI Adapter has been marked as a boot device. Removing "+
+ "it may cause the system not to boot."$(!LF)$(!LF)"Are you sure "+
+ "you want to remove the Adapter."
+
+[Source Media Descriptions]
+ 1 = "QLogic SCSI Software Diskette" , TAGFILE = qlscsi
+
+[Files-ScsiMiniportDrivers]
+ql10wnt = 1,ql10wnt.sys , SIZE=36864
+ql10nt35 = 1,ql10nt35.sys , SIZE=36864
diff --git a/private/ntos/miniport/qlogic/qlisp.c b/private/ntos/miniport/qlogic/qlisp.c
new file mode 100644
index 000000000..0d3991dfd
--- /dev/null
+++ b/private/ntos/miniport/qlogic/qlisp.c
@@ -0,0 +1,3050 @@
+/************************************************************************/
+/* */
+/* Driver Name: QL10WNT.SYS - NT Miniport Driver for QLogic ISP1020 */
+/* */
+/* Source File Name: QLISP.C */
+/* */
+/* Function: Main driver module containing code for processing I/O */
+/* requests from NT and all code for interfacing to the */
+/* ISP1020 chip. */
+/* */
+/************************************************************************/
+/* */
+/* NOTICE */
+/* */
+/* COPYRIGHT 1994-1995 QLOGIC CORPORATION */
+/* ALL RIGHTS RESERVED */
+/* */
+/* This computer program is CONFIDENTIAL and a TRADE SECRET */
+/* of QLOGIC CORPORATION. The receipt or possesion of this */
+/* program does not convey any rights to reproduce or disclose */
+/* its contents, or to manufacture, use, or sell anything that */
+/* it may describe, in whole or in part, without the specific */
+/* written consent of QLOGIC CORPORATION. Any reproduction of */
+/* this program without the express written consent of QLOGIC */
+/* CORPORATION is a violation of the copyright laws and may */
+/* subject you to criminal prosecution. */
+/* */
+/************************************************************************/
+/* */
+/* Revision history: */
+/* */
+/* 1.00 2/23/94 TWT Initial version for NT Version 3.1 */
+/* */
+/* 1.01 5/2/94 TWT Fix interrupt sharing problem (set */
+/* InterruptMode to LevelSensitive) */
+/* */
+/* 1.02 5/6/94 TWT Force PCI bus master enabled */
+/* */
+/* 1.03 5/23/94 TWT Add conditional assembly for supporting */
+/* new features of NT Version 3.5, set bus */
+/* type to PCI and let SCSI port driver */
+/* get PCI configuration, support SCSI */
+/* IDs up to 15 (NT 3.5 driver only) */
+/* */
+/* 1.10 6/3/94 TWT Modify QLFindAdapter routine for NT 3.5 */
+/* to use NT service calls to access PCI */
+/* config space (this will allow driver to */
+/* operate on all PCI systems supported by */
+/* NT), modify QLFindAdapter routine for */
+/* NT 3.1 to support both methods of */
+/* accessing PCI config space */
+/* */
+/* 1.11 6/8/94 TWT Fix problem with accessing config space */
+/* on Opti chip set (can only read data */
+/* reg one time per write to address reg) */
+/* */
+/* 1.12 7/26/94 TWT Update RISC code to version 1.14 */
+/* */
+/* 1.13 8/17/94 TWT Set only 1 RISC retry and no delay */
+/* (NT 3.5 Disk Administrator problem) */
+/* */
+/* 2.00 8/11/94 TWT Modifications for the Chicago OS, add */
+/* QLAdapterState entry, remove path from */
+/* includes, modify NovramDelay to call */
+/* ScsiPortStallExecution, update NOVRAM */
+/* drive default parameters */
+/* */
+/* 2.01 8/25/94 TWT Replaced QLFindAdapter with code from */
+/* CHC, added support for SRB flag to */
+/* disable auto request sense (requires */
+/* RISC code version 1.15), add code to */
+/* QLAdapterState for returning control to */
+/* ROM BIOS on shutdown, check for passed */
+/* in InitiatorBusId, update RISC code to */
+/* version 1.15, add temporary conditional */
+/* assembly code for Chicago beta versions */
+/* not supporting ConfigInfo->SlotNumber */
+/* */
+/* 2.02 11/17/94 TWT Don't issue error log message for */
+/* selection timeout on Inquiry command, */
+/* restart RISC command queue after check */
+/* condition and auto-sense disabled, add */
+/* support for soft termination, add */
+/* support for 60 MHz adapters, fix bug */
+/* leaving tagged queueing disabled if */
+/* NVRAM not present or not programmed */
+/* */
+/* 2.03 11/28/94 TWT Update RISC code to version 1.16 */
+/* */
+/* 2.04 11/30/94 TWT Remove temporary code for pre-beta 2 */
+/* version of Chicago (SlotNumber is now */
+/* supported) */
+/* */
+/* 2.05 12/19/94 TWT Added reset delays to QLResetIsp to fix */
+/* problem on faster Alpha machines */
+/* */
+/* 2.06 1/4/95 TWT Set MaximumNumberOfTargets to 15 instead*/
+/* of 16 for Chicago Beta 2 (if passed in */
+/* value is 7) */
+/* */
+/* 2.07 1/6/95 TWT Add support for QLVER utility and */
+/* copyright string */
+/* */
+/* 2.08 2/7/95 TWT Update build and install scripts for */
+/* driver name change to match MS release, */
+/* modify init code to skip RISC code load */
+/* if newer version already loaded, update */
+/* RISC code to version 1.18, add driver */
+/* delay to match RISC SCSI reset delay, */
+/* cleanup unneeded test in MailboxCommand */
+/* */
+/* 2.09 3/28/95 TWT Update RISC code to version 1.22 */
+/* */
+/* 2.10 4/14/95 TWT Update RISC code to version 1.25 */
+/* */
+/* 2.11 4/27/95 TWT Update RISC code to version 1.27, add */
+/* software termination modification for */
+/* DEC boards with ISP1020A */
+/* */
+/* 2.12 5/5/95 TWT Fix problem with system hang when RISC */
+/* request queue full and SRB returned to */
+/* port driver with FALSE status (thanks */
+/* to Chao Chen for finding this problem) */
+/* */
+/* 2.13 5/9/95 TWT Renamed subroutine WaitQueueSpace to */
+/* CheckQueueSpace and modified to not wait*/
+/* for space in the RISC request queue, */
+/* modified QLStartIo to throttle back cmds*/
+/* from port driver when request queue is */
+/* nearly full, add delays to QLResetIsp */
+/* */
+/************************************************************************/
+
+
+// #define NT_VERSION_31 1 // If defined, compile for NT Version 3.1
+
+#include "miniport.h"
+#include "scsi.h"
+#include "qlisp.h"
+
+#if DBG
+#define QLPrint(arg) ScsiDebugPrint arg
+#else
+#define QLPrint(arg)
+#endif
+
+// Name and version strings for QLVER utility
+
+CHAR CompanyName[] = "$$QLNAME$$" \
+"QLogic Corporation \0";
+
+CHAR Version[] = "$$QLVER$$ 2.13\0";
+
+// Copyright string
+
+CHAR QLogicCR[] = "Copyright (C) QLogic Corporation 1994-1995. All rights reserved.";
+
+/* External RISC code module definitions */
+
+extern USHORT risc_code_version;
+extern USHORT risc_code_addr01;
+extern USHORT risc_code01[];
+extern USHORT risc_code_length01;
+
+
+/************************************************************************/
+/* Driver SRB extension */
+/************************************************************************/
+
+typedef struct _SRB_EXTENSION
+{
+ ULONG SrbExtensionFlags;
+} SRB_EXTENSION, *PSRB_EXTENSION;
+
+#define SRB_EXT(x) ((PSRB_EXTENSION)(x->SrbExtension))
+
+/* SrbExtensionFlags bit definitions */
+
+
+/************************************************************************/
+/* Driver logical unit extension */
+/************************************************************************/
+
+typedef struct _HW_LUN_EXTENSION
+{
+ ULONG LunFlags;
+} HW_LUN_EXTENSION, *PHW_LUN_EXTENSION;
+
+/* LunFlags bit definitions */
+
+#define LFLG_INIT_COMPLETE 0x00000001 // completed initialization
+
+
+/************************************************************************/
+/* Driver noncached memory extension (for DMA interface to ISP1020) */
+/************************************************************************/
+
+typedef struct _NONCACHED_EXTENSION
+{
+ QUEUE_ENTRY RequestQueue[REQUEST_QUEUE_DEPTH];
+ QUEUE_ENTRY ResponseQueue[RESPONSE_QUEUE_DEPTH];
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+
+/************************************************************************/
+/* Driver device object extension */
+/************************************************************************/
+
+typedef struct _HW_DEVICE_EXTENSION
+{
+ ULONG AdapterFlags;
+ PISP_REGS Adapter; // Address of the ISP
+
+ // Request and Response queues and pointers
+
+ PNONCACHED_EXTENSION NoncachedExtension;
+ ULONG ppRequestQueue;
+ ULONG ppResponseQueue;
+ PQUEUE_ENTRY pRequestQueue;
+ PQUEUE_ENTRY pResponseQueue;
+ USHORT request_in;
+ USHORT request_out;
+ USHORT response_out;
+ USHORT queue_space;
+ PQUEUE_ENTRY request_ptr;
+ PQUEUE_ENTRY response_ptr;
+
+ // Configuration NOVRAM paramters
+
+ UCHAR Config_Reg;
+ UCHAR Initiator_SCSI_Id :4;
+ UCHAR Host_Adapter_Enable :1;
+ UCHAR DisableLoadRiscCode :1;
+ UCHAR Bus_Reset_Delay;
+ UCHAR Retry_Count;
+ UCHAR Retry_Delay;
+ UCHAR ASync_Data_Setup_Time :4;
+ UCHAR REQ_ACK_Active_Negation :1;
+ UCHAR DATA_Active_Negation :1;
+ UCHAR Data_DMA_Burst_Enable :1;
+ UCHAR Cmd_DMA_Burst_Enable :1;
+ UCHAR Tag_Age_Limit;
+ UCHAR Termination_Low_Enable :1;
+ UCHAR Termination_High_Enable :1;
+ UCHAR PCMC_Burst_Enable :1;
+ UCHAR Sixty_MHz_Enable :1;
+ USHORT Selection_Timeout;
+ USHORT Max_Queue_Depth;
+ struct
+ {
+ UCHAR Capability;
+ UCHAR Execution_Throttle;
+ UCHAR Sync_Period;
+ UCHAR Sync_Offset :4;
+ UCHAR Device_Enable :1;
+ } Id[NUM_SCSI_IDS];
+
+ PSCSI_REQUEST_BLOCK WaitingSrb;
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+/* AdapterFlags bit definitions */
+
+#define AFLG_INIT_COMPLETE 0x00000001 // completed initialization
+#define AFLG_TAGGED_QUEUING 0x00000002 // enable tagged queuing
+#define AFLG_SEND_MARKER 0x00000004 // need to send marker to ISP
+#define AFLG_SRB_WAITING 0x00000008 // SRB waiting for room in request Q
+
+/* Target "Capability" bit definitions */
+
+#define CAP_STOP_QUEUE_ON_CHECK 0x02
+#define CAP_AUTO_REQ_SENSE 0x04
+#define CAP_TAGGED_QUEUING 0x08
+#define CAP_SYNC_TRANSFER 0x10
+#define CAP_WIDE_TRANSFER 0x20
+
+
+/* Read and write macros for ISP chip registers */
+
+#define ISP_READ(ChipAddr,Register) ScsiPortReadPortUshort(&((ChipAddr)->Register))
+#define ISP_WRITE(ChipAddr,Register,Value) ScsiPortWritePortUshort(&((ChipAddr)->Register),(Value))
+
+/* Table to map ISP completion status to SRB error status */
+
+UCHAR CmpStsErrorMap[] =
+{
+ SRB_STATUS_SUCCESS, // 00h No error
+ SRB_STATUS_SELECTION_TIMEOUT, // 01h Incomplete transport (selection timeout)
+ SRB_STATUS_ERROR, // 02h DMA direction error
+ SRB_STATUS_ERROR, // 03h Transport error
+ SRB_STATUS_BUS_RESET, // 04h SCSI reset abort
+ SRB_STATUS_ABORTED, // 05h Aborted by system
+ SRB_STATUS_TIMEOUT, // 06h Timeout
+ SRB_STATUS_DATA_OVERRUN, // 07h Data overrun
+ SRB_STATUS_PHASE_SEQUENCE_FAILURE, // 08h Command overrun
+ SRB_STATUS_PHASE_SEQUENCE_FAILURE, // 09h Status overrun
+ SRB_STATUS_PHASE_SEQUENCE_FAILURE, // 0Ah Bad message
+ SRB_STATUS_PHASE_SEQUENCE_FAILURE, // 0Bh No message out
+ SRB_STATUS_MESSAGE_REJECTED, // 0Ch Extended ID failed
+ SRB_STATUS_MESSAGE_REJECTED, // 0Dh IDE message failed
+ SRB_STATUS_MESSAGE_REJECTED, // 0Eh Abort message failed
+ SRB_STATUS_MESSAGE_REJECTED, // 0Fh Reject message failed
+ SRB_STATUS_MESSAGE_REJECTED, // 10h NOP message failed
+ SRB_STATUS_MESSAGE_REJECTED, // 11h Parity error message failed
+ SRB_STATUS_MESSAGE_REJECTED, // 12h Device reset message failed
+ SRB_STATUS_MESSAGE_REJECTED, // 13h ID message failed
+ SRB_STATUS_UNEXPECTED_BUS_FREE, // 14h Unexpected bus free
+ SRB_STATUS_DATA_OVERRUN, // 15h Data underrun
+ SRB_STATUS_ERROR, // 16h
+ SRB_STATUS_ERROR, // 17h
+ SRB_STATUS_ERROR, // 18h Transaction error 1
+ SRB_STATUS_ERROR, // 19h Transaction error 2
+ SRB_STATUS_ERROR // 1Ah Transaction error 3
+};
+
+/* PCI Vendor ID and Device ID strings */
+
+CHAR QLVendorId[4] = "1077"; // QLogic PCI Vendor ID
+CHAR ISP1020DeviceId[4] = "1020"; // ISP1020 PCI Device ID
+
+USHORT findMethod = 1; // Method for scanning PCI config space
+
+
+/* Functions passed to the OS-specific port driver */
+
+ULONG QLFindAdapter(IN PVOID ServiceContext, IN PVOID Context, IN PVOID BusInformation,
+ IN PCHAR ArgumentString, IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again);
+
+BOOLEAN QLInitializeAdapter(IN PVOID ServiceContext);
+
+BOOLEAN QLInterruptServiceRoutine(IN PVOID ServiceContext);
+
+BOOLEAN QLResetScsiBus(IN PVOID ServiceContext, IN ULONG PathId);
+
+BOOLEAN QLStartIo(IN PVOID ServiceContext,IN PSCSI_REQUEST_BLOCK pSrb);
+
+BOOLEAN QLAdapterState(IN PVOID ServiceContext,IN PVOID Context,IN BOOLEAN SaveState);
+
+/* Internal mini-port driver functions */
+
+ULONG FindAdapter_M1(IN PVOID ServiceContext, IN OUT PULONG AdapterCount,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo);
+ULONG FindAdapter_M2(IN PVOID ServiceContext, IN OUT PULONG AdapterCount,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo);
+
+BOOLEAN QLResetIsp(IN PHW_DEVICE_EXTENSION pDevExt);
+
+BOOLEAN LoadRiscCode(IN PHW_DEVICE_EXTENSION pDevExt);
+
+BOOLEAN InitDeviceParameters(IN PHW_DEVICE_EXTENSION pDevExt,
+ IN PHW_LUN_EXTENSION pLunExt, IN PSCSI_REQUEST_BLOCK pSrb);
+
+BOOLEAN MailboxCommand(IN PHW_DEVICE_EXTENSION pDevExt,
+ USHORT *mbox_sts, UCHAR out_cnt, UCHAR in_cnt,
+ USHORT reg0, USHORT reg1, USHORT reg2,
+ USHORT reg3, USHORT reg4, USHORT reg5);
+
+VOID GetNovramParameters(IN PHW_DEVICE_EXTENSION pDevExt);
+
+BOOLEAN ReadAllNovram(IN PHW_DEVICE_EXTENSION pDevExt, UCHAR* buf);
+
+VOID ReadNovramWord(IN PHW_DEVICE_EXTENSION pDevExt,
+ USHORT addr, USHORT* ptr);
+VOID NovramDelay();
+
+BOOLEAN SendCommandToIsp(PHW_DEVICE_EXTENSION pDevExt, PSCSI_REQUEST_BLOCK pSrb);
+
+VOID SetErrorStatus(PHW_DEVICE_EXTENSION pDevExt, PSCSI_REQUEST_BLOCK pSrb,
+ PSTATUS_ENTRY pStsEntry);
+
+VOID QLLogError(IN PHW_DEVICE_EXTENSION pDevExt, IN PSCSI_REQUEST_BLOCK pSrb,
+ IN ULONG ErrorCode, IN ULONG UniqueId);
+
+BOOLEAN SendMarker(IN PHW_DEVICE_EXTENSION pDevExt);
+
+BOOLEAN CheckQueueSpace(IN PHW_DEVICE_EXTENSION pDevExt, USHORT slotcnt);
+
+VOID QLCleanupAfterReset(IN PHW_DEVICE_EXTENSION pDevExt);
+
+
+
+/************************************************************************/
+/* */
+/* DriverEntry */
+/* */
+/* Initial miniport driver entry routine called by NT. This routine */
+/* builds and returns to NT the HW_INITIALIZATION_DATA structure. */
+/* */
+/* Arguments: */
+/* */
+/* Driver Object is passed to ScsiPortInitialize() */
+/* */
+/* Return Value: */
+/* */
+/* Status from ScsiPortInitialize() */
+/* */
+/************************************************************************/
+
+ULONG DriverEntry(IN PVOID DriverObject, IN PVOID Argument2)
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG adapterCount;
+ ULONG i, status;
+
+ QLPrint((1, "\nDriverEntry: entering\n"));
+
+ // Zero out structure and set size of init data
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++)
+ {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ // Set driver entry points
+
+ hwInitializationData.HwInitialize = QLInitializeAdapter;
+ hwInitializationData.HwStartIo = QLStartIo;
+ hwInitializationData.HwInterrupt = QLInterruptServiceRoutine;
+ hwInitializationData.HwFindAdapter = QLFindAdapter;
+ hwInitializationData.HwResetBus = QLResetScsiBus;
+ hwInitializationData.HwAdapterState = QLAdapterState;
+
+#ifdef NT_VERSION_31
+ // Note: NT Version 3.1 rejects "PCIBus", set AdapterInterfaceType to "Isa"
+
+ hwInitializationData.AdapterInterfaceType = Isa;
+#else
+ hwInitializationData.AdapterInterfaceType = PCIBus;
+ hwInitializationData.VendorIdLength = 4;
+ hwInitializationData.VendorId = (PVOID)&QLVendorId;
+ hwInitializationData.DeviceIdLength = 4;
+ hwInitializationData.DeviceId = (PVOID)&ISP1020DeviceId;
+#endif
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.Reserved = 0;
+ hwInitializationData.MapBuffers = FALSE;
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+ hwInitializationData.TaggedQueuing = TRUE;
+ hwInitializationData.AutoRequestSense = TRUE;
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LUN_EXTENSION);
+ hwInitializationData.SrbExtensionSize = sizeof(SRB_EXTENSION);
+
+ adapterCount = 0;
+ status = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData,
+ &adapterCount);
+
+ QLPrint((1, "DriverEntry: exiting, status = %lx\n", status));
+
+ return(status);
+}
+
+#ifndef NT_VERSION_31
+
+/************************************************************************/
+/* */
+/* QLFindAdapter NT Version 3.5 and above */
+/* */
+/* This function is called by ScsiPortInitialize to find the next */
+/* adapter and fill in the configuration information structure and */
+/* map the SCSI protocol chip for access. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* AdapterCount - Count of adapter I/O register slots tested */
+/* BusInformation - Unused */
+/* ArgumentString - Unused */
+/* ConfigInfo - Pointer to the configuration information */
+/* structure to be filled in */
+/* Again - Returns a request to call this function again */
+/* */
+/* Return Value: */
+/* */
+/* Returns a status value for the initialization */
+/* */
+/************************************************************************/
+
+ULONG QLFindAdapter(IN PVOID ServiceContext, IN OUT PULONG AdapterCount,
+ IN PVOID BusInformation, IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ PACCESS_RANGE AccessRange;
+ ULONG retcode;
+ ULONG length;
+
+ QLPrint((1, "QLFindAdapter: entering\n"));
+
+ *Again = FALSE;
+
+ // Get access range.
+
+ AccessRange = &((*(ConfigInfo->AccessRanges))[0]);
+
+ if (AccessRange->RangeLength != 0)
+ {
+ // BUGBUG - Currently, when scsiport scans the PCI bus and finds
+ // a SCSI adapter, it will not automatically enable the
+ // Bus Master bit in the PCI command register. We need
+ // to enable this for the adapter to function properly.
+
+ PCI_COMMON_CONFIG pciBuffer;
+
+ QLPrint((1, "QLFindAdapter: found ISP1020 at address %lx\n", AccessRange->RangeStart));
+ QLPrint((1, "QLFindAdapter: BusInterruptLevel = %lx\n", ConfigInfo->BusInterruptLevel));
+
+ ScsiPortGetBusData(pDevExt,
+ PCIConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ ConfigInfo->SlotNumber,
+ &pciBuffer,
+ PCI_COMMON_HDR_LENGTH);
+ //
+ // Enable Bus Master bit
+ //
+
+ pciBuffer.Command |= BUS_MASTER_ENABLE;
+
+ //
+ // Zero bit 0 of the ROM address to take the chip
+ // out of the its reset state
+ //
+
+ pciBuffer.u.type0.ROMBaseAddress &= 0xfffffffe;
+
+ ScsiPortSetBusDataByOffset(pDevExt,
+ PCIConfiguration,
+ ConfigInfo->SystemIoBusNumber,
+ ConfigInfo->SlotNumber,
+ &pciBuffer,
+ 0,
+ PCI_COMMON_HDR_LENGTH);
+
+ // Map I/O registers for adapter
+
+ pDevExt->Adapter = ScsiPortGetDeviceBase(pDevExt,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ AccessRange->RangeStart,
+ AccessRange->RangeLength,
+ (BOOLEAN)!AccessRange->RangeInMemory);
+ if (pDevExt->Adapter == NULL)
+ {
+ QLPrint((1, "QLFindAdapter: Failed to map ISP registers\n"));
+ return(SP_RETURN_ERROR);
+ }
+
+ // Reset ISP chip and read in NOVRAM parameters
+
+ if (!QLResetIsp(pDevExt))
+ {
+ ScsiPortFreeDeviceBase(pDevExt, pDevExt->Adapter);
+ return(SP_RETURN_ERROR);
+ }
+
+ GetNovramParameters(pDevExt);
+
+ // Check for disabled adapter
+
+ if (!pDevExt->Host_Adapter_Enable)
+ {
+ ScsiPortFreeDeviceBase(pDevExt, pDevExt->Adapter);
+ return(SP_RETURN_ERROR);
+ }
+
+ // Check for passed in SCSI ID and override NVRAM setting
+
+ if (ConfigInfo->InitiatorBusId[0] == (CCHAR)SP_UNINITIALIZED_VALUE)
+ ConfigInfo->InitiatorBusId[0] = pDevExt->Initiator_SCSI_Id;
+ else
+ pDevExt->Initiator_SCSI_Id = ConfigInfo->InitiatorBusId[0];
+
+ // Fill in other port configuration information
+
+ ConfigInfo->MaximumTransferLength = 0xFFFFFFFF; // unlimited
+ ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_SEGMENTS - 1;
+ ConfigInfo->AlignmentMask = 0x00000003;
+ ConfigInfo->DmaWidth = 32;
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+ if (!(pDevExt->AdapterFlags & AFLG_TAGGED_QUEUING))
+ ConfigInfo->TaggedQueuing = FALSE;
+ ConfigInfo->BufferAccessScsiPortControlled = TRUE;
+
+ // Work around for Chicago Beta 2 bug
+
+ if (ConfigInfo->MaximumNumberOfTargets == 7)
+ ConfigInfo->MaximumNumberOfTargets = 15;
+ else
+ ConfigInfo->MaximumNumberOfTargets = 16;
+
+ // Allocate a Noncached Extension request/response queues
+
+ pDevExt->NoncachedExtension = ScsiPortGetUncachedExtension(pDevExt,
+ ConfigInfo, sizeof(NONCACHED_EXTENSION));
+
+ if (pDevExt->NoncachedExtension == NULL)
+ {
+ QLPrint((1, "QLFindAdapter: Failed to allocate noncached memory\n"));
+ ScsiPortFreeDeviceBase(pDevExt, pDevExt->Adapter);
+ return(SP_RETURN_ERROR);
+ }
+
+ // Init virtual and physical queue addresses
+
+ pDevExt->pRequestQueue = pDevExt->NoncachedExtension->RequestQueue;
+ pDevExt->pResponseQueue = pDevExt->NoncachedExtension->ResponseQueue;
+ pDevExt->ppRequestQueue = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(pDevExt, NULL,
+ pDevExt->NoncachedExtension->RequestQueue, &length));
+ pDevExt->ppResponseQueue = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(pDevExt, NULL,
+ pDevExt->NoncachedExtension->ResponseQueue, &length));
+
+ retcode = SP_RETURN_FOUND;
+ *Again = TRUE;
+ }
+ else
+ {
+ // Stop searching for adapters
+
+ retcode = SP_RETURN_NOT_FOUND;
+ *Again = FALSE;
+ }
+
+ QLPrint((1, "QLFindAdapter: exiting, retcode = %lx\n", retcode));
+
+ return(retcode);
+}
+#endif
+
+#ifdef NT_VERSION_31
+
+/************************************************************************/
+/* */
+/* QLFindAdapter NT Version 3.1 */
+/* */
+/* This function is called by ScsiPortInitialize to find the next */
+/* adapter and fill in the configuration information structure and */
+/* map the SCSI protocol chip for access. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* AdapterCount - Count of adapter I/O register slots tested */
+/* BusInformation - Unused */
+/* ArgumentString - Unused */
+/* ConfigInfo - Pointer to the configuration information */
+/* structure to be filled in */
+/* Again - Returns a request to call this function again */
+/* */
+/* Return Value: */
+/* */
+/* Returns a status value for the initialization */
+/* */
+/************************************************************************/
+
+ULONG QLFindAdapter(IN PVOID ServiceContext, IN OUT PULONG AdapterCount,
+ IN PVOID BusInformation, IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ ULONG retcode;
+ ULONG length;
+
+ QLPrint((1, "QLFindAdapter: entering\n"));
+
+ *Again = FALSE; // preset no return call
+
+ // Look for adapter, try both methods of accessing PCI config space
+
+find_adapter:
+
+ if (findMethod == 1)
+ {
+ retcode = FindAdapter_M1(ServiceContext, AdapterCount, ConfigInfo);
+ }
+ else
+ {
+ retcode = FindAdapter_M2(ServiceContext, AdapterCount, ConfigInfo);
+ }
+
+ if (retcode != SP_RETURN_FOUND)
+ {
+ if (findMethod == 1 && *AdapterCount == 0)
+ {
+ findMethod = 2; // Switch to method 2
+ goto find_adapter; // Try again
+ }
+ }
+ else
+ {
+ // Found next adapter
+ // Map I/O registers for adapter
+
+ pDevExt->Adapter = ScsiPortGetDeviceBase(
+ pDevExt, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ (*ConfigInfo->AccessRanges)[0].RangeStart,
+ (ULONG)(sizeof(ISP_REGS)), // NumberOfBytes
+ TRUE); // InIoSpace
+
+ if (pDevExt->Adapter == NULL)
+ {
+ QLPrint((1, "QLFindAdapter: Failed to map ISP registers.\n"));
+ return(SP_RETURN_ERROR);
+ }
+
+ // Reset ISP chip and read in NOVRAM parameters
+
+ if (!QLResetIsp(pDevExt))
+ {
+ ScsiPortFreeDeviceBase(pDevExt, pDevExt->Adapter);
+ return(SP_RETURN_ERROR);
+ }
+
+ GetNovramParameters(pDevExt);
+
+ // Check for disabled adapter
+
+ if (!pDevExt->Host_Adapter_Enable)
+ {
+ ScsiPortFreeDeviceBase(pDevExt, pDevExt->Adapter);
+ (*AdapterCount)++; // skip this adapter
+ goto find_adapter; // Try again
+ }
+
+ // Check for passed in SCSI ID and override NVRAM setting
+
+ if (ConfigInfo->InitiatorBusId[0] == (CCHAR)SP_UNINITIALIZED_VALUE)
+ ConfigInfo->InitiatorBusId[0] = pDevExt->Initiator_SCSI_Id;
+ else
+ pDevExt->Initiator_SCSI_Id = ConfigInfo->InitiatorBusId[0];
+
+ // Fill in other port configuration information
+
+ ConfigInfo->MaximumTransferLength = 0xFFFFFFFF; // unlimited
+ ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_SEGMENTS - 1;
+ ConfigInfo->AlignmentMask = 0x00000003;
+ ConfigInfo->DmaWidth = 32;
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+ if (!(pDevExt->AdapterFlags & AFLG_TAGGED_QUEUING))
+ ConfigInfo->TaggedQueuing = FALSE;
+ ConfigInfo->InterruptMode = LevelSensitive; // Set this for shared IRQ level
+
+ // Allocate a Noncached Extension request/response queues
+
+ pDevExt->NoncachedExtension = ScsiPortGetUncachedExtension(
+ pDevExt, ConfigInfo, sizeof(NONCACHED_EXTENSION));
+
+ if (pDevExt->NoncachedExtension == NULL)
+ {
+ QLPrint((1, "QLFindAdapter: Failed to allocate noncached memory\n"));
+ ScsiPortFreeDeviceBase(pDevExt, pDevExt->Adapter);
+ return(SP_RETURN_ERROR);
+ }
+
+ // Init virtual and physical queue addresses
+
+ pDevExt->pRequestQueue = pDevExt->NoncachedExtension->RequestQueue;
+ pDevExt->pResponseQueue = pDevExt->NoncachedExtension->ResponseQueue;
+ pDevExt->ppRequestQueue = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(pDevExt, NULL,
+ pDevExt->NoncachedExtension->RequestQueue, &length));
+ pDevExt->ppResponseQueue = pDevExt->ppRequestQueue +
+ REQUEST_QUEUE_DEPTH * sizeof(QUEUE_ENTRY);
+
+ (*AdapterCount)++;
+ *Again = TRUE;
+ }
+
+ QLPrint((1, "QLFindAdapter: exiting, retcode = %lx\n", retcode));
+
+ return(retcode);
+}
+
+
+/************************************************************************/
+/* */
+/* FindAdapter_M1 NT Version 3.1 */
+/* */
+/* This function is called by QLFindAdapter to find the next */
+/* adapter using PCI configuration mechanism #1. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* AdapterCount - Count of adapter I/O register slots tested */
+/* ConfigInfo - Pointer to the configuration information */
+/* structure to be filled in */
+/* */
+/* Return Value: */
+/* */
+/* Returns a status value for the initialization */
+/* */
+/************************************************************************/
+
+ULONG FindAdapter_M1(IN PVOID ServiceContext, IN OUT PULONG AdapterCount,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ PPCI_CHIP_REGISTERS_M1 PciChip;
+ PPCI_REGS PciConfig = 0;
+ ULONG retcode = SP_RETURN_NOT_FOUND;
+ USHORT index, VendorId, DeviceId;
+ ULONG BusNum, DevNum;
+ ULONG ha_base;
+ ULONG RomBase;
+ ULONG cmd_reg;
+ ULONG dataread;
+
+ // Map PCI chip registers
+
+ PciChip = ScsiPortGetDeviceBase(
+ pDevExt, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress((ULONG)PCI_CONFIG_ADDRESS),
+ sizeof(PCI_CHIP_REGISTERS_M1), // NumberOfBytes
+ TRUE); // InIoSpace
+
+ if (PciChip == NULL)
+ {
+ QLPrint((1, "FindAdapter_M1: Failed to map PCI chip registers.\n"));
+ return(SP_RETURN_ERROR);
+ }
+
+ // Scan configuration space headers for next adapter
+
+ for (index=0, BusNum=0; BusNum < PCI_MAXBUSNUM; BusNum++)
+ {
+ for (DevNum = 0; DevNum < PCI_MAXDEVNUM; DevNum++)
+ {
+ ScsiPortWritePortUlong(&PciChip->Config_Address,
+ (PCI_ENABLE_CONFIG | BusNum << 16 | DevNum << 11 |
+ (ULONG)(&PciConfig->Vendor_Id)));
+
+ dataread = ScsiPortReadPortUlong(&PciChip->Config_Data);
+ VendorId = (USHORT)dataread;
+ DeviceId = (USHORT)(dataread >> 16);
+
+ if (VendorId == QLogic_VENDOR_ID && DeviceId == QLogic_DEVICE_ID)
+ {
+ if (index == *AdapterCount)
+ {
+ // Found next adapter
+ // Get base I/O address and interrupt level
+
+ ScsiPortWritePortUlong(&PciChip->Config_Address,
+ (PCI_ENABLE_CONFIG | BusNum << 16 | DevNum << 11 |
+ (ULONG)(&PciConfig->IO_Base_Address)));
+ ha_base = ScsiPortReadPortUlong(&PciChip->Config_Data) & 0xfffffffc;
+
+ ScsiPortWritePortUlong(&PciChip->Config_Address,
+ (PCI_ENABLE_CONFIG | BusNum << 16 | DevNum << 11 |
+ (ULONG)(&PciConfig->Interrupt_Line)));
+ ConfigInfo->BusInterruptLevel =
+ ScsiPortReadPortUlong(&PciChip->Config_Data) & 0x000000ff;
+
+ QLPrint((1, "FindAdapter_M1: found ISP1020 at address %lx\n", ha_base));
+
+ // Fill in the access array information
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(ha_base);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(ISP_REGS);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ // Must clear bit 0 of ROM base address register
+
+ ScsiPortWritePortUlong(&PciChip->Config_Address,
+ (PCI_ENABLE_CONFIG | BusNum << 16 | DevNum << 11 |
+ (ULONG)(&PciConfig->ROM_Base_Address)));
+ RomBase = ScsiPortReadPortUlong(&PciChip->Config_Data);
+ ScsiPortWritePortUlong(&PciChip->Config_Address,
+ (PCI_ENABLE_CONFIG | BusNum << 16 | DevNum << 11 |
+ (ULONG)(&PciConfig->ROM_Base_Address)));
+ ScsiPortWritePortUlong(&PciChip->Config_Data, (RomBase & 0xfffffffe));
+
+ // Make sure bus master enabled
+
+ ScsiPortWritePortUlong(&PciChip->Config_Address,
+ (PCI_ENABLE_CONFIG | BusNum << 16 | DevNum << 11 |
+ (ULONG)(&PciConfig->Command)));
+ cmd_reg = ScsiPortReadPortUlong(&PciChip->Config_Data);
+ ScsiPortWritePortUlong(&PciChip->Config_Address,
+ (PCI_ENABLE_CONFIG | BusNum << 16 | DevNum << 11 |
+ (ULONG)(&PciConfig->Command)));
+ ScsiPortWritePortUlong(&PciChip->Config_Data, (cmd_reg | BUS_MASTER_ENABLE));
+
+ retcode = SP_RETURN_FOUND;
+ goto find_exit;
+ }
+ index++;
+ }
+ }
+ }
+
+find_exit:
+
+ // Disable PCI chip registers
+
+ ScsiPortWritePortUlong(&PciChip->Config_Address, PCI_DISABLE_CONFIG);
+ ScsiPortFreeDeviceBase(pDevExt, PciChip);
+
+ return(retcode);
+}
+
+
+/************************************************************************/
+/* */
+/* FindAdapter_M2 NT Version 3.1 */
+/* */
+/* This function is called by QLFindAdapter to find the next */
+/* adapter using PCI configuration mechanism #2. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* AdapterCount - Count of adapter I/O register slots tested */
+/* ConfigInfo - Pointer to the configuration information */
+/* structure to be filled in */
+/* */
+/* Return Value: */
+/* */
+/* Returns a status value for the initialization */
+/* */
+/************************************************************************/
+
+ULONG FindAdapter_M2(IN PVOID ServiceContext, IN OUT PULONG AdapterCount,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ PPCI_CHIP_REGISTERS PciChip;
+ UCHAR config_reg;
+ ULONG retcode = SP_RETURN_NOT_FOUND;
+ PPCI_REGS PciConfig, PciSlot;
+ USHORT index, slot, VendorId, DeviceId;
+ ULONG ha_base;
+ USHORT RomBase;
+ USHORT cmd_reg;
+
+ // Map PCI chip registers and enable configuration space
+
+ PciChip = ScsiPortGetDeviceBase(
+ pDevExt, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress((ULONG)PCI_CONFIG),
+ sizeof(PCI_CHIP_REGISTERS), // NumberOfBytes
+ TRUE); // InIoSpace
+
+ if (PciChip == NULL)
+ {
+ QLPrint((1, "FindAdapter_M2: Failed to map PCI chip registers.\n"));
+ return(SP_RETURN_ERROR);
+ }
+
+ config_reg = ScsiPortReadPortUchar(&PciChip->pci_config);
+ ScsiPortWritePortUchar(&PciChip->pci_config, (UCHAR)(config_reg | PCI_ENABLE));
+
+ // Map PCI configuration space
+
+ PciConfig = ScsiPortGetDeviceBase(
+ pDevExt, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress((ULONG)PCI_START),
+ sizeof(PCI_REGS) * PCI_SLOT_CNT, // NumberOfBytes
+ TRUE); // InIoSpace
+
+ if (PciConfig == NULL)
+ {
+ QLPrint((1, "FindAdapter_M2: Failed to map PCI config space.\n"));
+ ScsiPortFreeDeviceBase(pDevExt, PciChip);
+ return(SP_RETURN_ERROR);
+ }
+
+ // Scan configuration space headers for next adapter
+
+ for (index=0, slot=0, PciSlot=PciConfig; slot<PCI_SLOT_CNT; slot++, PciSlot++)
+ {
+ VendorId = ScsiPortReadPortUshort(&PciSlot->Vendor_Id);
+ DeviceId = ScsiPortReadPortUshort(&PciSlot->Device_Id);
+
+ if (VendorId == QLogic_VENDOR_ID && DeviceId == QLogic_DEVICE_ID)
+ {
+ if (index == *AdapterCount)
+ {
+ // Found next adapter
+ // Get base I/O address and interrupt level
+
+ ha_base = ScsiPortReadPortUshort((PUSHORT)&PciSlot->IO_Base_Address) & 0xfffc;
+ ConfigInfo->BusInterruptLevel =
+ ScsiPortReadPortUchar(&PciSlot->Interrupt_Line);
+
+ QLPrint((1, "FindAdapter_M2: found ISP1020 at address %lx\n", ha_base));
+
+ // Fill in the access array information
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(ha_base);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(ISP_REGS);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ // Must clear bit 0 of ROM base address register
+
+ RomBase = ScsiPortReadPortUshort((PUSHORT)&PciSlot->ROM_Base_Address);
+ ScsiPortWritePortUshort((PUSHORT)&PciSlot->ROM_Base_Address, (USHORT)(RomBase & 0xfffe));
+
+ // Make sure bus master enabled
+
+ cmd_reg = ScsiPortReadPortUshort(&PciSlot->Command);
+ ScsiPortWritePortUshort(&PciSlot->Command, (USHORT)(cmd_reg | BUS_MASTER_ENABLE));
+
+ retcode = SP_RETURN_FOUND;
+ break;
+ }
+ index++;
+ }
+ }
+
+ // Disable configuration space
+
+ ScsiPortWritePortUchar(&PciChip->pci_config, config_reg);
+ ScsiPortFreeDeviceBase(pDevExt, PciChip);
+ ScsiPortFreeDeviceBase(pDevExt, PciConfig);
+
+ return(retcode);
+}
+#endif
+
+
+/************************************************************************/
+/* */
+/* QLInitializeAdapter */
+/* */
+/* This function is called to initialize the adapter after boot or */
+/* after a power failure. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* */
+/* Return Value: */
+/* */
+/* Returns TRUE if initialization is complete */
+/* Returns FALSE if error */
+/* */
+/************************************************************************/
+
+BOOLEAN QLInitializeAdapter(IN PVOID ServiceContext)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ USHORT mbox_sts[6];
+ UCHAR *c_ptr;
+ USHORT i;
+ USHORT scsi_id;
+ USHORT ram_addr, ram_data;
+ USHORT running_version;
+
+ QLPrint((1, "QLInitializeAdapter: entering\n"));
+
+ // Check version of loaded RISC code, don't reload if same or newer version
+ // Must restart RISC firmware first
+
+ if (MailboxCommand(pDevExt, mbox_sts, 2, 0,
+ MBOX_CMD_EXECUTE_FIRMWARE,
+ risc_code_addr01,
+ 0,0,0,0))
+ {
+ // Get running RISC code version
+
+ if (MailboxCommand(pDevExt, mbox_sts, 1, 3,
+ MBOX_CMD_ABOUT_FIRMWARE,
+ 0,0,0,0,0))
+ {
+ // Compare running version to version linked with driver
+
+ running_version = mbox_sts[1] << 10 | mbox_sts[2];
+
+ QLPrint((1, "QLInitializeAdapter: running RISC code version %x\n", running_version));
+ QLPrint((1, "QLInitializeAdapter: driver RISC code version %x\n", risc_code_version));
+
+ if (risc_code_version <= running_version)
+ {
+ pDevExt->DisableLoadRiscCode = 1;
+ }
+ }
+ else
+ {
+ QLPrint((1, "QLInitializeAdapter: ABOUT FIRMWARE command failed\n"));
+ }
+ }
+ else
+ {
+ QLPrint((1, "QLInitializeAdapter: EXECUTE FIRMWARE command failed\n"));
+ }
+
+ if (!pDevExt->DisableLoadRiscCode)
+ {
+ // Reset ISP chip
+
+ if (!QLResetIsp(pDevExt))
+ {
+ return(FALSE);
+ }
+
+ // Must manually clear Burst Enable, chip reset not working correctly
+
+ ISP_WRITE(pDevExt->Adapter, bus_config1, 0);
+
+ // Load RISC code
+
+ if (!LoadRiscCode(pDevExt))
+ {
+ QLPrint((1, "QLInitializeAdapter: Load RISC code failed\n"));
+ return(FALSE);
+ }
+
+ // Start ISP firmware
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 0,
+ MBOX_CMD_EXECUTE_FIRMWARE,
+ risc_code_addr01,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: EXECUTE FIRMWARE command failed\n"));
+ return(FALSE);
+ }
+
+ QLPrint((1, "QLInitializeAdapter: RISC code loaded and started\n"));
+ }
+ else
+ {
+ QLPrint((1, "QLInitializeAdapter: RISC not reloaded\n"));
+ }
+
+ // Set Bus Control Parameters
+
+ ISP_WRITE(pDevExt->Adapter, bus_config1,
+ (USHORT)pDevExt->Config_Reg);
+ if (!MailboxCommand(pDevExt, mbox_sts, 3, 3,
+ MBOX_CMD_SET_BUS_CONTROL_PARAMETERS,
+ (USHORT)(pDevExt->Data_DMA_Burst_Enable << 1),
+ (USHORT)(pDevExt->Cmd_DMA_Burst_Enable << 1),
+ 0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET BUS CONTROL PARAMS cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Set ISP1020 clock rate
+
+ if (pDevExt->Sixty_MHz_Enable)
+ {
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_SET_CLOCK_RATE,
+ (USHORT)60,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET CLOCK RATE cmd failed\n"));
+ return(FALSE);
+ }
+ }
+
+ // Set software controlled SCSI bus termination
+ // Must reset and enable termination PAL first
+
+ for (i = 0, ram_addr = 0xFF00; i < 4; i++, ram_addr += 0x0010)
+ {
+ if (!MailboxCommand(pDevExt, mbox_sts, 3, 3,
+ MBOX_CMD_WRITE_RAM_WORD,
+ ram_addr,
+ (USHORT)0,
+ 0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: WRITE RAM WORD cmd failed\n"));
+ return(FALSE);
+ }
+ }
+
+ if (pDevExt->Termination_High_Enable)
+ {
+ if (pDevExt->Termination_Low_Enable)
+ ram_addr = 0xFF00;
+ else
+ ram_addr = 0xFF40;
+ }
+ else
+ {
+ if (pDevExt->Termination_Low_Enable)
+ ram_addr = 0xFF80;
+ else
+ ram_addr = 0xFFC0;
+ }
+ ram_data = (USHORT)(pDevExt->Termination_High_Enable) << 1 |
+ (USHORT)(pDevExt->Termination_Low_Enable);
+ if (!MailboxCommand(pDevExt, mbox_sts, 3, 3,
+ MBOX_CMD_WRITE_RAM_WORD,
+ ram_addr,
+ ram_data,
+ 0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: WRITE RAM WORD cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Clear request queue area and initialize queue
+
+ c_ptr = (UCHAR *)pDevExt->pRequestQueue;
+ for (i = 0; i < REQUEST_QUEUE_DEPTH * sizeof(QUEUE_ENTRY); i++)
+ *c_ptr++ = 0;
+
+ pDevExt->queue_space = REQUEST_QUEUE_DEPTH - 1;
+ pDevExt->request_in = 0;
+ pDevExt->request_out = 0;
+ pDevExt->request_ptr = pDevExt->pRequestQueue;
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 5, 6,
+ MBOX_CMD_INIT_REQUEST_QUEUE,
+ REQUEST_QUEUE_DEPTH,
+ (USHORT)(pDevExt->ppRequestQueue >> 16),
+ (USHORT)(pDevExt->ppRequestQueue & 0xFFFF),
+ pDevExt->request_in,
+ 0))
+ {
+ QLPrint((1, "QLInitializeAdapter: INIT REQUEST QUEUE cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Clear response queue area and initialize queue
+
+ c_ptr = (UCHAR *)pDevExt->pResponseQueue;
+ for (i = 0; i < RESPONSE_QUEUE_DEPTH * sizeof(QUEUE_ENTRY); i++)
+ *c_ptr++ = 0;
+
+ pDevExt->response_out = 0;
+ pDevExt->response_ptr = pDevExt->pResponseQueue;
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 6, 6,
+ MBOX_CMD_INIT_RESPONSE_QUEUE,
+ RESPONSE_QUEUE_DEPTH,
+ (USHORT)(pDevExt->ppResponseQueue >> 16),
+ (USHORT)(pDevExt->ppResponseQueue & 0xFFFF),
+ 0,
+ pDevExt->response_out))
+ {
+ QLPrint((1, "QLInitializeAdapter: INIT RESPONSE QUEUE cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Set Initiator SCSI ID
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_SET_INITIATOR_SCSI_ID,
+ (USHORT)pDevExt->Initiator_SCSI_Id,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET INITIATOR SCSI ID cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Set Selection Timeout
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_SET_SELECTION_TIMEOUT,
+ (USHORT)pDevExt->Selection_Timeout,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET SELECTION TIMEOUT cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Disable retrys for autoconfigure
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 3, 3,
+ MBOX_CMD_SET_RETRY_COUNT,
+ 0,0,
+ 0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET RETRY COUNT cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Set Active Negation
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_SET_ACTIVE_NEGATION_STATE,
+ (USHORT)((pDevExt->REQ_ACK_Active_Negation << 5) +
+ (pDevExt->DATA_Active_Negation << 4)),
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET ACTIVE NEGATION STATE cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Set Tag Age Limits
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_SET_TAG_AGE_LIMIT,
+ pDevExt->Tag_Age_Limit,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET TAG AGE LIMIT cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Set Async Data Setup Time
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_SET_ASYNC_DATA_SETUP_TIME,
+ pDevExt->ASync_Data_Setup_Time,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET ASYNC DATA SETUP TIME cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Set target parameters for doing SCSI autoconfigure
+
+ for (scsi_id = 0; scsi_id < NUM_SCSI_IDS; scsi_id++)
+ {
+ if (!MailboxCommand(pDevExt, mbox_sts, 4, 4,
+ MBOX_CMD_SET_TARGET_PARAMETERS,
+ (USHORT)(scsi_id << 8),
+ (USHORT)(CAP_AUTO_REQ_SENSE << 8),
+ 0,0,0))
+ {
+ QLPrint((1, "QLInitializeAdapter: SET TARGET PARAMETERS cmd failed\n"));
+ return(FALSE);
+ }
+ }
+
+ // Reset SCSI bus
+
+ QLResetScsiBus(pDevExt, 0);
+
+ // Enable ISP interrupts
+
+ ISP_WRITE(pDevExt->Adapter, hccr, HCCR_CMD_CLEAR_RISC_INT);
+ ISP_WRITE(pDevExt->Adapter, bus_sema, 0);
+ ISP_WRITE(pDevExt->Adapter, bus_icr, ICR_ENABLE_ALL_INTS | ICR_ENABLE_RISC_INT);
+
+ QLPrint((1, "QLInitializeAdapter: exiting\n"));
+
+ return( TRUE );
+}
+
+
+/************************************************************************/
+/* */
+/* QLResetIsp */
+/* */
+/* This function is called to reset the ISP chip. */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* */
+/* Return Value: */
+/* */
+/* Returns TRUE if reset completed OK */
+/* Returns FALSE if error */
+/* */
+/************************************************************************/
+
+BOOLEAN QLResetIsp(IN PHW_DEVICE_EXTENSION pDevExt)
+{
+ USHORT i;
+
+ // Reset ISP chip and disable BIOS
+
+ ISP_WRITE(pDevExt->Adapter, bus_icr, ICR_SOFT_RESET);
+
+ // Small delay after reset
+
+ ScsiPortStallExecution(10);
+
+ ISP_WRITE(pDevExt->Adapter, hccr, HCCR_CMD_RESET);
+
+ // Small delay after reset
+
+ ScsiPortStallExecution(10);
+
+ ISP_WRITE(pDevExt->Adapter, hccr, HCCR_CMD_RELEASE);
+
+ // Small delay after reset
+
+ ScsiPortStallExecution(10);
+
+ ISP_WRITE(pDevExt->Adapter, hccr, HCCR_WRITE_BIOS_ENABLE);
+
+ // Small delay after reset
+
+ ScsiPortStallExecution(10);
+
+ // Wait for mailbox 0 to clear
+
+ for (i = 0; i < 1000; i++)
+ {
+ if (ISP_READ(pDevExt->Adapter, mailbox0) == 0)
+ {
+ break;
+ }
+ }
+ if (ISP_READ(pDevExt->Adapter, mailbox0) != 0)
+ {
+ QLPrint((1, "QLResetIsp: Chip reset timeout\n"));
+ return(FALSE);
+ }
+
+ // Check product ID of chip
+
+ if (ISP_READ(pDevExt->Adapter, mailbox1) != PROD_ID_1 ||
+ (ISP_READ(pDevExt->Adapter, mailbox2) != PROD_ID_2 &&
+ ISP_READ(pDevExt->Adapter, mailbox2) != PROD_ID_2a) ||
+ ISP_READ(pDevExt->Adapter, mailbox3) != PROD_ID_3 ||
+ ISP_READ(pDevExt->Adapter, mailbox4) != PROD_ID_4)
+ {
+ QLPrint((1, "QLResetIsp: Failed chip product ID test\n"));
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* LoadRiscCode */
+/* */
+/* This function is called to load the RISC firmware. */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* */
+/* Return Value: */
+/* */
+/* Returns TRUE if load completed OK */
+/* Returns FALSE if error */
+/* */
+/************************************************************************/
+
+BOOLEAN LoadRiscCode(IN PHW_DEVICE_EXTENSION pDevExt)
+{
+ USHORT i, j;
+ USHORT RiscCodeAddr;
+ USHORT *pCode, *pBuffer;
+ USHORT mbox_sts[6];
+ USHORT BufSize;
+
+ // Use request/response queues buffer for loading RISC code
+ // (having trouble loading directly from driver code space?)
+
+ BufSize = (REQUEST_QUEUE_DEPTH + RESPONSE_QUEUE_DEPTH) * sizeof(QUEUE_ENTRY);
+ pCode = risc_code01;
+ for (i = 0, RiscCodeAddr = risc_code_addr01;
+ i < risc_code_length01;
+ RiscCodeAddr += BufSize/2)
+ {
+ pBuffer = (USHORT *)pDevExt->pRequestQueue;
+ for (j = 0; j < BufSize/2 && i < risc_code_length01; j++, i++)
+ {
+ *pBuffer++ = *pCode++;
+ }
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 5, 5,
+ MBOX_CMD_LOAD_RAM,
+ RiscCodeAddr,
+ (USHORT)(pDevExt->ppRequestQueue >> 16),
+ (USHORT)(pDevExt->ppRequestQueue & 0xFFFF),
+ (USHORT)(BufSize / 2),
+ 0))
+ {
+ QLPrint((1, "LoadRiscCode: LOAD RAM command failed\n"));
+ return(FALSE);
+ }
+ }
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* InitDeviceParameters */
+/* */
+/* This function is called to set target device parameters after */
+/* autoconfigure Inquiry commands are done */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* pLunExt - Pointer to lun extension */
+/* pSrb - Pointer to SCSI request block */
+/* */
+/* Return Value: */
+/* */
+/* Returns TRUE if completed OK */
+/* Returns FALSE if error */
+/* */
+/************************************************************************/
+
+BOOLEAN InitDeviceParameters(IN PHW_DEVICE_EXTENSION pDevExt,
+ IN PHW_LUN_EXTENSION pLunExt, IN PSCSI_REQUEST_BLOCK pSrb)
+{
+ USHORT scsi_id;
+ USHORT mbox_sts[6];
+
+
+ // If 1st call for this adapter, set retries and target parameters
+
+ if (!(pDevExt->AdapterFlags & AFLG_INIT_COMPLETE))
+ {
+ QLPrint((1, "InitDeviceParameters: set adapter init complete\n"));
+
+ pDevExt->AdapterFlags |= AFLG_INIT_COMPLETE;
+
+ // Reset target parameters from NOVRAM parameters
+
+ for (scsi_id = 0; scsi_id < NUM_SCSI_IDS; scsi_id++)
+ {
+ if (!MailboxCommand(pDevExt, mbox_sts, 4, 4,
+ MBOX_CMD_SET_TARGET_PARAMETERS,
+ (USHORT)(scsi_id << 8),
+ (USHORT)(pDevExt->Id[scsi_id].Capability << 8),
+ (USHORT)((pDevExt->Id[scsi_id].Sync_Offset << 8) |
+ (pDevExt->Id[scsi_id].Sync_Period)),
+ 0,0))
+ {
+ QLPrint((1, "InitDeviceParameters: SET TARGET PARAMS cmd failed\n"));
+ return(FALSE);
+ }
+ }
+
+ // Set RETRY limits
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 3, 3,
+ MBOX_CMD_SET_RETRY_COUNT,
+ pDevExt->Retry_Count,
+ pDevExt->Retry_Delay,
+ 0,0,0))
+ {
+ QLPrint((1, "InitDeviceParameters: SET RETRY COUNT cmd failed\n"));
+ return(FALSE);
+ }
+ }
+
+ QLPrint((1, "InitDeviceParameters: set lun init complete\n"));
+
+ pLunExt->LunFlags |= LFLG_INIT_COMPLETE;
+
+ // Set device queue parameters
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 4, 4,
+ MBOX_CMD_SET_DEVICE_QUEUE_PARAMETERS,
+ (USHORT)(((USHORT)(pSrb->TargetId) << 8) | pSrb->Lun),
+ pDevExt->Max_Queue_Depth,
+ (USHORT)(pDevExt->Id[pSrb->TargetId].Execution_Throttle),
+ 0,0))
+ {
+ QLPrint((1, "InitDeviceParameters: SET QUEUE PARAMS cmd failed\n"));
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* QLStartIo */
+/* */
+/* This function is called by the port driver to start execution */
+/* of an I/O request. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* pSrb - Supplies the SCSI request block to be started. */
+/* */
+/* Return Value: */
+/* */
+/* TRUE - If the request can be accepted at this time */
+/* FALSE - If the request must be submitted later */
+/* */
+/************************************************************************/
+
+BOOLEAN QLStartIo(IN PVOID ServiceContext, IN PSCSI_REQUEST_BLOCK pSrb)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ PHW_LUN_EXTENSION pLunExt;
+ USHORT mbox_sts[6];
+
+/*
+ QLPrint((1, "QLStartIo: SRB function: %x", pSrb->Function));
+ QLPrint((1, " flags: %lx", pSrb->SrbFlags));
+ QLPrint((1, " cdb: %x\n", (USHORT)(pSrb->Cdb[0])));
+*/
+
+ switch (pSrb->Function)
+ {
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ // Get LUN extension pointer
+
+ pLunExt = ScsiPortGetLogicalUnit(pDevExt, pSrb->PathId,
+ pSrb->TargetId, pSrb->Lun);
+
+ // Finish up init stuff on 1st request after Inquiry commands
+
+ if (!(pLunExt->LunFlags & LFLG_INIT_COMPLETE) &&
+ pSrb->Cdb[0] != SCSIOP_INQUIRY)
+ {
+ InitDeviceParameters(pDevExt, pLunExt, pSrb);
+ }
+
+ // Build request and send to ISP
+
+ if (!SendCommandToIsp(pDevExt, pSrb))
+ {
+ pDevExt->WaitingSrb = pSrb;
+ pDevExt->AdapterFlags |= AFLG_SRB_WAITING;
+ return(TRUE); // start command later
+ }
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+ case SRB_FUNCTION_TERMINATE_IO:
+
+ QLPrint((1, "QLStartIo: abort command function\n"));
+
+ // Send abort command to ISP
+
+ if (MailboxCommand(pDevExt, mbox_sts, 4, 4,
+ MBOX_CMD_ABORT,
+ (USHORT)(((USHORT)(pSrb->TargetId) << 8) | pSrb->Lun),
+ (USHORT)((ULONG)(pSrb->NextSrb) & 0x0000ffff),
+ (USHORT)((ULONG)(pSrb->NextSrb) >> 16 & 0x0000ffff),
+ 0,0))
+ {
+ pSrb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+ else
+ {
+ QLPrint((1, "QLStartIo: ABORT cmd failed\n"));
+ pSrb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+ }
+
+ ScsiPortNotification(RequestComplete, pDevExt, pSrb);
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ QLPrint((1, "QLStartIo: reset device function\n"));
+
+ // Send abort target command to ISP
+
+ if (MailboxCommand(pDevExt, mbox_sts, 3, 3,
+ MBOX_CMD_ABORT_TARGET,
+ (USHORT)((USHORT)pSrb->TargetId << 8),
+ (USHORT)pDevExt->Bus_Reset_Delay,
+ 0,0,0))
+ {
+ pSrb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+ else
+ {
+ QLPrint((1, "QLStartIo: ABORT TARGET cmd failed\n"));
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+ }
+
+ // Send marker to unlock queues
+
+ if (!SendMarker(pDevExt))
+ {
+ pDevExt->AdapterFlags |= AFLG_SEND_MARKER;
+ }
+ ScsiPortNotification(RequestComplete, pDevExt, pSrb);
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ QLPrint((1, "QLStartIo: reset bus function\n"));
+
+ // Reset SCSI bus and send marker
+
+ if (QLResetScsiBus(pDevExt, 0))
+ {
+ pSrb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+ else
+ {
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+ }
+ ScsiPortNotification(RequestComplete, pDevExt, pSrb);
+ break;
+
+ default:
+
+ QLPrint((1, "QLStartIo: unsupported function %x\n", pSrb->Function));
+
+ // Unsupported function code, complete request with error status
+
+ pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete, pDevExt, pSrb);
+ break;
+ }
+
+ // Request next command
+
+ if (pDevExt->queue_space > 5)
+ {
+ ScsiPortNotification(NextLuRequest, pDevExt, pSrb->PathId,
+ pSrb->TargetId, pSrb->Lun);
+ }
+ else
+ {
+ ScsiPortNotification(NextRequest, pDevExt);
+ }
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* SendCommandToIsp */
+/* */
+/* This function is called by QLStartIo to build an ISP command */
+/* entry and pass it to the ISP for execution. */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* pSrb - Supplies the SCSI request block to be started. */
+/* */
+/* Return Value: */
+/* */
+/* TRUE - If command passed to ISP */
+/* FALSE - If no ISP request slot available */
+/* */
+/************************************************************************/
+
+BOOLEAN SendCommandToIsp(PHW_DEVICE_EXTENSION pDevExt, PSCSI_REQUEST_BLOCK pSrb)
+{
+ PCOMMAND_ENTRY pCmdEntry;
+ USHORT i, segmentCnt;
+ USHORT controlFlags = 0;
+ ULONG transferCnt = pSrb->DataTransferLength;
+ PVOID dataPointer = pSrb->DataBuffer;
+ ULONG length;
+
+ // Send a Marker to ISP if needed
+
+ if (pDevExt->AdapterFlags & AFLG_SEND_MARKER)
+ {
+ if (!SendMarker(pDevExt))
+ {
+ return(FALSE); // Error sending marker
+ }
+ }
+
+ // Disable ISP interrupts
+
+ ISP_WRITE(pDevExt->Adapter, bus_icr, 0);
+
+ // Check available request slots
+
+ if (MAX_CONT_ENTRYS + 1 > pDevExt->queue_space)
+ {
+ if (!CheckQueueSpace(pDevExt, MAX_CONT_ENTRYS + 1))
+ {
+ ISP_WRITE(pDevExt->Adapter, bus_icr,
+ ICR_ENABLE_ALL_INTS | ICR_ENABLE_RISC_INT);
+ return(FALSE); // No queue space
+ }
+ }
+
+ // Get pointer to the queue entry for the command
+
+ pCmdEntry = (PCOMMAND_ENTRY)pDevExt->request_ptr;
+
+ // Advance request queue pointer
+
+ if (pDevExt->request_in == (REQUEST_QUEUE_DEPTH - 1))
+ {
+ pDevExt->request_in = 0;
+ pDevExt->request_ptr = pDevExt->pRequestQueue;
+ }
+ else
+ {
+ pDevExt->request_in++;
+ pDevExt->request_ptr++;
+ }
+ pDevExt->queue_space--;
+
+ // Setup request to send to ISP
+
+ pCmdEntry->hdr.entry_type = ET_COMMAND;
+ pCmdEntry->hdr.entry_cnt = 1; // start with 1
+ pCmdEntry->hdr.flags = 0;
+ pCmdEntry->hdr.sys_def_1 = 0;
+
+ pCmdEntry->handle = (ULONG)pSrb;
+ pCmdEntry->target_id = pSrb->TargetId;
+ pCmdEntry->target_lun = pSrb->Lun;
+ pCmdEntry->reserved = 0;
+
+ // Set command timeout value
+
+ if (pSrb->TimeOutValue > 65535 || pSrb->TimeOutValue == 0)
+ {
+ pCmdEntry->time_out = 0;
+ }
+ else
+ {
+ pCmdEntry->time_out = (USHORT)(pSrb->TimeOutValue + 1);
+ }
+
+ // Setup control flags
+
+ if (pSrb->SrbFlags & SRB_FLAGS_DATA_IN)
+ {
+ controlFlags = CF_READ;
+ }
+ if (pSrb->SrbFlags & SRB_FLAGS_DATA_OUT)
+ {
+ controlFlags = CF_WRITE;
+ }
+
+ if (pSrb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ {
+ controlFlags |= CF_NO_DISCONNECTS;
+ }
+
+ if (pSrb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)
+ {
+ controlFlags |= CF_NO_REQUEST_SENSE;
+ }
+
+ if ((pSrb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) &&
+ (pDevExt->Id[pSrb->TargetId].Capability & CAP_TAGGED_QUEUING))
+ {
+ if (pSrb->QueueAction == SRB_SIMPLE_TAG_REQUEST)
+ controlFlags |= CF_SIMPLE_TAG;
+ else if (pSrb->QueueAction == SRB_HEAD_OF_QUEUE_TAG_REQUEST)
+ controlFlags |= CF_HEAD_TAG;
+ else
+ controlFlags |= CF_ORDERED_TAG;
+ }
+
+ pCmdEntry->control_flags = controlFlags;
+
+ // Move SCSI CDB
+
+ pCmdEntry->cdb_length = pSrb->CdbLength;
+ for (i = 0; i < pCmdEntry->cdb_length; i++)
+ {
+ pCmdEntry->cdb[i] = pSrb->Cdb[i];
+ }
+
+ // Setup data segments
+
+ for (segmentCnt = 0; transferCnt && segmentCnt < 4; segmentCnt++)
+ {
+ pCmdEntry->dseg[segmentCnt].base =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(pDevExt, pSrb, dataPointer, &length));
+ if (length > transferCnt)
+ {
+ length = transferCnt;
+ }
+ pCmdEntry->dseg[segmentCnt].count = length;
+ transferCnt -= length;
+ dataPointer = (PUCHAR)dataPointer + length;
+ }
+
+ while (transferCnt)
+ {
+ PCONTINUATION_ENTRY pContEntry;
+
+ // Get ptr to next queue entry for command and bump entry count
+
+ pContEntry = (PCONTINUATION_ENTRY)pDevExt->request_ptr;
+
+ pCmdEntry->hdr.entry_cnt++;
+
+ // Advance request queue pointer
+
+ if (pDevExt->request_in == (REQUEST_QUEUE_DEPTH - 1))
+ {
+ pDevExt->request_in = 0;
+ pDevExt->request_ptr = pDevExt->pRequestQueue;
+ }
+ else
+ {
+ pDevExt->request_in++;
+ pDevExt->request_ptr++;
+ }
+ pDevExt->queue_space--;
+
+ // Setup header
+
+ pContEntry->hdr.entry_type = ET_CONTINUATION;
+ pContEntry->hdr.entry_cnt = 1; // hopefully RISC doesn't need total here
+ pContEntry->hdr.flags = EF_CONTINUATION;
+ pContEntry->hdr.sys_def_1 = 0;
+
+ // Fill in data segments
+
+ for (i = 0; transferCnt && i < 7; i++, segmentCnt++)
+ {
+ pContEntry->dseg[i].base =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(pDevExt, pSrb, dataPointer, &length));
+ if (length > transferCnt)
+ {
+ length = transferCnt;
+ }
+ pContEntry->dseg[i].count = length;
+ transferCnt -= length;
+ dataPointer = (PUCHAR)dataPointer + length;
+ }
+ }
+ pCmdEntry->segment_cnt = segmentCnt;
+
+ // Tell ISP it's got a new I/O request
+
+ ISP_WRITE(pDevExt->Adapter, mailbox4, pDevExt->request_in);
+
+ // Enable ISP interrupts
+
+ ISP_WRITE(pDevExt->Adapter, bus_icr, ICR_ENABLE_ALL_INTS | ICR_ENABLE_RISC_INT);
+
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* QLInterruptServiceRoutine */
+/* */
+/* This routine is the interrupt service routine for the ISP1020. */
+/* The response queue is checked for completed commands. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* */
+/* Return Value: */
+/* */
+/* TRUE - Indicates that an interrupt was found. */
+/* FALSE - Indicates the device was not interrupting. */
+/* */
+/************************************************************************/
+
+BOOLEAN QLInterruptServiceRoutine(PVOID ServiceContext)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ PSCSI_REQUEST_BLOCK pSrb;
+ USHORT response_in;
+ PSTATUS_ENTRY pStsEntry;
+ USHORT status;
+
+
+// QLPrint((1, "ISR: Entering, pDevExt = %lx\n", (ULONG)pDevExt));
+
+ if (!(ISP_READ(pDevExt->Adapter, bus_isr) & BUS_ISR_RISC_INT))
+ {
+ // QLPrint((1, "ISR: spurious interrupt?\n"));
+ return(FALSE); // not my interrupt
+ }
+
+ // Loop to process all responses from ISP
+
+ do
+ {
+ // Check for async mailbox event
+
+ if (ISP_READ(pDevExt->Adapter, bus_sema) & BUS_SEMA_LOCK)
+ {
+ // Check mailbox status
+
+ status = ISP_READ(pDevExt->Adapter, mailbox0);
+ switch (status)
+ {
+ case MBOX_ASTS_SCSI_BUS_RESET:
+ QLPrint((1, "ISR: SCSI bus reset detected\n"));
+ QLCleanupAfterReset(pDevExt);
+ break;
+
+ case MBOX_ASTS_TIMEOUT_RESET:
+ QLPrint((1, "ISR: command timeout reset\n"));
+ QLCleanupAfterReset(pDevExt);
+ break;
+
+ default:
+ QLPrint((1, "ISR: Unexpected MailBox Response: %x", status));
+ QLPrint((1, " %x", ISP_READ(pDevExt->Adapter, mailbox1)));
+ QLPrint((1, " %x", ISP_READ(pDevExt->Adapter, mailbox2)));
+ QLPrint((1, " %x", ISP_READ(pDevExt->Adapter, mailbox3)));
+ QLPrint((1, " %x", ISP_READ(pDevExt->Adapter, mailbox4)));
+ QLPrint((1, " %x\n", ISP_READ(pDevExt->Adapter, mailbox5)));
+ }
+
+ QLLogError(pDevExt, NULL, SP_INTERNAL_ADAPTER_ERROR, (ULONG)status);
+
+ // Clear the semaphore lock
+
+ ISP_WRITE(pDevExt->Adapter, bus_sema, 0);
+ }
+
+ // Get current "response in" pointer
+
+ response_in = ISP_READ(pDevExt->Adapter, mailbox5);
+
+ // Clear risc interrupt
+
+ ISP_WRITE(pDevExt->Adapter, hccr, HCCR_CMD_CLEAR_RISC_INT);
+
+ // Process all responses from response queue
+
+ while (pDevExt->response_out != response_in)
+ {
+ // Get pointer to next response entry
+
+ pStsEntry = (PSTATUS_ENTRY)pDevExt->response_ptr;
+
+ // Advance pointers for next entry
+
+ if (pDevExt->response_out == (RESPONSE_QUEUE_DEPTH - 1))
+ {
+ pDevExt->response_out = 0;
+ pDevExt->response_ptr = pDevExt->pResponseQueue;
+ }
+ else
+ {
+ pDevExt->response_out++;
+ pDevExt->response_ptr++;
+ }
+
+ // Verify we have a valid Status queue entry
+
+ if (pStsEntry->hdr.entry_type != ET_STATUS ||
+ pStsEntry->hdr.flags & EF_ERROR_MASK)
+ {
+ QLPrint((1, "ISR - Invalid Status queue entry\n"));
+ }
+
+ // Set SRB pointer from queue entry handle
+
+ pSrb = (PSCSI_REQUEST_BLOCK)pStsEntry->handle;
+
+ // Check for normal completion
+
+ if (pStsEntry->completion_status == SCS_COMPLETE &&
+ pStsEntry->scsi_status == SCSISTAT_GOOD)
+ {
+ pSrb->SrbStatus = SRB_STATUS_SUCCESS;
+ pSrb->ScsiStatus = SCSISTAT_GOOD;
+ ScsiPortNotification(RequestComplete, pDevExt, pSrb);
+ }
+
+ // Error handling
+
+ else
+ {
+ // Convert ISP/SCSI error status to SRB error status
+
+ SetErrorStatus(pDevExt, pSrb, pStsEntry);
+
+ // Looks like retries are handled at a higher level
+ // Just return the error status (and sense data)
+
+ QLPrint((1, "ISR: Request completed with error = %x\n", pSrb->SrbStatus));
+
+ if (pSrb->SrbStatus == SRB_STATUS_DATA_OVERRUN)
+ {
+ pSrb->DataTransferLength -= pStsEntry->residual;
+ }
+ ScsiPortNotification(RequestComplete, pDevExt, pSrb);
+ }
+ }
+
+ // Done with responses, update the ISP
+
+ ISP_WRITE(pDevExt->Adapter, mailbox5, pDevExt->response_out);
+
+ } while (ISP_READ(pDevExt->Adapter, bus_isr) & BUS_ISR_RISC_INT);
+
+ // Check for waiting SRB and try to start it again
+
+ if (pDevExt->AdapterFlags & AFLG_SRB_WAITING)
+ {
+ pSrb = pDevExt->WaitingSrb;
+ if (SendCommandToIsp(pDevExt, pSrb))
+ {
+ // Command queued OK this time, notify port driver
+
+ pDevExt->AdapterFlags &= ~AFLG_SRB_WAITING;
+ ScsiPortNotification(NextLuRequest, pDevExt, pSrb->PathId,
+ pSrb->TargetId, pSrb->Lun);
+ }
+ }
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* SetErrorStatus */
+/* */
+/* This routine is called by the interrupt service routine to */
+/* convert an error status from the ISP into a SRB error status. */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* pSrb - Pointer to SRB */
+/* pStsEntry - Pointer to status entry from the ISP */
+/* */
+/* Return Value: */
+/* */
+/* None */
+/* */
+/************************************************************************/
+
+VOID SetErrorStatus(PHW_DEVICE_EXTENSION pDevExt, PSCSI_REQUEST_BLOCK pSrb,
+ PSTATUS_ENTRY pStsEntry)
+{
+ ULONG length;
+ USHORT mbox_sts[6];
+
+ QLPrint((1, "ISR: completion sts=%x", pStsEntry->completion_status));
+ QLPrint((1, " SCSI ID=%x", pSrb->TargetId));
+ QLPrint((1, " SCSI sts=%x", pStsEntry->scsi_status));
+ QLPrint((1, " sense key=%x\n", (USHORT)(pStsEntry->req_sense_data[2])));
+
+ // Convert ISP completion status to SRB error code
+
+ if (pStsEntry->completion_status != SCS_COMPLETE)
+ {
+ if (pStsEntry->completion_status < sizeof(CmpStsErrorMap))
+ {
+ pSrb->SrbStatus = CmpStsErrorMap[pStsEntry->completion_status];
+ }
+ else
+ {
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+ }
+ if (pStsEntry->completion_status == SCS_RESET_OCCURRED ||
+ pStsEntry->completion_status == SCS_TIMEOUT)
+ {
+ QLCleanupAfterReset(pDevExt);
+ }
+
+ // Log error (if not data underrun and not Inquiry selection timeout)
+
+ if (pSrb->SrbStatus != SRB_STATUS_DATA_OVERRUN &&
+ (pStsEntry->completion_status != SCS_INCOMPLETE ||
+ pSrb->Cdb[0] != SCSIOP_INQUIRY))
+ {
+ QLLogError(pDevExt, pSrb, SP_INTERNAL_ADAPTER_ERROR,
+ (ULONG)pStsEntry->completion_status);
+ }
+ }
+
+ // Handle SCSI error status, return sense data
+
+ else
+ {
+ // Return scsi status
+
+ pSrb->ScsiStatus = (UCHAR)pStsEntry->scsi_status;
+ pSrb->SrbStatus = SRB_STATUS_ERROR;
+
+ switch(pStsEntry->scsi_status)
+ {
+ case SCSISTAT_CHECK_CONDITION:
+
+ // Return request sense data
+
+ if ((pStsEntry->state_flags & SS_GOT_SENSE) &&
+ !(pSrb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) &&
+ pSrb->SenseInfoBufferLength)
+ {
+
+ QLPrint((1, "ISR: Returning sense data\n"));
+
+ if (pStsEntry->req_sense_length > pSrb->SenseInfoBufferLength)
+ length = (ULONG)(pSrb->SenseInfoBufferLength);
+ else
+ length = (ULONG)(pStsEntry->req_sense_length);
+ ScsiPortMoveMemory(pSrb->SenseInfoBuffer,
+ pStsEntry->req_sense_data, length);
+ pSrb->SenseInfoBufferLength = (UCHAR)length;
+ pSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+ }
+
+ // If check condition and autosense disabled, need to
+ // restart command queue
+
+ if (pSrb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)
+ {
+ // Restart RISC command queue
+
+ QLPrint((1, "ISR: Restart RISC queue\n"));
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 3,
+ MBOX_CMD_START_QUEUE,
+ (USHORT)(((USHORT)(pSrb->TargetId) << 8) | pSrb->Lun),
+ 0,0,0,0))
+ {
+ QLPrint((1, "ISR: START QUEUE command failed\n"));
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+/************************************************************************/
+/* */
+/* QLLogError */
+/* */
+/* This routine is called to log an error to the system. */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* pSrb - Supplies pointer to SRB or NULL if no SRB */
+/* ErrorCode - Supplies the error code to log with the error */
+/* UniqueId - Supplies the unique error identifier */
+/* */
+/* Return Value: */
+/* */
+/* None */
+/* */
+/************************************************************************/
+
+VOID QLLogError(IN PHW_DEVICE_EXTENSION pDevExt, IN PSCSI_REQUEST_BLOCK pSrb,
+ IN ULONG ErrorCode, IN ULONG UniqueId)
+{
+
+ QLPrint((1, "QLLogError called\n"));
+
+ if (pSrb == NULL)
+ {
+ ScsiPortLogError(
+ pDevExt, // HwDeviceExtension
+ NULL, // Srb
+ 0, // PathId
+ 0, // TargetId
+ 0, // Lun
+ ErrorCode, // ErrorCode
+ UniqueId // UniqueId
+ );
+ }
+ else
+ {
+ ScsiPortLogError(
+ pDevExt, // HwDeviceExtension
+ pSrb, // Srb
+ pSrb->PathId, // PathId
+ pSrb->TargetId, // TargetId
+ pSrb->Lun, // Lun
+ ErrorCode, // ErrorCode
+ UniqueId // UniqueId
+ );
+ }
+}
+
+
+/************************************************************************/
+/* */
+/* MailboxCommand */
+/* */
+/* This routine issues a mailbox command and waits for completion */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* */
+/* Return Value: */
+/* */
+/* TRUE if command completed OK */
+/* FALSE if error */
+/* */
+/************************************************************************/
+
+BOOLEAN MailboxCommand(IN PHW_DEVICE_EXTENSION pDevExt,
+ USHORT *mbox_sts, UCHAR out_cnt, UCHAR in_cnt,
+ USHORT reg0, USHORT reg1, USHORT reg2,
+ USHORT reg3, USHORT reg4, USHORT reg5)
+{
+ ULONG waitcnt;
+ USHORT retrycnt;
+ USHORT controlReg;
+
+/*
+ QLPrint((1, " MailboxCommand %x", reg0));
+ QLPrint((1, " %x", reg1));
+ QLPrint((1, " %x", reg2));
+ QLPrint((1, " %x", reg3));
+ QLPrint((1, " %x", reg4));
+ QLPrint((1, " %x\n", reg5));
+*/
+
+ // Disable adapter interrupts
+
+ controlReg = ISP_READ(pDevExt->Adapter, bus_icr);
+ if (controlReg & ICR_ENABLE_ALL_INTS)
+ {
+ ISP_WRITE(pDevExt->Adapter, bus_icr, 0);
+ }
+
+ // Use loop to retry mailbox command if busy status returned
+
+ retrycnt = 16; // retry a few times if busy
+ do
+ {
+ // Make sure host interrupt is clear
+
+ waitcnt = 10000; // wait a little bit if necessary
+ while (ISP_READ(pDevExt->Adapter, hccr) & HCCR_HOST_INT)
+ {
+ if (waitcnt-- == 0)
+ {
+ QLPrint((1, "MailboxCommand: host interrupt timeout\n"));
+ ISP_WRITE(pDevExt->Adapter, bus_icr, controlReg);
+ return(FALSE);
+ }
+ }
+
+ // Load data to the mailbox registers
+
+ switch (out_cnt)
+ {
+ case 6: ISP_WRITE(pDevExt->Adapter, mailbox5, reg5);
+ case 5: if (reg0 != MBOX_CMD_INIT_RESPONSE_QUEUE)
+ ISP_WRITE(pDevExt->Adapter, mailbox4, reg4);
+ case 4: ISP_WRITE(pDevExt->Adapter, mailbox3, reg3);
+ case 3: ISP_WRITE(pDevExt->Adapter, mailbox2, reg2);
+ case 2: ISP_WRITE(pDevExt->Adapter, mailbox1, reg1);
+ case 1: ISP_WRITE(pDevExt->Adapter, mailbox0, reg0);
+ }
+
+ // Wake up the ISP
+
+ ISP_WRITE(pDevExt->Adapter, hccr, HCCR_CMD_SET_HOST_INT);
+
+ // Wait for command to complete
+
+ waitcnt = 100000;
+ while (!(ISP_READ(pDevExt->Adapter, bus_isr) & BUS_ISR_RISC_INT) ||
+ !(ISP_READ(pDevExt->Adapter, bus_sema) & BUS_SEMA_LOCK))
+ {
+ if (waitcnt-- == 0)
+ {
+ QLPrint((1, "MailboxCommand: cmd completion timeout\n"));
+ ISP_WRITE(pDevExt->Adapter, bus_icr, controlReg);
+ return(FALSE);
+ }
+ }
+
+ // Save away status registers
+
+ mbox_sts[0] = ISP_READ(pDevExt->Adapter, mailbox0);
+ switch (in_cnt)
+ {
+ case 6: mbox_sts[5] = ISP_READ(pDevExt->Adapter, mailbox5);
+ case 5: if (reg0 != MBOX_CMD_INIT_RESPONSE_QUEUE)
+ mbox_sts[4] = ISP_READ(pDevExt->Adapter, mailbox4);
+ case 4: mbox_sts[3] = ISP_READ(pDevExt->Adapter, mailbox3);
+ case 3: mbox_sts[2] = ISP_READ(pDevExt->Adapter, mailbox2);
+ case 2: mbox_sts[1] = ISP_READ(pDevExt->Adapter, mailbox1);
+ }
+
+ // Clear the semaphore lock
+
+ ISP_WRITE(pDevExt->Adapter, bus_sema, 0);
+
+ // Clear interrupt
+
+ ISP_WRITE(pDevExt->Adapter, hccr, HCCR_CMD_CLEAR_RISC_INT);
+
+ // Check status from ISP
+
+ switch (mbox_sts[0])
+ {
+ case MBOX_STS_BUSY:
+ QLPrint((1, "MailboxCommand: ISP busy\n"));
+ break; // retry command
+
+ case MBOX_STS_COMMAND_COMPLETE:
+ ISP_WRITE(pDevExt->Adapter, bus_icr, controlReg);
+ return(TRUE); // return good status
+
+ case MBOX_ASTS_SCSI_BUS_RESET:
+ pDevExt->AdapterFlags |= AFLG_SEND_MARKER;
+ QLPrint((1, "MailboxCommand: ISP SCSI bus RESET seen\n"));
+ break; // retry command
+
+ default:
+ QLPrint((1, "MailboxCommand: error status = %lx\n", mbox_sts[0]));
+ ISP_WRITE(pDevExt->Adapter, bus_icr, controlReg);
+ QLLogError(pDevExt, NULL, SP_INTERNAL_ADAPTER_ERROR,
+ (ULONG)mbox_sts[0]);
+ return(FALSE); // return error status
+ }
+ } while (retrycnt--);
+
+ QLPrint((1, "MailboxCommand: busy timeout\n"));
+ ISP_WRITE(pDevExt->Adapter, bus_icr, controlReg);
+ return(FALSE);
+}
+
+
+/************************************************************************/
+/* */
+/* SendMarker */
+/* */
+/* This call sends a Marker packet to the ISP */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* */
+/* Return Value: */
+/* */
+/* TRUE - marker sent */
+/* FALSE - no slot in request queue */
+/* */
+/************************************************************************/
+
+BOOLEAN SendMarker(IN PHW_DEVICE_EXTENSION pDevExt)
+{
+ PMARKER_ENTRY pMarkEntry;
+
+ // Disable ISP interrupts
+
+ ISP_WRITE(pDevExt->Adapter, bus_icr, 0);
+
+ // Check available queue space
+
+ if (!CheckQueueSpace(pDevExt, 1))
+ {
+ ISP_WRITE(pDevExt->Adapter, bus_icr, ICR_ENABLE_ALL_INTS | ICR_ENABLE_RISC_INT);
+ return(FALSE); // No queue space, return error
+ }
+
+ // Reset the flag so we don't send another marker
+
+ pDevExt->AdapterFlags &= ~AFLG_SEND_MARKER;
+
+ // Get pointer to the queue entry for the marker
+
+ pMarkEntry = (PMARKER_ENTRY)pDevExt->request_ptr;
+
+ // Move the internal pointers for the request queue
+
+ if (pDevExt->request_in == (REQUEST_QUEUE_DEPTH - 1))
+ {
+ pDevExt->request_in = 0;
+ pDevExt->request_ptr = pDevExt->pRequestQueue;
+ }
+ else
+ {
+ pDevExt->request_in++;
+ pDevExt->request_ptr++;
+ }
+
+ // Put the marker in the request queue
+
+ pMarkEntry->hdr.entry_type = ET_MARKER;
+ pMarkEntry->hdr.entry_cnt = 1;
+ pMarkEntry->hdr.flags = 0;
+ pMarkEntry->hdr.sys_def_1 = 0;
+ pMarkEntry->reserved0 = 0;
+ pMarkEntry->target_id = 0;
+ pMarkEntry->target_lun = 0;
+ pMarkEntry->reserved1 = 0;
+ pMarkEntry->modifier = 2;
+
+ // Tell ISP it's got a new I/O request
+
+ ISP_WRITE(pDevExt->Adapter, mailbox4, pDevExt->request_in);
+
+ // One less I/O slot
+
+ pDevExt->queue_space--;
+
+ // Enable ISP interrupts
+
+ ISP_WRITE(pDevExt->Adapter, bus_icr, ICR_ENABLE_ALL_INTS | ICR_ENABLE_RISC_INT);
+
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* CheckQueueSpace */
+/* */
+/* This call checks if enough request queue slots are available */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* slotcnt - number of needed slots */
+/* */
+/* Return Value: */
+/* */
+/* TRUE - request slots are available */
+/* FALSE - request slots not available */
+/* */
+/************************************************************************/
+
+BOOLEAN CheckQueueSpace(IN PHW_DEVICE_EXTENSION pDevExt, USHORT slotcnt)
+{
+ USHORT mailbox4;
+
+ // Update available slot count
+
+ mailbox4 = ISP_READ(pDevExt->Adapter, mailbox4);
+ pDevExt->request_out = mailbox4;
+
+ if (pDevExt->request_in == pDevExt->request_out)
+ {
+ pDevExt->queue_space = REQUEST_QUEUE_DEPTH - 1;
+ }
+ else if (pDevExt->request_in > pDevExt->request_out)
+ {
+ pDevExt->queue_space = ((REQUEST_QUEUE_DEPTH - 1) -
+ (pDevExt->request_in - pDevExt->request_out));
+ }
+ else
+ {
+ pDevExt->queue_space = (pDevExt->request_out-pDevExt->request_in)-1;
+ }
+
+ // Check if enough are now available
+
+ if (pDevExt->queue_space >= slotcnt)
+ {
+ return(TRUE); // Queue space available, return
+ }
+ else
+ {
+ QLPrint((1, "CheckQueueSpace: no request queue space\n"));
+ return(FALSE); // No space, return error status
+ }
+}
+
+
+/************************************************************************/
+/* */
+/* QLResetScsiBus */
+/* */
+/* This function resets the SCSI bus and calls the reset cleanup */
+/* function. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* PathId - Supplies the path id of the bus */
+/* */
+/* Return Value: */
+/* */
+/* TRUE - Indicating the reset is complete */
+/* FALSE - if error doing reset */
+/* */
+/************************************************************************/
+
+BOOLEAN QLResetScsiBus(IN PVOID ServiceContext, IN ULONG PathId)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ USHORT mbox_sts[6];
+ USHORT i;
+
+ QLPrint((1, "QLResetScsiBus: Resetting the SCSI bus\n"));
+
+ // Reset SCSI bus
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_BUS_RESET,
+ pDevExt->Bus_Reset_Delay,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLResetScsiBus: SCSI BUS RESET command failed\n"));
+ return(FALSE);
+ }
+
+ // Wait for RISC reset delay
+
+ for (i = 0; i < pDevExt->Bus_Reset_Delay * 1000; i++)
+ ScsiPortStallExecution((ULONG)1000);
+
+ QLCleanupAfterReset(pDevExt);
+
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* QLCleanupAfterReset */
+/* */
+/* This routine is called after a SCSI bus reset occurs. */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* */
+/* Return Value: */
+/* */
+/* None */
+/* */
+/************************************************************************/
+
+VOID QLCleanupAfterReset(IN PHW_DEVICE_EXTENSION pDevExt)
+{
+
+ // Reenable ISP queues
+
+ if (!SendMarker(pDevExt))
+ {
+ QLPrint((1, "QLCleanupAfterReset: Failed to send marker\n"));
+ pDevExt->AdapterFlags |= AFLG_SEND_MARKER;
+ }
+
+ ScsiPortNotification(ResetDetected, pDevExt, NULL);
+
+}
+
+
+/************************************************************************/
+/* */
+/* QLAdapterState */
+/* */
+/* This function is called for switching states between real and */
+/* protected mode drivers. */
+/* */
+/* Arguments: */
+/* */
+/* ServiceContext - Supplies a pointer to the device extension */
+/* Context - */
+/* SaveState - TRUE indicates adapter state should be saved */
+/* FALSE indicates adapter state should be restored */
+/* */
+/* Return Value: */
+/* */
+/* TRUE - Indicating the operation is complete */
+/* FALSE - if error */
+/* */
+/************************************************************************/
+
+BOOLEAN QLAdapterState(IN PVOID ServiceContext,IN PVOID Context,IN BOOLEAN SaveState)
+{
+ PHW_DEVICE_EXTENSION pDevExt = ServiceContext;
+ USHORT mbox_sts[6];
+
+ if (SaveState)
+ {
+ QLPrint((1, "QLAdapterState: save adapter state\n"));
+ }
+ else
+ {
+ QLPrint((1, "QLAdapterState: restore adapter state\n"));
+
+ // Disable ISP interrupts for ROM BIOS
+
+ ISP_WRITE(pDevExt->Adapter, bus_icr, ICR_DISABLE_ALL_INTS);
+
+ // Disable RISC request queue
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_INIT_REQUEST_QUEUE,
+ 0,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLAdapterState: INIT REQUEST QUEUE cmd failed\n"));
+ return(FALSE);
+ }
+
+ // Disable RISC response queue
+
+ if (!MailboxCommand(pDevExt, mbox_sts, 2, 2,
+ MBOX_CMD_INIT_RESPONSE_QUEUE,
+ 0,
+ 0,0,0,0))
+ {
+ QLPrint((1, "QLAdapterState: INIT RESPONSE QUEUE cmd failed\n"));
+ return(FALSE);
+ }
+
+ }
+
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* GetNovramParameters */
+/* */
+/* This routine gets NOVRAM parameters and sets up in host adapter */
+/* block, use default values if NOVRAM data not valid. */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* */
+/* Return Value: */
+/* */
+/* None */
+/* */
+/************************************************************************/
+
+VOID GetNovramParameters(IN PHW_DEVICE_EXTENSION pDevExt)
+{
+ NOVRAM NovramParameters;
+ PNOVRAM nvram_ptr = &NovramParameters;
+ USHORT i;
+
+ // Read in entire NOVRAM and perform checksum to make sure data is valid
+
+ if (ReadAllNovram(pDevExt, (UCHAR*)nvram_ptr))
+ {
+ QLPrint((1, "GetNovramParameters: parameters valid\n"));
+
+ // NOVRAM valid, use paramters
+
+ pDevExt->Config_Reg = nvram_ptr->Fifo_Threshold;
+ pDevExt->Host_Adapter_Enable = nvram_ptr->Host_Adapter_Enable;
+ pDevExt->Initiator_SCSI_Id = nvram_ptr->Initiator_SCSI_Id;
+ pDevExt->Bus_Reset_Delay = nvram_ptr->Bus_Reset_Delay;
+
+ // Only 1 retry and no delay for NT driver (Disk Administrator problem)
+ // pDevExt->Retry_Count = nvram_ptr->Retry_Count;
+ // pDevExt->Retry_Delay = nvram_ptr->Retry_Delay;
+ pDevExt->Retry_Count = NVRAM_DEF_RETRY_COUNT;
+ pDevExt->Retry_Delay = NVRAM_DEF_RETRY_DELAY;
+
+ pDevExt->ASync_Data_Setup_Time = nvram_ptr->ASync_Data_Setup_Time;
+ pDevExt->REQ_ACK_Active_Negation= nvram_ptr->REQ_ACK_Active_Negation;
+ pDevExt->DATA_Active_Negation = nvram_ptr->DATA_Line_Active_Negation;
+ pDevExt->Data_DMA_Burst_Enable = nvram_ptr->Data_DMA_Burst_Enable;
+ pDevExt->Cmd_DMA_Burst_Enable = nvram_ptr->Command_DMA_Burst_Enable;
+ pDevExt->Tag_Age_Limit = nvram_ptr->Tag_Age_Limit;
+ pDevExt->Selection_Timeout = nvram_ptr->Selection_Timeout;
+ pDevExt->Max_Queue_Depth = nvram_ptr->Max_Queue_Depth;
+ pDevExt->Termination_Low_Enable = nvram_ptr->Termination_Low_Enable;
+ pDevExt->Termination_High_Enable= nvram_ptr->Termination_High_Enable;
+ pDevExt->PCMC_Burst_Enable = nvram_ptr->PCMC_Burst_Enable;
+ pDevExt->Sixty_MHz_Enable = nvram_ptr->Sixty_MHz_Enable;
+
+ for (i = 0; i < 16; i++)
+ {
+ UCHAR temp = 0;
+
+ temp |= nvram_ptr->Id[i].Renegotiate_on_Error << 0;
+ temp |= nvram_ptr->Id[i].Stop_Queue_on_Check << 1;
+ temp |= nvram_ptr->Id[i].Auto_Request_Sense << 2;
+ temp |= nvram_ptr->Id[i].Tagged_Queuing << 3;
+ temp |= nvram_ptr->Id[i].Sync_Data_Transfers << 4;
+ temp |= nvram_ptr->Id[i].Wide_Data_Transfers << 5;
+ temp |= nvram_ptr->Id[i].Parity_Checking << 6;
+ temp |= nvram_ptr->Id[i].Disconnect_Allowed << 7;
+
+ pDevExt->Id[i].Capability = temp;
+ pDevExt->Id[i].Execution_Throttle = nvram_ptr->Id[i].Execution_Throttle;
+ pDevExt->Id[i].Sync_Period = nvram_ptr->Id[i].Sync_Period;
+ pDevExt->Id[i].Sync_Offset = nvram_ptr->Id[i].Sync_Offset;
+ pDevExt->Id[i].Device_Enable= nvram_ptr->Id[i].Device_Enable;
+
+ // Force auto request sense ON and stop queue OFF
+
+ pDevExt->Id[i].Capability |= CAP_AUTO_REQ_SENSE;
+ pDevExt->Id[i].Capability &= ~CAP_STOP_QUEUE_ON_CHECK;
+
+ if (pDevExt->Id[i].Capability & CAP_TAGGED_QUEUING)
+ {
+ pDevExt->AdapterFlags |= AFLG_TAGGED_QUEUING;
+ }
+ }
+ }
+ else
+ {
+ QLPrint((1, "GetNovramParameters: parameters NOT valid, using defaults\n"));
+
+ // Use defaults, NOVRAM was not programmed
+
+ pDevExt->Config_Reg = NVRAM_DEF_FIFO_THRESHOLD;
+ pDevExt->Host_Adapter_Enable = NVRAM_DEF_ADAPTER_ENABLE;
+ pDevExt->Initiator_SCSI_Id = NVRAM_DEF_INITIATOR_SCSI_ID;
+ pDevExt->Bus_Reset_Delay = NVRAM_DEF_BUS_RESET_DELAY;
+ pDevExt->Retry_Count = NVRAM_DEF_RETRY_COUNT;
+ pDevExt->Retry_Delay = NVRAM_DEF_RETRY_DELAY;
+ pDevExt->ASync_Data_Setup_Time = NVRAM_DEF_ASYNC_SETUP_TIME;
+ pDevExt->REQ_ACK_Active_Negation= NVRAM_DEF_REQ_ACK_ACTIVE_NEGATION;
+ pDevExt->DATA_Active_Negation = NVRAM_DEF_DATA_ACTIVE_NEGATION;
+ pDevExt->Data_DMA_Burst_Enable = NVRAM_DEF_DATA_DMA_BURST_ENABLE;
+ pDevExt->Cmd_DMA_Burst_Enable = NVRAM_DEF_CMD_DMA_BURST_ENABLE;
+ pDevExt->Tag_Age_Limit = NVRAM_DEF_TAG_AGE_LIMIT;
+ pDevExt->Selection_Timeout = NVRAM_DEF_SELECTION_TIMEOUT;
+ pDevExt->Max_Queue_Depth = NVRAM_DEF_MAX_QUEUE_DEPTH;
+ pDevExt->Termination_Low_Enable = NVRAM_DEF_TERMINATION_LOW_ENABLE;
+ pDevExt->Termination_High_Enable= NVRAM_DEF_TERMINATION_HIGH_ENABLE;
+ pDevExt->PCMC_Burst_Enable = NVRAM_DEF_PCMC_BURST_ENABLE;
+ pDevExt->Sixty_MHz_Enable = NVRAM_DEF_SIXTY_MHZ_ENABLE;
+
+ for (i = 0; i < 16; i++)
+ {
+ UCHAR temp = 0;
+
+ temp |= NVRAM_DEF_RENEGOTIATE_ON_ERROR << 0;
+ temp |= NVRAM_DEF_STOP_QUEUE_ON_CHECK << 1;
+ temp |= NVRAM_DEF_AUTO_REQUEST_SENSE << 2;
+ temp |= NVRAM_DEF_TAGGED_QUEUING << 3;
+ temp |= NVRAM_DEF_SYNC_DATA_TRANSFERS << 4;
+ temp |= NVRAM_DEF_WIDE_DATA_TRANSFERS << 5;
+ temp |= NVRAM_DEF_PARITY_CHECKING << 6;
+ temp |= NVRAM_DEF_DISCONNECT_ALLOWED << 7;
+
+ pDevExt->Id[i].Capability = temp;
+ pDevExt->Id[i].Execution_Throttle = NVRAM_DEF_EXECUTION_THROTTLE;
+ pDevExt->Id[i].Sync_Period = NVRAM_DEF_SYNC_PERIOD;
+ pDevExt->Id[i].Sync_Offset = NVRAM_DEF_SYNC_OFFSET;
+ pDevExt->Id[i].Device_Enable= NVRAM_DEF_DEVICE_ENABLE;
+
+ if (pDevExt->Id[i].Capability & CAP_TAGGED_QUEUING)
+ {
+ pDevExt->AdapterFlags |= AFLG_TAGGED_QUEUING;
+ }
+ }
+ }
+
+ // Enable burst mode
+
+ if (pDevExt->Data_DMA_Burst_Enable || pDevExt->Cmd_DMA_Burst_Enable)
+ {
+ pDevExt->Config_Reg |= NVRAM_CONFIG_BURST_ENABLE;
+ }
+}
+
+
+/************************************************************************/
+/* */
+/* ReadAllNovram */
+/* */
+/* This routine is called to read the entire NOVRAM into buffer */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* buf - pointer to parameter buffer */
+/* */
+/* Return Value: */
+/* */
+/* TRUE if NOVRAM read OK */
+/* FALSE if NOVRAM not valid */
+/* */
+/************************************************************************/
+
+BOOLEAN ReadAllNovram(IN PHW_DEVICE_EXTENSION pDevExt, UCHAR* buf)
+{
+ UCHAR* ptr;
+ UCHAR sum;
+ USHORT index;
+
+ // Loop through the entire NOVRAM (64 words)
+
+ ptr = (UCHAR*)buf;
+ for (index = 0; index < 64; index++, ptr += 2)
+ {
+ // Read next word from NOVRAM
+
+ ReadNovramWord(pDevExt, index, (USHORT*)ptr);
+ }
+
+ // Check for a valid signiture
+
+ if (buf[0] != 'I' ||
+ buf[1] != 'S' ||
+ buf[2] != 'P' ||
+ buf[3] != ' ')
+ {
+ return(FALSE); // invalid signature
+ }
+
+ // Check version number for 2 or above
+
+ if (buf[4] < 2)
+ {
+ QLPrint((1, "NOVRAM wrong version\n"));
+ return(FALSE); // wrong version (old NOVRAM layout)
+ }
+
+ // Verify correct checksum
+
+ ptr = (UCHAR*)buf;
+ for (sum = 0, index = 0; index < 128; index++, ptr++)
+ {
+ sum += *ptr;
+ }
+ if (sum != 0)
+ {
+ return(FALSE); // bad checksum
+ }
+
+ return(TRUE);
+}
+
+
+/************************************************************************/
+/* */
+/* ReadNovramWord */
+/* */
+/* This routine is called to read a word from NOVRAM */
+/* */
+/* Arguments: */
+/* */
+/* pDevExt - Supplies a pointer to the device extension */
+/* addr - NOVRAM word offset to read */
+/* ptr - pointer to parameter buffer */
+/* */
+/* Return Value: */
+/* */
+/* None */
+/* */
+/************************************************************************/
+
+VOID ReadNovramWord(IN PHW_DEVICE_EXTENSION pDevExt,
+ USHORT addr, USHORT* ptr)
+{
+ USHORT word_val;
+ USHORT bit_val;
+ SHORT index;
+
+ // Select the chip
+
+ ISP_WRITE(pDevExt->Adapter, NvRam_reg, NVRAM_SELECT);
+ NovramDelay();
+ ISP_WRITE(pDevExt->Adapter, NvRam_reg, (NVRAM_SELECT | NVRAM_CLOCK));
+ NovramDelay();
+
+ // Setup 9 bit command word: 1 start bit, 2 opcode bits, 6 addr bits
+
+ word_val = (NVRAM_READ_OP << 6) | (addr & 0x3F);
+
+ // Send the request
+
+ for (index = 8; index >= 0; index--)
+ {
+ // determine if we should send a one or a zero
+
+ bit_val = 0;
+ if ((word_val >> index) & 1)
+ {
+ bit_val = NVRAM_DATA_OUT;
+ }
+
+ // send the bit to the NvRam
+ // 1. Select + data bit, delay
+ // 2. Select + data bit + clock, delay
+ // 3. Select + data bit (remove clock), delay
+
+ ISP_WRITE(pDevExt->Adapter, NvRam_reg, (USHORT)(NVRAM_SELECT | bit_val));
+ NovramDelay();
+
+ ISP_WRITE(pDevExt->Adapter, NvRam_reg,
+ (USHORT)(NVRAM_SELECT | bit_val | NVRAM_CLOCK));
+ NovramDelay();
+
+ ISP_WRITE(pDevExt->Adapter, NvRam_reg, (USHORT)(NVRAM_SELECT | bit_val));
+ NovramDelay();
+ }
+
+ // Zap the location we're reading to before starting
+
+ *ptr = 0;
+
+ // read the NvRam data
+
+ for (index = 15; index >= 0; index--)
+ {
+ // move all of bits over (bits are read in MSB manner)
+
+ *ptr <<= 1;
+
+ // cycle the clock
+
+ ISP_WRITE(pDevExt->Adapter, NvRam_reg, (NVRAM_SELECT | NVRAM_CLOCK));
+ NovramDelay();
+
+ // see if the incoming bit should be set or not
+
+ word_val = ISP_READ(pDevExt->Adapter, NvRam_reg);
+ if (word_val & NVRAM_DATA_IN)
+ {
+ *ptr |= 1;
+ }
+
+ // remove the clock
+
+ ISP_WRITE(pDevExt->Adapter, NvRam_reg, NVRAM_SELECT);
+ NovramDelay();
+ }
+
+ // Done with this request, clear the selection
+
+ ISP_WRITE(pDevExt->Adapter, NvRam_reg, NVRAM_DESELECT);
+}
+
+
+/************************************************************************/
+/* */
+/* NovramDelay */
+/* */
+/* This routine waits a little bit to let signals settle */
+/* */
+/* Arguments: */
+/* */
+/* None */
+/* */
+/* Return Value: */
+/* */
+/* None */
+/* */
+/************************************************************************/
+
+VOID NovramDelay()
+{
+
+ ScsiPortStallExecution((ULONG)NVRAM_DELAY_COUNT);
+}
diff --git a/private/ntos/miniport/qlogic/qlisp.h b/private/ntos/miniport/qlogic/qlisp.h
new file mode 100644
index 000000000..2dafdd333
--- /dev/null
+++ b/private/ntos/miniport/qlogic/qlisp.h
@@ -0,0 +1,608 @@
+/************************************************************************/
+/* */
+/* Driver Name: QL10WNT.SYS - NT Miniport Driver for QLogic ISP1020 */
+/* */
+/* Source File Name: QLISP.H */
+/* */
+/* Function: Internal data structures and C macros. */
+/* */
+/************************************************************************/
+/* */
+/* NOTICE */
+/* */
+/* COPYRIGHT 1994-1995 QLOGIC CORPORATION */
+/* ALL RIGHTS RESERVED */
+/* */
+/* This computer program is CONFIDENTIAL and a TRADE SECRET */
+/* of QLOGIC CORPORATION. The receipt or possesion of this */
+/* program does not convey any rights to reproduce or disclose */
+/* its contents, or to manufacture, use, or sell anything that */
+/* it may describe, in whole or in part, without the specific */
+/* written consent of QLOGIC CORPORATION. Any reproduction of */
+/* this program without the express written consent of QLOGIC */
+/* CORPORATION is a violation of the copyright laws and may */
+/* subject you to criminal prosecution. */
+/* */
+/************************************************************************/
+/* */
+/* Revision history: */
+/* */
+/* See QLISP.C module for driver revision history */
+/* */
+/************************************************************************/
+
+
+/**********************************************************************/
+/* Local defines and constants */
+/**********************************************************************/
+
+#define MAX_SUPPORTED_ADAPTERS 3 // maximum # of supported adapters
+#define NUM_SCSI_IDS 16
+#define NUM_SCSI_LUNS 8
+#define REQUEST_QUEUE_DEPTH 32
+#define RESPONSE_QUEUE_DEPTH 32
+#define MAX_SG_SEGMENTS 18 // max s/g segments (cmd entry + 2 cont entrys)
+#define MAX_CONT_ENTRYS 2 // max continuation entrys (2 = 18 s/g segments)
+#define WAIT_QUEUE_RETRY_CNT 1000
+#define CMD_RETRY_CNT 3
+#define DEFTIMEOUT 30 // default timeout (seconds)
+
+
+/************************************************************************/
+/* Macros */
+/************************************************************************/
+
+
+/**********************************************************************/
+/* Forward typedefs */
+/**********************************************************************/
+
+
+/************************************************************************/
+/* NOVRAM definitions */
+/************************************************************************/
+
+/* NOVRAM data structure */
+
+typedef struct _NOVRAM
+{
+ UCHAR id[4]; /* "ISP " */
+ UCHAR version;
+ /* bits */
+ UCHAR Fifo_Threshold :2; /* 0,1 */
+ UCHAR Not_Used0 :1; /* 2 */
+ UCHAR Host_Adapter_Enable :1; /* 3 */
+ UCHAR Initiator_SCSI_Id :4; /* 4,5,6,7 */
+
+ UCHAR Bus_Reset_Delay;
+ UCHAR Retry_Count;
+ UCHAR Retry_Delay;
+ /* bits */
+ UCHAR ASync_Data_Setup_Time :4; /* 0,1,2,3 */
+ UCHAR REQ_ACK_Active_Negation :1; /* 4 */
+ UCHAR DATA_Line_Active_Negation :1; /* 5 */
+ UCHAR Data_DMA_Burst_Enable :1; /* 6 */
+ UCHAR Command_DMA_Burst_Enable :1; /* 7 */
+
+ UCHAR Tag_Age_Limit;
+ /* bits */
+ UCHAR Termination_Low_Enable :1; /* 0 */
+ UCHAR Termination_High_Enable :1; /* 1 */
+ UCHAR PCMC_Burst_Enable :1; /* 3 */
+ UCHAR Sixty_MHz_Enable :1; /* 2 */
+ UCHAR Not_Used1 :4;
+
+ USHORT Selection_Timeout;
+ USHORT Max_Queue_Depth;
+ UCHAR Pad0[12];
+
+ struct
+ { /*bit*/
+ UCHAR Renegotiate_on_Error :1; /* 0 */
+ UCHAR Stop_Queue_on_Check :1; /* 1 */
+ UCHAR Auto_Request_Sense :1; /* 2 */
+ UCHAR Tagged_Queuing :1; /* 3 */
+ UCHAR Sync_Data_Transfers :1; /* 4 */
+ UCHAR Wide_Data_Transfers :1; /* 5 */
+ UCHAR Parity_Checking :1; /* 6 */
+ UCHAR Disconnect_Allowed :1; /* 7 */
+
+ UCHAR Execution_Throttle;
+ UCHAR Sync_Period;
+ /* bits */
+ UCHAR Sync_Offset :4; /* 0,1,2,3 */
+ UCHAR Device_Enable :1; /* 4 */
+ UCHAR Not_Used2 :3; /* 5,6,7 */
+
+ UCHAR Available0;
+ UCHAR Available1;
+ } Id[16];
+
+ UCHAR Pad1[3];
+ UCHAR Check_Sum;
+} NOVRAM, *PNOVRAM;
+
+/* Command values */
+
+#define NVRAM_START_BIT 4
+#define NVRAM_WRITE_OP (NVRAM_START_BIT+1)
+#define NVRAM_READ_OP (NVRAM_START_BIT+2)
+#define NVRAM_ERASE_OP (NVRAM_START_BIT+3)
+#define NVRAM_DELAY_COUNT 10
+
+/* NvRam Register bit values */
+
+#define NVRAM_DESELECT 0x00
+#define NVRAM_CLOCK 0x01
+#define NVRAM_SELECT 0x02
+#define NVRAM_DATA_OUT 0x04
+#define NVRAM_DATA_IN 0x08
+
+/* NvRam Parameter Defaults */
+
+#define OFF 0
+#define ON 1
+
+/* Host Adapter defaults */
+
+#define NVRAM_DEF_FIFO_THRESHOLD 2 /* 32 bytes */
+#define NVRAM_DEF_ADAPTER_ENABLE ON
+#define NVRAM_DEF_INITIATOR_SCSI_ID 7
+#define NVRAM_DEF_BUS_RESET_DELAY 3 /* 3 second */
+// Only 1 retry and no delay for NT driver (problem with NT 3.5 Disk Administrator)
+#define NVRAM_DEF_RETRY_COUNT 1
+#define NVRAM_DEF_RETRY_DELAY 0
+#define NVRAM_DEF_ASYNC_SETUP_TIME 6 /* 4 clock periods */
+#define NVRAM_DEF_REQ_ACK_ACTIVE_NEGATION ON
+#define NVRAM_DEF_DATA_ACTIVE_NEGATION ON
+#define NVRAM_DEF_DATA_DMA_BURST_ENABLE ON
+#define NVRAM_DEF_CMD_DMA_BURST_ENABLE ON
+#define NVRAM_DEF_TAG_AGE_LIMIT 8
+#define NVRAM_DEF_SELECTION_TIMEOUT 250 /* 250 ms */
+#define NVRAM_DEF_TERMINATION_LOW_ENABLE ON
+#define NVRAM_DEF_TERMINATION_HIGH_ENABLE ON
+#define NVRAM_DEF_PCMC_BURST_ENABLE OFF
+#define NVRAM_DEF_SIXTY_MHZ_ENABLE OFF
+
+/* Drive defaults */
+
+#define NVRAM_DEF_RENEGOTIATE_ON_ERROR ON
+#define NVRAM_DEF_STOP_QUEUE_ON_CHECK OFF
+#define NVRAM_DEF_AUTO_REQUEST_SENSE ON
+#define NVRAM_DEF_TAGGED_QUEUING ON
+#define NVRAM_DEF_SYNC_DATA_TRANSFERS ON
+#define NVRAM_DEF_WIDE_DATA_TRANSFERS ON
+#define NVRAM_DEF_PARITY_CHECKING ON
+#define NVRAM_DEF_DISCONNECT_ALLOWED ON
+#define NVRAM_DEF_SYNC_PERIOD 25
+#define NVRAM_DEF_SYNC_OFFSET 12
+#define NVRAM_DEF_DEVICE_ENABLE ON
+#define NVRAM_DEF_EXECUTION_THROTTLE 16
+#define NVRAM_DEF_MAX_QUEUE_DEPTH 256
+
+#define NVRAM_CONFIG_BURST_ENABLE 0x04
+
+
+/************************************************************************/
+/* PCI configuration definitions */
+/************************************************************************/
+
+typedef struct _PCI_CHIP_REGISTERS_M1 // Method 1
+{
+ ULONG Config_Address;
+ ULONG Config_Data;
+} PCI_CHIP_REGISTERS_M1, *PPCI_CHIP_REGISTERS_M1;
+
+#define PCI_MAXBUSNUM 256
+#define PCI_MAXDEVNUM 32
+#define PCI_CONFIG_ADDRESS 0xcf8
+#define PCI_CONFIG_DATA 0xcfc
+#define PCI_ENABLE_CONFIG 0x80000000
+#define PCI_DISABLE_CONFIG 0x00000000
+
+typedef struct _PCI_CHIP_REGISTERS // Method 2
+{
+ UCHAR pci_config;
+} PCI_CHIP_REGISTERS, *PPCI_CHIP_REGISTERS;
+
+#define PCI_CONFIG 0xcf8
+#define PCI_ENABLE 0x80
+#define PCI_START 0xC000
+#define PCI_SLOT_CNT 16
+#define PCI_LAST 0xDFFF
+#define PCI_SIZE 0x100
+
+#define PCI_BEGIN_SEARCH (paddr_t)0xe0000
+#define PCI_END_SEARCH (paddr_t)0xfffff
+
+#define PCI_BIOS_VECT 0x6EFE00F0
+#define PCI_BIOS_INT 0x1A
+
+#define PCI_FUNCTION_ID 0xB100
+
+/* PCI Function List */
+
+#define PCI_BIOS_PRESENT 0xB101
+#define FIND_PCI_DEVICE 0xB102
+#define FIND_PCI_CLASS_CODE 0xB103
+#define GENERATE_SPECIAL_CYCLE 0xB106
+#define READ_CONFIG_BYTE 0xB108
+#define READ_CONFIG_WORD 0xB109
+#define READ_CONFIG_DWORD 0xB10A
+#define WRITE_CONFIG_BYTE 0xB10B
+#define WRITE_CONFIG_WORD 0xB10C
+#define WRITE_CONFIG_DWORD 0xB10D
+
+/* PCI Return Code List */
+
+#define SUCCESSFUL 0x00
+#define FUNC_NOT_SUPPORTED 0x81
+#define BAD_VENDOR_ID 0x83
+#define DEVICE_NOT_FOUND 0x86
+#define BAD_REGISTER_NUMBER 0x87
+
+/* Configuration space register definitions */
+
+typedef struct _PCI_REGS
+{
+ USHORT Vendor_Id;
+#define QLogic_VENDOR_ID 0x1077
+ USHORT Device_Id;
+#define QLogic_DEVICE_ID 0x1020
+ USHORT Command;
+#define BUS_MASTER_ENABLE 0x0004
+ USHORT Status;
+ ULONG Rev_Id_Class_Code;
+ UCHAR Cache_Line_Size;
+ UCHAR Latency_Timer;
+ UCHAR Header_Type;
+ UCHAR BIST;
+ ULONG IO_Base_Address;
+ ULONG Memory_Base_Address;
+ ULONG Base_Address_3;
+ ULONG Base_Address_4;
+ ULONG Base_Address_5;
+ ULONG Base_Address_6;
+ ULONG Reserved_1;
+ ULONG Reserved_2;
+ ULONG ROM_Base_Address;
+ ULONG Reserved_3;
+ ULONG Reserved_4;
+ UCHAR Interrupt_Line;
+ UCHAR Interrupt_Pin;
+ UCHAR Minimum_Grant;
+ UCHAR Maximum_Latency;
+ UCHAR unused[192];
+} PCI_REGS, *PPCI_REGS;
+
+
+/****************************************************************/
+/* ISP firmware interface definitions */
+/****************************************************************/
+
+/*** Queue Entry structure ***/
+
+typedef struct _QueueEntry
+{
+ UCHAR data[64];
+} QUEUE_ENTRY, *PQUEUE_ENTRY;
+
+
+/*** ENTRY HEADER structure ***/
+
+typedef struct
+{
+ UCHAR entry_type;
+ UCHAR entry_cnt;
+ UCHAR sys_def_1;
+ UCHAR flags;
+} ENTRY_HEADER;
+
+/* Entry Header Type Definitions */
+
+#define ET_COMMAND 1
+#define ET_CONTINUATION 2
+#define ET_STATUS 3
+#define ET_MARKER 4
+#define ET_EXTENDED_COMMAND 5
+
+/* Entry Header Flag Definitions */
+
+#define EF_CONTINUATION 0x01
+#define EF_BUSY 0x02
+#define EF_BAD_HEADER 0x04
+#define EF_BAD_PAYLOAD 0x08
+#define EF_ERROR_MASK (EF_BUSY | EF_BAD_HEADER | EF_BAD_PAYLOAD)
+
+
+/*** DATA SEGMENT structure ***/
+
+typedef struct
+{
+ ULONG base;
+ ULONG count;
+} DATA_SEG;
+
+
+/*** COMMAND ENTRY structure ***/
+
+typedef struct _CommandEntry
+{
+ ENTRY_HEADER hdr;
+ ULONG handle;
+ UCHAR target_lun;
+ UCHAR target_id;
+ USHORT cdb_length;
+ USHORT control_flags;
+ USHORT reserved;
+ USHORT time_out;
+ USHORT segment_cnt;
+ UCHAR cdb[12];
+ DATA_SEG dseg[4];
+} COMMAND_ENTRY, *PCOMMAND_ENTRY;
+
+/* Command Entry Control Flag Definitions */
+
+#define CF_NO_DISCONNECTS 0x0001
+#define CF_HEAD_TAG 0x0002
+#define CF_ORDERED_TAG 0x0004
+#define CF_SIMPLE_TAG 0x0008
+#define CF_TARGET_ROUTINE 0x0010
+#define CF_READ 0x0020
+#define CF_WRITE 0x0040
+#define CF_NO_REQUEST_SENSE 0x0100
+
+
+/*** EXTENDED COMMAND ENTRY structure ***/
+
+typedef struct _ExtCommandEntry
+{
+ ENTRY_HEADER hdr;
+ ULONG handle;
+ UCHAR target_lun;
+ UCHAR target_id;
+ USHORT cdb_length;
+ USHORT control_flags;
+ USHORT reserved;
+ USHORT time_out;
+ USHORT segment_cnt;
+ UCHAR cdb[44];
+} EXT_COMMAND_ENTRY, *PEXT_COMMAND_ENTRY;
+
+
+/*** CONTINUATION ENTRY structure ***/
+
+typedef struct _ContinuationEntry
+{
+ ENTRY_HEADER hdr;
+ ULONG reserved;
+ DATA_SEG dseg[7];
+} CONTINUATION_ENTRY, *PCONTINUATION_ENTRY;
+
+
+/*** MARKER ENTRY structure ***/
+
+typedef struct _MarkerEntry
+{
+ ENTRY_HEADER hdr;
+ ULONG reserved0;
+ UCHAR target_lun;
+ UCHAR target_id;
+ UCHAR modifier;
+ UCHAR reserved1;
+ UCHAR reserved2[52];
+} MARKER_ENTRY, *PMARKER_ENTRY;
+
+/* Marker Entry Modifier Definitions */
+
+#define MM_SYNC_DEVICE 0
+#define MM_SYNC_TARGET 1
+#define MM_SYNC_ALL 2
+
+
+/*** STATUS ENTRY structure ***/
+
+typedef struct _StatusEntry
+{
+ ENTRY_HEADER hdr;
+ ULONG handle;
+ USHORT scsi_status;
+ USHORT completion_status;
+ USHORT state_flags;
+ USHORT status_flags;
+ USHORT time;
+ USHORT req_sense_length;
+ ULONG residual;
+ UCHAR reserved[8];
+ UCHAR req_sense_data[32];
+} STATUS_ENTRY, *PSTATUS_ENTRY;
+
+/* Status Entry Completion Status Defintions */
+
+#define SCS_COMPLETE 0
+#define SCS_INCOMPLETE 1
+#define SCS_DMA_ERROR 2
+#define SCS_TRANSPORT_ERROR 3
+#define SCS_RESET_OCCURRED 4
+#define SCS_ABORTED 5
+#define SCS_TIMEOUT 6
+#define SCS_DATA_OVERRUN 7
+#define SCS_COMMAND_OVERRUN 8
+#define SCS_STATUS_OVERRUN 9
+#define SCS_BAD_MESSAGE 10
+#define SCS_NO_MESSAGE_OUT 11
+#define SCS_EXT_ID_FAILED 12
+#define SCS_IDE_MSG_FAILED 13
+#define SCS_ABORT_MSG_FAILED 14
+#define SCS_REJECT_MSG_FAILED 15
+#define SCS_NOP_MSG_FAILED 16
+#define SCS_PARITY_ERROR_MSG_FAILED 17
+#define SCS_DEVICE_RESET_MSG_FAILED 18
+#define SCS_ID_MSG_FAILED 19
+#define SCS_UNEXPECTED_BUS_FREE 20
+
+/* Status Entry State Flag Definitions */
+
+#define SS_GOT_BUS 0x0100
+#define SS_GOT_TARGET 0x0200
+#define SS_SENT_CDB 0x0400
+#define SS_TRANSFERRED_DATA 0x0800
+#define SS_GOT_STATUS 0x1000
+#define SS_GOT_SENSE 0x2000
+#define SS_TRANSFER_COMPLETE 0x4000
+
+/* Status Entry Status Flag Definitions */
+
+#define SST_DISCONNECT 0x0001
+#define SST_SYNCHRONOUS 0x0002
+#define SST_PARITY_ERROR 0x0004
+#define SST_BUS_RESET 0x0008
+#define SST_DEVICE_RESET 0x0010
+#define SST_ABORTED 0x0020
+#define SST_TIMEOUT 0x0040
+#define SST_NEGOTIATION 0x0080
+
+
+/* Mailbox Command Definitions */
+
+#define MBOX_CMD_LOAD_RAM 0x0001
+#define MBOX_CMD_EXECUTE_FIRMWARE 0x0002
+#define MBOX_CMD_WRITE_RAM_WORD 0x0004
+#define MBOX_CMD_READ_RAM_WORD 0x0005
+#define MBOX_CMD_MAILBOX_REGISTER_TEST 0x0006
+#define MBOX_CMD_VERIFY_CHECKSUM 0x0007
+#define MBOX_CMD_ABOUT_FIRMWARE 0x0008
+#define MBOX_CMD_INIT_REQUEST_QUEUE 0x0010
+#define MBOX_CMD_INIT_RESPONSE_QUEUE 0x0011
+#define MBOX_CMD_STOP_FIRMWARE 0x0014
+#define MBOX_CMD_ABORT 0x0015
+#define MBOX_CMD_ABORT_DEVICE 0x0016
+#define MBOX_CMD_ABORT_TARGET 0x0017
+#define MBOX_CMD_BUS_RESET 0x0018
+#define MBOX_CMD_START_QUEUE 0x001A
+
+#define MBOX_CMD_SET_INITIATOR_SCSI_ID 0x0030
+#define MBOX_CMD_SET_SELECTION_TIMEOUT 0x0031
+#define MBOX_CMD_SET_RETRY_COUNT 0x0032
+#define MBOX_CMD_SET_TAG_AGE_LIMIT 0x0033
+#define MBOX_CMD_SET_CLOCK_RATE 0x0034
+#define MBOX_CMD_SET_ACTIVE_NEGATION_STATE 0x0035
+#define MBOX_CMD_SET_ASYNC_DATA_SETUP_TIME 0x0036
+#define MBOX_CMD_SET_BUS_CONTROL_PARAMETERS 0x0037
+#define MBOX_CMD_SET_TARGET_PARAMETERS 0x0038
+#define MBOX_CMD_SET_DEVICE_QUEUE_PARAMETERS 0x0039
+
+#define MBOX_CMD_GET_FIRMWARE_STATUS 0x001F
+#define MBOX_CMD_GET_INITIATOR_SCSI_ID 0x0020
+#define MBOX_CMD_GET_SELECTION_TIMEOUT 0x0021
+#define MBOX_CMD_GET_RETRY_COUNT 0x0022
+#define MBOX_CMD_GET_TAG_AGE_LIMIT 0x0023
+#define MBOX_CMD_GET_CLOCK_RATE 0x0024
+#define MBOX_CMD_GET_ACTIVE_NEGATION_STATE 0x0025
+#define MBOX_CMD_GET_ASYNC_DATA_SETUP_TIME 0x0026
+#define MBOX_CMD_GET_BUS_CONTROL_PARAMETERS 0x0027
+#define MBOX_CMD_GET_TARGET_PARAMETERS 0x0028
+#define MBOX_CMD_GET_DEVICE_QUEUE_PARAMETERS 0x0029
+
+/* Mailbox Status Definitions */
+
+#define MBOX_STS_FIRMWARE_ALIVE 0x0000
+#define MBOX_STS_CHECKSUM_ERROR 0x0001
+#define MBOX_STS_SHADOW_LOAD_ERROR 0x0002
+#define MBOX_STS_BUSY 0x0004
+
+#define MBOX_STS_COMMAND_COMPLETE 0x4000
+#define MBOX_STS_INVALID_COMMAND 0x4001
+#define MBOX_STS_HOST_INTERFACE_ERROR 0x4002
+#define MBOX_STS_TEST_FAILED 0x4003
+#define MBOX_STS_COMMAND_ERROR 0x4005
+#define MBOX_STS_COMMAND_PARAMETER_ERROR 0x4006
+
+#define MBOX_ASTS_SCSI_BUS_RESET 0x8001
+#define MBOX_ASTS_SYSTEM_ERROR 0x8002
+#define MBOX_ASTS_REQUEST_TRANSFER_ERROR 0x8003
+#define MBOX_ASTS_RESPONSE_TRANSFER_ERROR 0x8004
+#define MBOX_ASTS_REQUEST_QUEUE_WAKEUP 0x8005
+#define MBOX_ASTS_TIMEOUT_RESET 0x8006
+
+
+/****************************************************************/
+/* ISP Register Definitions */
+/****************************************************************/
+
+typedef struct _ISP_REGS
+{
+ /* Bus interface registers */
+
+ USHORT bus_id_low; /* 0000 */
+ USHORT bus_id_high; /* 0002 */
+ USHORT bus_config0; /* 0004 */
+ USHORT bus_config1; /* 0006 */
+ USHORT bus_icr; /* 0008 */
+ USHORT bus_isr; /* 000A */
+ USHORT bus_sema; /* 000C */
+ USHORT NvRam_reg; /* 000E */
+
+ /* Skip over DMA Controller registers */
+
+ UCHAR not_used0[0x0060]; /* 0010-006F */
+
+ /* Mailbox registers */
+
+ USHORT mailbox0; /* 0070 */
+ USHORT mailbox1; /* 0072 */
+ USHORT mailbox2; /* 0074 */
+ USHORT mailbox3; /* 0076 */
+ USHORT mailbox4; /* 0078 */
+ USHORT mailbox5; /* 007A */
+
+ /* Skip down to HCCR register */
+
+ UCHAR not_used1[0x44]; /* 007C-00BF */
+
+ /* Host Configuration and Control register */
+
+ USHORT hccr; /* 00C0 */
+
+ UCHAR not_used3[0x3E]; /* 00C2-00FF */
+} ISP_REGS, *PISP_REGS;
+
+/* Bus Control Register Definitions */
+
+#define ICR_SOFT_RESET 0x0001
+#define ICR_ENABLE_ALL_INTS 0x0002
+#define ICR_ENABLE_RISC_INT 0x0004
+#define ICR_DISABLE_ALL_INTS 0x0000
+
+/* Bus Interrupt Status Register Defintions */
+
+#define BUS_ISR_RISC_INT 0x0004
+
+/* Bus Semaphore Register Definitions */
+
+#define BUS_SEMA_LOCK 0x0001
+#define BUS_SEMA_STATUS 0x0002
+
+/* Host Command and Control Register Command Definitions */
+
+#define HCCR_CMD_RESET 0x1000 /* Reset RISC */
+#define HCCR_CMD_PAUSE 0x2000 /* Pause RISC */
+#define HCCR_CMD_RELEASE 0x3000 /* Release Paused RISC */
+#define HCCR_CMD_SET_HOST_INT 0x5000 /* Set Host Interrupt */
+#define HCCR_CMD_CLEAR_RISC_INT 0x7000 /* Clear RISC interrupt */
+#define HCCR_WRITE_BIOS_ENABLE 0x9000 /* Write BIOS enable */
+
+/* Host Command and Control Register Status Definitions */
+
+#define HCCR_HOST_INT 0x0080 /* R: Host interrupt set */
+#define HCCR_RESET 0x0040 /* R: RISC reset in progress */
+#define HCCR_PAUSE 0x0020 /* R: RISC paused */
+
+/* ISP Product ID Definitions */
+
+#define PROD_ID_1 0x4953
+#define PROD_ID_2 0x0000
+#define PROD_ID_2a 0x5020
+#define PROD_ID_3 0x2020
+#define PROD_ID_4 0x0001
+
diff --git a/private/ntos/miniport/qlogic/qlisp.rc b/private/ntos/miniport/qlogic/qlisp.rc
new file mode 100644
index 000000000..0b3dc97e0
--- /dev/null
+++ b/private/ntos/miniport/qlogic/qlisp.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "QLogic ISP1020 SCSI Driver"
+#define VER_INTERNALNAME_STR "ql10wnt.sys"
+#define VER_ORIGINALFILENAME_STR "ql10wnt.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/qlogic/sources b/private/ntos/miniport/qlogic/sources
new file mode 100644
index 000000000..2589a5a48
--- /dev/null
+++ b/private/ntos/miniport/qlogic/sources
@@ -0,0 +1,41 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=ql10wnt
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+!IF $(ALPHA)
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib $(BASEDIR)\public\sdk\lib\*\libcntpr.lib
+!ENDIF
+
+SOURCES=qlisp.c \
+ isp_fw.c \
+ qlisp.rc
diff --git a/private/ntos/miniport/qlogic/txtsetup.oem b/private/ntos/miniport/qlogic/txtsetup.oem
new file mode 100644
index 000000000..d8a7e7f5d
--- /dev/null
+++ b/private/ntos/miniport/qlogic/txtsetup.oem
@@ -0,0 +1,97 @@
+#
+# format for txtsetup.oem.
+#
+# General format:
+#
+# [section]
+# key = value1,value2,...
+#
+#
+# The hash ('#') introduces a comment.
+# Strings with embedded spaces, commas, or hashes should be double-quoted
+#
+
+
+[Disks]
+
+# This section lists all disks in the disk set.
+#
+# <description> is a descriptive name for a disk, used when
+# prompting for the disk
+# <tagfile> is a file whose presence allows setup to recognize
+# that the disk is inserted.
+# <directory> is where the files are located on the disk.
+#
+
+d1 = "QLogic SCSI Software Diskette", \qlscsi, \nt\
+
+
+[Defaults]
+
+# This section lists the default selection for each 'required'
+# hardware component. If a line is not present for a component,
+# the default defaults to the first item in the [<component_name>]
+# section (see below).
+#
+# <component_name> is one of computer, display, keyboard, mouse, scsi
+# <id> is a unique <within the component> string to be associated
+# with an option.
+
+scsi = OEMSCSI
+
+
+
+[scsi]
+
+# This section lists the options available for a particular component.
+#
+# <id> is the unique string for the option
+# <description> is a text string, presented to the user in a menu
+# <key_name> gives the name of the key to be created for the component in
+# HKEY_LOCAL_MACHINE\ControlSet001\Services
+
+
+OEMSCSI = "QLogic Fast!SCSI/QLA100 (Windows NT V3.1)", ql10wnt
+OEMSCSI2 = "QLogic Fast!SCSI/QLA100 (Windows NT V3.5)", ql10nt35
+
+
+
+[Files.scsi.OEMSCSI]
+
+# This section lists the files that should be copied if the user
+# selects a particular component option.
+#
+# <file_type> is one of driver, port, class, dll, hal, inf, or detect.
+# See below.
+# <source_disk> identifies where the file is to be copied from, and must
+# match en entry in the [Disks] section.
+# <filename> is the name of the file. This will be appended to the
+# directory specified for the disk in the [Disks] section to form the
+# full path of the file on the disk.
+
+driver = d1, ql10wnt.sys, ql10wnt
+inf = d1, oemsetup.inf
+
+[Files.scsi.OEMSCSI2]
+
+driver = d1, ql10nt35.sys, ql10nt35
+inf = d1, oemsetup.inf
+
+
+
+[Config.scsi.OEMSCSI]
+
+# This section specifies values to be set in the registry for
+# particular component options. Required values in the services\xxx
+# key are created automatically -- use this section to specify additional
+# keys to be created in services\xxx and values in services\xxx and
+# services\xxx\yyy.
+#
+# <key_name> is relative to the services node for this device.
+# If it is empty, then it refers to the services node.
+# If specified, the key is created first.
+# <value_name> specifies the value to be set within the key
+# <value_type> is a string like REG_DWORD. See below.
+# <value> specifies the actual value; its format depends on <value_type>
+
+[Config.scsi.OEMSCSI2]
diff --git a/private/ntos/miniport/scsiwdl/dirs b/private/ntos/miniport/scsiwdl/dirs
new file mode 100644
index 000000000..9bc88d1b4
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/dirs
@@ -0,0 +1,25 @@
+!IF 0
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=ami4448 \
+ ncrcam
+
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/cam.h b/private/ntos/miniport/scsiwdl/ncrcam/cam.h
new file mode 100644
index 000000000..a5ffbe470
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/cam.h
@@ -0,0 +1,309 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 1992 NCR Corporation
+//
+// CAM.H
+//
+// Revisions:
+//
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef CAM_H
+#define CAM_H
+
+#pragma pack(1) /* pack structures, cannot do it with compiler option
+ Zp because structures shared with the NT MiniPort
+ driver and NT upper layer drivers will be messed up.
+ We must pack only the structures shared with the
+ CAMcore. */
+
+typedef struct
+{
+/* 0 */ ushort CCBLength; /* filled by device driver */
+/* 2 */ uchar FunctionCode; /* filled by device driver */
+/* 3 */ uchar CAMStatus; /* filled by CAM */
+/* 4 */ uchar SCSIStatus; /* filled by CAM */
+/* 5 */ uchar PathID; /* filled by device driver */
+/* 6 */ ulong CAMFlags; /* filled by device driver */
+/* A */
+} CAMHeader; /* 10 bytes */
+
+/* CAM function code definitions */
+#define FUNC_ABORT_SCSI_COMMAND 0x01
+#define FUNC_EXECUTE_SCSI_IO 0x02
+#define FUNC_GET_DEVICE_TYPE 0x03
+#define FUNC_PATH_INQUIRY 0x05
+#define FUNC_RELEASE_SIM_QUEUE 0x06
+#define FUNC_RESET_SCSI_BUS 0x07
+#define FUNC_RESET_SCSI_DEVICE 0x08
+#define FUNC_SET_ASYNC_CALLBACK 0x09
+#define FUNC_SET_DEVICE_TYPE 0x0A
+#define FUNC_SET_HBA_PARAMETERS 0x0B
+#define FUNC_CHANGE_OS2_NAME 0x20
+#define FUNC_ROM_DEBUGS 0x21
+#define FUNC_CHS_MAP 0x22
+#define FUNC_INIT_PATH 0x23
+#define FUNC_POLL_PATH 0x24
+#define FUNC_CHAIN 0x25
+
+/* CAM status values */
+#define STAT_REQUEST_IN_PROGRESS 0x00
+#define STAT_REQUEST_DONE_NO_ERROR 0x01
+#define STAT_ABORTED_BY_HOST 0x02
+#define STAT_UNABLE_TO_ABORT 0x03
+#define STAT_COMPLETE_WITH_ERROR 0x04
+#define STAT_CAM_BUSY 0x05
+#define STAT_INVALID_REQUEST 0x06
+#define STAT_INVALID_PATH_ID 0x07
+#define STAT_SCSI_DEVICE_NOT_INSTALLED 0x08
+#define STAT_WAIT_FOR_TIMEOUT 0x09
+#define STAT_SELECTION_TIMEOUT 0x0A
+#define STAT_COMMAND_TIMEOUT 0x0B
+#define STAT_SCSI_BUS_BUSY 0x0C
+#define STAT_MESSAGE_REJECT_RECIEVED 0x0D
+#define STAT_SCSI_BUS_RESET 0x0E
+#define STAT_UNCORRECTED_PARITY_ERROR 0x0F
+#define STAT_REQUEST_SENSE_FAILED 0x10
+#define STAT_NO_HBA_DETECTED_ERROR 0x11
+#define STAT_DATA_OVERRUN_OR_UNDERRUN 0x12
+#define STAT_UNEXPECTED_BUS_FREE 0x13
+#define STAT_PHASE_SEQUENCE_FAILURE 0x14
+#define STAT_CCB_LENGTH_INADEQUATE 0x15
+#define STAT_CANNOT_PROVIDE_CAPABILITY 0x16
+#define STAT_INVALID_LUN 0x20
+#define STAT_INVALID_TARGET_ID 0x21
+#define STAT_FUNCTION_NOT_IMPLEMENTED 0x22
+#define STAT_NEXUS_NOT_ESTABLISHED 0x23
+#define STAT_INVALID_INTIATOR_ID 0x24
+#define STAT_INVALID_DATA_BUFFER 0x25
+#define STAT_NO_CAM_PRESENT 0x26
+#define STAT_GENERAL_FAILURE 0x27
+
+/* CAM status flags */
+#define SIM_QUEUE_FROZEN 0x40
+#define AUTOSENSE_DATA_VALID 0x80
+
+/* SCSI Status Values */
+#define SCSI_STAT_CHECK_COND 0x02
+
+typedef struct
+{
+ CAMHeader Header;
+ long CCBPtr; /* filled by device driver */
+} AbortXPTRequestCCB, *PAbortXPTRequestCCB;
+
+
+typedef struct
+{
+ CAMHeader Header;
+ uchar TargetID; /* filled by device driver */
+ uchar LUN; /* filled by device driver */
+ uchar PeripheralDeviceType; /* filled by CAM */
+ ulong InquiryDatPtr; /* filled by CAM */
+} GetDeviceTypeCCB, *PGetDeviceTypeCCB;
+
+
+typedef struct
+{
+ CAMHeader Header;
+ uchar TargetID; /* filled by device driver */
+ uchar LUN; /* filled by device driver */
+ uchar PeripheralDeviceType; /* filled by device driver */
+} SetDeviceTypeCCB, *PSetDeviceTypeCCB;
+
+
+typedef struct
+{
+ CAMHeader Header;
+} ChangeOS2NameCCB, ResetSCSIBusCCB, *PResetSCSIBusCCB;
+
+
+typedef struct
+{
+ CAMHeader Header;
+ uchar TargetID; /* filled by device driver */
+ uchar HostStatus; /* filled by CAM */
+ uchar TargetStaus; /* filled by CAM */
+} ResetSCSIDeviceCCB, *PResetSCSIDeviceCCB;
+
+
+typedef struct
+{
+ CAMHeader Header;
+ uchar TargetID; /* filled by device driver */
+ uchar LUN; /* filled by device driver */
+} ReleaseSIMQueueCCB, *PReleaseSIMQueueCCB;
+
+
+typedef struct
+{
+ CAMHeader Header;
+ ulong FeatureList; /* filled by CAM */
+ uchar HighestPathID; /* filled by CAM */
+ uchar InitiatorID; /* filled by CAM */
+ uchar SIMVendorName[16]; /* filled by CAM */
+ uchar HBAVendorName[16]; /* filled by CAM */
+ uchar VendorUnique[16]; /* filled by CAM */
+ ulong PrivateDataSize; /* filled by CAM */
+ ulong OSD; /* filled by both */
+} PathInquiryCCB, *PPathInquiryCCB;
+
+
+/* feature list flags */
+#define RELATIVE_ADDRESSING_SUPPORTED 0x80
+#define SCSI_BUS_SUPPORTED_32_BIT 0x40
+#define SCSI_BUS_SUPPORTED_16_BIT 0x20
+#define SYNCHRONOUS_TRANSFER_SUPPORTED 0x10
+#define LINKED_COMMANDS_SUPPORTED 0x08
+#define COMMAND_QUEUING_SUPPORTED 0x02
+#define SOFT_RESET_SUPPORTED 0x01
+
+
+typedef struct
+{
+ CAMHeader Header;
+ ulong FeatureList; /* filled by CAM */
+} SetHBAParametersCCB, *PSetHBAParametersCCB;
+
+
+typedef struct
+{
+ CAMHeader Header;
+ uchar TargetID; /* filled by device driver */
+ uchar LUN; /* filled by device driver */
+ uchar AENFlags; /* filled by device driver */
+ ulong CallBackPtr; /* filled by device driver */
+} SetAsyncCallbackCCB, *PSetAsyncCallbackCCB;
+
+
+/* AEN flags */
+#define SCSI_ASYNCRONOUS_EVENT_NOTIFY 0x08
+#define RECOVERED_FROM_PARITY_ERROR 0x04
+#define UNSOLICITED_RESELECTION 0x02
+#define UNSOLICITED_SCSI_BUS_RESET 0x01
+
+typedef struct SCSIRequestCCB
+{
+/* 0 */ CAMHeader Header;
+/* A */ uchar TargetID; /* filled by device driver */
+/* B */ uchar LUN; /* filled by device driver */
+/* C */ uchar Queue_Action; /* filled by device driver */
+/* D */ ushort VendorFlags; /* filled by both */
+/* F */ ushort CDBLength; /* filled by device driver */
+/* 11 */ ushort SenseLength; /* filled by device driver */
+/* 13 */ ushort MessageLength; /* filled by device driver */
+/* 15 */ ushort SGListLength; /* filled by device driver */
+/* 17 */ ulong DataLength; /* filled by both */
+/* 1B */ ulong TimeOut; /* filled by device driver */
+/* 1F */ ulong DataPtr; /* filled by device driver */
+/* 23 */ ulong SensePtr; /* filled by device driver */
+/* 27 */ ulong MessagePtr; /* filled by device driver */
+/* 2B */ ulong LinkPtr; /* filled by device driver */
+/* 2F */ ulong PeripheralPtr; /* filled by device driver */
+/* 33 */ ulong CallBackPtr[3]; /* filled by device driver */
+/* 3F */ uchar CDB[16]; /* filled by device driver */
+#ifndef FROMCAM
+/* 4F */ char filler1[113];
+/* C0 */
+#endif
+} SCSIRequestCCB, *PSCSIRequestCCB; /* 192 bytes */
+
+
+/* scatter/gather list types */
+typedef struct
+{
+ ulong DataPtr; /* filled by device driver */
+ ulong DataLength; /* filled by device driver */
+} SGListEntry, *PSGListEntry;
+
+typedef SGListEntry * SGList;
+
+/* CAM flags */
+#define CAM_DATA_DIRECTION 0xC0000000 /* BITS 30 & 31 */
+#define CAM_DISABLE_AUTOSENSE 0x20000000 /* BIT 29 */
+#define CAM_DATAPTR_IS_SG_LIST_PTR 0x10000000 /* BIT 28 */
+#define CAM_DO_NOT_CALLBACK 0x08000000 /* BIT 27 */
+#define CAM_LINKED_COMMAND 0x04000000 /* BIT 26 */
+#define CAM_QUEUE_ACTION_SPECIFIED 0x02000000 /* BIT 25 */
+#define CAM_CDB_FIELD_IS_CDB_PTR 0x01000000 /* BIT 24 */
+#define CAM_DO_NOT_ALLOW_DISCONNECT 0x00800000 /* BIT 23 */
+#define CAM_INIT_SYNC_TRANSFERS 0x00400000 /* BIT 22 */
+#define CAM_DISABLE_SYNC_TRAN 0x00200000 /* BIT 21 */
+#define CAM_CDBPTR_IS_PHYS_ADDR 0x00004000 /* BIT 14 */
+#define CAM_DATAPTR_IS_PHYS_ADDR 0x00002000 /* BIT 13 */
+#define CAM_SENSEPTR_IS_PHYS_ADDR 0x00001000 /* BIT 12 */
+#define CAM_MSGPTR_IS_PHYS_ADDR 0x00000800 /* BIT 11 */
+#define CAM_LINKPTR_IS_PHYS_ADDR 0x00000400 /* BIT 10 */
+#define CAM_CALLBACKPTR_IS_PHYS_ADDR 0x00000200 /* BIT 9 */
+#define CAM_DATA_BUFFER_VALID 0x00000080 /* BIT 7 */
+#define CAM_STATUS_VALID 0x00000040 /* BIT 6 */
+#define CAM_MESSAGE_BUFFER_VALID 0x00000020 /* BIT 5 */
+#define CAM_RESERVED_BITS 0X001F811F /* BITS 1-4,8,14-20 */
+
+#define CAM_DATA_DIRECTION_CLEAR 0x3FFFFFFF /* BITS 30 & 31 */
+
+#define CAM_DIR_DATA_IN 0x40000000
+#define CAM_DIR_DATA_OUT 0x80000000
+#define CAM_DIR_NO_DATA 0xC0000000
+
+#define DATA_IN 1
+#define DATA_OUT 2
+#define NO_DATA 3
+
+/* Vendor Unique Flags */
+/* first 8 bits are for user's use */
+
+/* the next 8 bits are defined by NCR */
+#define BSCVU_POLLED (0x0100)
+#define BSCVU_PIO_DATA (0x0400)
+#define BSCVU_SYNC_TRAN (0x1000)
+#define BSCVU_ROM_REQ (0x8000)
+
+
+
+typedef struct
+{
+ CAMHeader Header;
+ ushort Dbgflag;
+ ulong Dbgwait;
+ ushort Topscrnpos;
+ ushort Botscrnpos;
+} SetROMDebugCCB, *PSetROMDebugCCB;
+
+typedef struct
+{
+ ulong cyls;
+ ulong heads;
+ ulong sects;
+} CHSData, *PCHSData;
+
+/* SCSI status defines */
+#define STATUS_GOOD 0x00
+#define STATUS_CHECK_CONDITION 0x02
+#define STATUS_BUSY 0X08
+#define STATUS_RES_CONFLICT 0x18
+
+/* sense keys and their meanings */
+#define SENSE_NO_SENSE 0X00
+#define SENSE_RECOVERED_ERROR 0X01
+#define SENSE_NOT_READY 0X02
+#define SENSE_MEDIUM_ERROR 0X03
+#define SENSE_HARDWARE_ERROR 0X04
+#define SENSE_ILLEGAL_REQUEST 0X05
+#define SENSE_UNIT_ATTENTION 0X06
+#define SENSE_DATA_PROTECT 0X07
+#define SENSE_BLANK_CHECK 0X08
+#define SENSE_VENDOR_UNIQUE 0X09
+#define SENSE_COPY_ABORTED 0X0A
+#define SENSE_ABORTED_COMMAND 0X0B
+#define SENSE_EQUAL 0X0C
+#define SENSE_VOLUME_OVERFLOW 0X0D
+#define SENSE_MISCOMPARE 0X0E
+
+#define SEL_TIMEOUT_MS 250
+
+#pragma pack()
+
+#endif
+
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/camcore.h b/private/ntos/miniport/scsiwdl/ncrcam/camcore.h
new file mode 100644
index 000000000..c11a01659
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/camcore.h
@@ -0,0 +1,140 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 1992 NCR Corporation
+//
+// CAMCORE.H
+//
+// Revisions:
+//
+// 5/19/92 added SCSIClockSpeed
+// added ChipSpec1 through ChipSpec9
+//
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef CAMCORE_H
+
+/*
+ Defines first 274 bytes of ROM code.
+ The ROM CAMCORE Header FIELDS are primarily for internal use
+ of the Core. However, certain drivers might need to use the
+ information contained in the header. The main interface
+ between the drivers and the cores should be the GLOBALS
+ structure. This will allow the CAMCORE Header to change
+ without affecting the drivers. In particular, everything
+ following the config_flags, needs to be private within
+ the cores. CAMInit() will make sure that all the appropriate
+ information will get put into the GLOBALS.
+*/
+
+#define CAMCORE_H
+
+////////////////////////////////////////////////////////////////////////////
+// Following line added for Windows NT
+// Must pack the following structures because the CAMcore has
+// been compiled with the structures packed (default Borland
+// option).
+////////////////////////////////////////////////////////////////////////////
+
+#pragma pack(1)
+
+
+typedef struct {
+/* 0*/ ushort ROMMark; /* 0xAA55 */
+/* 2*/ uchar ROMlen; /* in multiples of 512 bytes */
+/* 3*/ uchar POSTEntryPt[3]; /* jmp _init */
+/* 6*/ ushort ABIOSMark; /* 0xBB66 */
+/* 8*/ uchar InitTableCnt; /* how many init table entries this ROM uses */
+/* 9*/ uchar ABIOSEntryPt[3]; /* jmp _abios_init */
+/* C*/ ushort MachineType; /* "AT", "MC", "EI" */
+/* E*/ ushort iobaseport;
+/*10*/ uchar dmachannel;
+/*11*/ uchar irqnum;
+/*12*/ uchar hascsiid;
+/*13*/ uchar DMA_IO_Port;/*offset from iobaseport where DMA gets/puts data*/
+/*14*/ ushort ConfigurationWord;
+/* NOTE: the next five bits must not change places or order, CUSTOM.EXE uses */
+/* must be negative logic (MAKEROM.EXE also uses these bits */
+#define CORHDR_DISABLE_SYNC (0X0001)
+#define CORHDR_DISABLE_DISCONNECT (0X0002)
+#define CORHDR_DISABLE_IRQUSE (0X0004)
+#define CORHDR_DO_NOT_RESET_SCSI_BUS (0X0008)
+#define CORHDR_SINGLE_DMA (0X0010)
+#define CONFIG_MASK 0x1f
+/*********************** see NOTE above ***************************/
+#define CORHDR_DMA_BUSMASTER (0X0100)
+#define CORHDR_NEEDS_CCBPHYS (0X0200)
+#define CORHDR_GET_ROM_COPY_MEMORY (0X0400)
+#define CORHDR_ROM_COPY_AT_POST (0X0800)
+#define CORHDR_16BIT_DMA (0X1000)
+#define CORHDR_DMA_IOADDR (0X2000)
+/*16*/ ushort globalseg_reg;
+/*18*/ ushort cr_lf_1;
+/*1a*/ uchar copyright_str[51];
+/*4d*/ ushort zero_str_terminator;
+/*4f*/ uchar revision_byte_unused;
+/*50*/ ushort maxdma;
+/*52*/ uchar romchksum1;
+/*53*/ uchar romchksum2;
+/*54*/ uchar romchksum3;
+/*55*/ uchar rom_sim_str[24];
+/*6d*/ uchar sim_rev_byte_1;
+/*6e*/ uchar sim_rev_byte_2;
+/*6f*/ ushort vendor_str_offset;
+/*71*/ ushort camcore_version;
+/*73*/ ulong chip_phys;
+/*77*/ ushort chip_offset;
+/*79*/ ushort reservedcc; /* used by DOSNEC90.SYS and PATCHNEC.EXE */
+/*7b*/ ushort hba_ram_offset;
+/*7d*/ ushort ram_size;
+/*7f*/ ushort vendor_unique_str_offset;
+/*81*/ uchar chip_type_str[8]; /*holds "NCR5380", "NCR53400", etc.*/
+/*89*/ ushort offset_to_32bit;
+/*8B*/ ushort res20;
+/*8D*/ uchar reserved3[2];
+/*8F*/ long AddSpaceOffset;
+/*93*/ ulong AddSpaceLength;
+/*97*/ long StartEntryOffset;
+/*9b*/ long InterruptEntryOffset;
+/*9f*/ ulong StackSpace;
+/*A3*/ ulong IntStackSpace;
+/*A7*/ ulong GlobalMemLength;
+/*Ab*/ ulong CCBPrivateDataLength;
+/*Af*/ uchar ClockSpeed;
+/*B0*/ uchar SCSIClockSpeed; /** 5/19/92 SCLK support for fast synchronous */
+/*B1*/ uchar FastSyncHW; /** Variable in .RSP if H/W supports fast synchronous */
+/*B2*/ ushort res22;
+/*B4*/ ushort res23;
+/*B6*/ ushort res24;
+/*B8*/ ushort res25;
+/*BA*/ ushort res26;
+/*BC*/ ushort res27;
+/*BE*/ ushort res28;
+/*C0*/ ushort res29;
+/*C2*/ ushort res30;
+/*C4*/ ulong DelayValue;
+/*C8*/ ulong expiration_date;
+/*CC*/ uchar reserved; /* if ABIOS is defined the following */
+/*CD*/ uchar poscount; /* fields will NOT BE IN THE ROM */
+/*CE*/ uchar res0;
+/*CF*/ uchar res1;
+/*D0*/ uchar res2;
+/*D1*/ uchar res3;
+/*D2*/ uchar res4;
+/*D3*/ uchar res5;
+/*D4*/ uchar res6;
+/*D5*/ uchar res7;
+/*D6*/ ulong res8;
+/*DA*/ ulong res9;
+/*DE*/ ulong res10;
+/*E2*/ ushort customdata[8];
+/*F2*/ ulong posdata[8];
+/*112*/ /* sizeof this structure */
+} ROMCAMcoreFields;
+
+#define rccfp ((ROMCAMcoreFields far *)gp->cg.HAVirtAddr)
+
+#pragma pack()
+
+#endif
+
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/camglbls.h b/private/ntos/miniport/scsiwdl/ncrcam/camglbls.h
new file mode 100644
index 000000000..96fc97946
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/camglbls.h
@@ -0,0 +1,59 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 1992 NCR Corporation
+//
+// CAMGLBLS.H
+//
+// Revisions:
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef CAM_GLOBALS_H
+#define CAM_GLOBALS_H
+
+#pragma pack(1) /* pack structures, cannot do it with compiler option
+ Zp because structures shared with the NT MiniPort
+ driver and NT upper layer drivers will be messed up.
+ We must pack only the structures shared with the
+ CAMcore. */
+
+typedef struct CAMGlobals
+{
+/*00*/ ushort Debugsel; /* used by PMSG */
+/*02*/ uchar CoreInitialized; /* core sets this */
+/*03*/ uchar HASCSIID; /* core sets this */
+/*04*/ uchar IRQNum; /* core sets this */
+/*05*/ uchar DMAChannel; /* core sets this */
+/*06*/ ushort reserved1;
+/*08*/ ulong GlobalPhysAddr; /* caller sets this */
+/*0c*/ ulong HAPhysAddr; /* caller sets this */
+/*10*/ ulong Dbgwait; /* used by PMSG */
+/*14*/ ushort Lclscrnpos; /* used by PMSG */
+/*16*/ ushort Botscrnlimit; /* used by PMSG */
+/*18*/ ushort Topscrnlimit; /* used by PMSG */
+/*1a*/ uchar Dbgflag; /* used by PMSG */
+/*1b*/ uchar reserved2;
+/*1c*/ ulong HAVirtAddr; /* caller sets this */
+/*20*/ ushort BasePort; /* core sets this */
+/*22*/ ushort PortCnt; /* core sets this */
+/*24*/ ulong ChipVirtAddr; /* caller sets this */
+/*28*/ ulong HARAMVirtAddr; /* caller sets this */
+/*2c*/ ushort DelayValue; /* core sets this */
+/*2e*/ ushort Reserved5; /* changed from ulong to ushort */
+/*30*/ uchar DelayCalculated; /* core sets this */
+/*31*/ uchar config_info; /* core sets this */
+#define CONFIG_VALID (0x080)
+/*32*/ ushort GlobalFlags; /* caller sets this */
+#define GLOBAL_FLAGS_TRUE_INT (0x0001)
+/*34*/ ulong Reserved3;
+/*38*/ ushort Reserved4;
+/*3A*/ ushort custom; /* core sets this */
+/*3c*/ ulong HAOrigPhysAddr; /* caller sets this */
+/*40*/ uchar rsccb[256]; /* storage area for caller */
+/*140*/
+} CAMGlobals; /* 320 bytes */
+
+#pragma pack()
+
+#endif
+
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/intercam.h b/private/ntos/miniport/scsiwdl/ncrcam/intercam.h
new file mode 100644
index 000000000..9c30bad8f
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/intercam.h
@@ -0,0 +1,71 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 1992 NCR Corporation
+//
+// INTERCAM.H
+//
+// Revisions:
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef INTERCAM_H
+#define INTERCAM_H
+
+/* this define keeps the SCSIRequestCCB the correct length for internal use */
+#define FROMCAM /* not defining this will cause a filler added to
+ SCSIRequestCCB structure in CAM.H and cause us to have a
+ negative subscript for our filler in the ROMscsiCCB structure. */
+#include "cam.h" /* CAM CCB structures */
+
+#pragma pack(1) /* pack structures, cannot do it with compiler option
+ Zp because structures shared with the NT MiniPort
+ driver and NT upper layer drivers will be messed up.
+ We must pack only the structures shared with the
+ CAMcore. */
+
+
+/* ROMCCBFields.Flags flags */
+#define REAL_MODE 0x0001
+#define SEL_ALLOCED 0x0002
+#define SHAD_FLAG 0x0004
+
+/*#define DEFAULT_TIMEOUT 2 /*seconds*/ /* Now defined in cam.c */
+
+typedef struct
+{
+/* 0 */ ushort Flags; /* not used in 700 cores */
+/* 2 */ ushort DMAChannel; /* not used in 700 cores */
+/* 4 */ ulong DataPhys;
+/* 8 */ ulong DataVirt;
+/* C */ ulong SensePhys;
+/* 10 */ ulong SenseVirt; /* not used in 700 cores */
+/* 14 */ ushort CDBLength;
+/* 16 */ uchar CDB[16];
+/* 26 */ ulong camlink; /* not used in 700 cores */
+/* 2A */ ulong CCBPhys; /* not used in 700 cores */
+/* 2E */
+} ROMCCBFields; /* 46 bytes */
+
+#define MAX_CCB_LEN 192
+/* Changing defn below as it is negative */
+#define ROMscsiCCB_FILLER_LEN \
+ (MAX_CCB_LEN - (sizeof(SCSIRequestCCB)+sizeof(ROMCCBFields)))
+
+typedef struct
+{
+/* 0 */ SCSIRequestCCB SCSIReq; /* CAM CCB data structure */
+/* 4F */ ROMCCBFields ROMFields; /* Unique fields used in CAMcores */
+ /* Try to get rid of this in 3.0*/
+/* 7D */ uchar filler[ROMscsiCCB_FILLER_LEN]; /* 66 bytes */
+} ROMscsiCCB, *PROMscsiCCB;
+
+/* not needed for Windows NT */
+/* ulong CAMInterrupt(uchar far * GlobalData);
+ushort CAMInit( CAMGlobals far *cgp);
+ulong CAMStart( CAMGlobals far *cgp, ROMscsiCCB far *rsp);
+ */
+
+
+#pragma pack( )
+
+#endif
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/makefile b/private/ntos/miniport/scsiwdl/ncrcam/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.c b/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.c
new file mode 100644
index 000000000..c2e2d0ca2
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.c
@@ -0,0 +1,1640 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 1992 NCR Corporation
+//
+// NCRSDMS.C
+//
+// This is the Windows NT NCR MiniPort driver for all NCR CAMcores.
+//
+// Revisions:
+//
+//
+// Note: Search for the word "future" for things that may need to
+// be upgraded for SDMS 3.0 or to support other enhanced
+// features.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+// NT include files
+
+#include "miniport.h" // MiniPort structure definitions
+#include "scsi.h" // SRB & SCSI structure definitions and others
+
+#ifdef i386
+
+// NCR SDMS include files
+
+#include "typedefs.h" // Defines for uchar,ushort,ulong etc.
+#include "camcore.h" // CAMCore ROM header structure definition
+#include "camglbls.h" // Globals structure definitions
+#include "intercam.h" // ROMCCB structure definitions, additional
+ // fields used in ROM appended to end of
+ // CAM CCB. Also, includes cam.h which
+ // defines CAM CCB structures.
+
+
+#include "ncrsdms.h" // Specific info for the miniport driver.
+
+// Noncached Extension - Guarantees to be below the 16MB 24 bit addressing
+// limitation of AT cards. Need this for CoreGlobals which contain
+// SCRIPT instructions for the C700 family. Must fetch below the
+// 16MB limit for AT cards. Note: Fujitsu EISA board also has this
+// limitation.
+
+typedef struct _NONCACHED_EXTENSION{
+
+ CAMGlobals CoreGlobals; // CAMGlobals structure defined in CAMGLBLS.H
+
+ UCHAR SCSICoreGlobals[4096];
+ // This is to make room for the globals
+ // defined in SCSICORE for each chip.
+ // For example, C700 SCRIPTS and misc.
+ // other globals. Defined in SCSIcore.h
+ // for each chips camcore.
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+// Hardware device extension.
+// This structure is initialized in the FindCore routine.
+
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ // Pointer to noncached extension
+
+ PNONCACHED_EXTENSION NoncachedExtension;
+
+ // The next set of functions MUST be defined as type "_cdecl".
+ // These functions are in the CAMcore and have been previously
+ // compiled as "_cdecl" type functions, while NT assumes all
+ // functions are "_stdcall". The difference is in which type of
+ // function adjusts the stack - caller adjusts when using _cdecl
+ // while callee adjusts stack when using _stdcall.
+
+ // Pointer to CAMInit in 32-bit CAMcore code.
+ ULONG (__cdecl *initPtr)(PVOID CoreGlobalsPtr);
+
+ // Pointer to CAMStart in 32-bit CAMcore code.
+ ULONG (__cdecl *startPtr)(PVOID CoreGlobalsPtr, PVOID CCBPtr);
+
+ // Pointer to CAMInterrupt in 32-bit CAMcore code.
+ ULONG (__cdecl *interruptPtr)(PVOID CoreGlobalsPtr);
+
+ // Pointer to chsMap routine in stdport 32 bit CAMcore code.
+ VOID (__cdecl *chsPtr)(PVOID CoreGlobalsPtr, PVOID CCBPtr);
+
+ // SDMS Version number.
+ ULONG SdmsVersion;
+
+ // Path id of this device extension.
+ ULONG scsiBusId;
+
+ // Storage area for REX code.
+ UCHAR base32BitCode[MAX_32BIT_SIZE];
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+// Logical unit extension derived from the SRB
+
+typedef struct _HW_LU_EXTENSION {
+
+ PSCSI_REQUEST_BLOCK CurrentSrb; // Current SRB
+
+} HW_LU_EXTENSION, *PHW_LU_EXTENSION;
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+NCRFindAdapter(
+ IN PVOID DeviceExtension,
+ IN PVOID HwContext,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+NCRHwInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+NCRStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+NCRInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+NCRResetBus(
+ IN PVOID DeviceExtension,
+ IN ULONG PathId
+ );
+
+ULONG
+FindCore(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PHWInfo hwInfo,
+ OUT PBOOLEAN Again
+ );
+
+VOID
+InitPath(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+BuildCCBFromSRB(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DriverEntry
+//
+// Installable driver initialization entry point for system.
+// 1) Initialize hwInitializationData structure
+// 2) Call ScsiPortInitialize routine in PortDriver
+//
+// Arguments:
+// Argument1 - supplies a context value with
+// which the HBA miniport driver should call
+// ScsiPortInitialize.
+//
+// Argument2 - supplies a 2nd context value with
+// which the HBA miniport driver should call
+// ScsiPortInitialize.
+//
+// Return Value: status returned by ScsiPortInitialize
+//
+/////////////////////////////////////////////////////////////////////////////
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+{
+ HW_INITIALIZATION_DATA hwInitData;
+
+ HWInfo hwInfo;
+
+ ULONG isaStatus;
+ ULONG eisaStatus;
+ ULONG mcaStatus;
+ ULONG internalStatus;
+ ULONG busStatus;
+ ULONG i;
+
+ DebugPrint(( 1, "NCR SDMS: DriverEntry \n"));
+
+ // Zero out structure
+
+ for ( i = 0 ; i < sizeof(HW_INITIALIZATION_DATA); i++ ) {
+ ((PUCHAR)&hwInitData)[i] = 0;
+ }
+
+ // Set size of hwInitData
+
+ hwInitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ // Initialize entry points to MiniPort routines
+
+ hwInitData.HwInitialize = NCRHwInitialize;
+ hwInitData.HwStartIo = NCRStartIo;
+ hwInitData.HwInterrupt = NCRInterrupt;
+ hwInitData.HwFindAdapter = NCRFindAdapter;
+ hwInitData.HwResetBus = NCRResetBus;
+
+ // Following MiniPort routines not supported.
+ hwInitData.HwDmaStarted = NULL;
+
+ // Size in bytes required to hold per adapter information.
+ hwInitData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ // Specify size (bytes) of per logical unit storage.
+ hwInitData.SpecificLuExtensionSize = 0;
+
+ // Specify size (bytes) of the per request storage.
+ // Setting extension size to zero causes a crash in FindCore when
+ // ScsiPortGetUncachedExtension is called. Why????
+
+ hwInitData.SrbExtensionSize = sizeof( ROMscsiCCB );
+
+ // Initialize access range from CAMcore ROM header
+ // (I/O and/or memory mapped locations) normally 2 for now.
+ // Future: We have to allow for I/O, Memory-mapped,
+ // or both because we do not know anything about the
+ // adapter at this point.
+ hwInitData.NumberOfAccessRanges = 2;
+
+ hwInitData.MapBuffers = FALSE;
+
+ hwInitData.NeedPhysicalAddresses = TRUE;
+
+ // Initial release does not support tagged queing.
+ hwInitData.TaggedQueuing = FALSE;
+
+ // Auto request sense not enabled. The SRB will still attempt to
+ // enable this function, so auto request sense must also be disabled
+ // at the CCB level.
+ hwInitData.AutoRequestSense = FALSE;
+
+ hwInitData.MultipleRequestPerLu = FALSE;
+
+ hwInitData.ReceiveEvent = FALSE;
+
+ // Reset the HBA count.
+ hwInfo.hbaCount = 0;
+
+ // Track how many adapter addresses have been checked for validity.
+ // This variable also referred to as "HwContext" or "Context" in
+ // the FindAdapter routine.
+
+ // Try to configure for EISA.
+
+ DebugPrint(( 2, "NCR SDMS: DriverEntry *** EISA *** \n" ));
+
+ hwInfo.romAddrSpace = 0;
+ hwInfo.currentVirtAddr = 0;
+ hwInfo.currentRomAddr = FIRST_ROM_ADDRESS;
+ hwInfo.scsiBusId = 0;
+ hwInitData.AdapterInterfaceType = Eisa;
+
+ eisaStatus = ScsiPortInitialize(DriverObject, Argument2,
+ &hwInitData, &hwInfo);
+
+ DebugPrint(( 3, "NCR SDMS: DriverEntry ...eisaStatus = 0x%x \n",
+ eisaStatus ));
+
+ if ( hwInfo.hbaCount < MAX_NT_HBAS && eisaStatus != 0 )
+ {
+ DebugPrint(( 2, "NCR SDMS: DriverEntry *** ISA *** \n" ));
+
+ hwInfo.romAddrSpace = 0;
+ hwInfo.currentVirtAddr = 0;
+ hwInfo.currentRomAddr = FIRST_ROM_ADDRESS;
+ hwInfo.scsiBusId = 0;
+ hwInitData.AdapterInterfaceType = Isa;
+
+ isaStatus = ScsiPortInitialize(DriverObject, Argument2,
+ &hwInitData, &hwInfo);
+
+ DebugPrint(( 3, "NCR SDMS: DriverEntry ...isaStatus = 0x%x \n",
+ isaStatus ));
+
+ }
+
+
+ // Try to configure for internal (what is Internal???)
+
+ if ( hwInfo.hbaCount < MAX_NT_HBAS )
+ {
+ DebugPrint(( 2, "NCR SDMS: DriverEntry *** Internal *** \n" ));
+
+ hwInfo.romAddrSpace = 0;
+ hwInfo.currentVirtAddr = 0;
+ hwInfo.currentRomAddr = FIRST_ROM_ADDRESS;
+ hwInfo.scsiBusId = 0;
+ hwInitData.AdapterInterfaceType = Internal;
+
+ internalStatus = ScsiPortInitialize(DriverObject, Argument2,
+ &hwInitData, &hwInfo);
+
+ DebugPrint(( 3, "NCR SDMS: DriverEntry ...internalStatus = 0x%x \n",
+ internalStatus ));
+ }
+
+ // Try to configure for Microchannel.
+
+ if ( hwInfo.hbaCount < MAX_NT_HBAS )
+ {
+ DebugPrint(( 2, "NCR SDMS: DriverEntry *** Microchannel *** \n"));
+
+ hwInfo.romAddrSpace = 0;
+ hwInfo.currentVirtAddr = 0;
+ hwInfo.currentRomAddr = FIRST_ROM_ADDRESS;
+ hwInfo.scsiBusId = 0;
+ hwInitData.AdapterInterfaceType = MicroChannel;
+
+ mcaStatus = ScsiPortInitialize(DriverObject, Argument2,
+ &hwInitData, &hwInfo);
+
+ DebugPrint(( 3, "NCR SDMS: DriverEntry ...mcaStatus = 0x%x \n",
+ mcaStatus ));
+ }
+
+ // Return the minimum value.
+ if ( eisaStatus < isaStatus )
+ busStatus = eisaStatus;
+ else
+ busStatus = isaStatus;
+
+ if (internalStatus < busStatus )
+ busStatus = internalStatus;
+
+ if ( mcaStatus < busStatus )
+ busStatus = mcaStatus;
+
+ // Return the smallest status.
+
+ DebugPrint(( 1, "NCR SDMS: DriverEntry ...exiting\n"));
+
+ return( busStatus );
+
+} // End NCREntry
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// NCRFindAdapter
+//
+// 1). Relocate 32 bit CAMcore code.
+// 2). Allocate noncachedExtension.
+//
+// Return:
+// ROMBase - base address of where CAMCore ROM was located.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+ULONG
+NCRFindAdapter(
+ IN PVOID HwDeviceExtension, // CAMGlobals
+ IN PVOID HwContext,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension;
+ ULONG FCReturnValue;
+ PHWInfo hwInfo;
+
+
+ DebugPrint(( 1, "NCR SDMS: NCRFindAdapter \n" ));
+
+ // Need to get some information about previous calls.
+ hwInfo = (PHWInfo)HwContext;
+
+ // Check if the ROM address space has been mapped yet.
+ // If not, map the entire ROM address space in one call --
+ // this is to prevent a problem with NTLoader running out
+ // of page frame entries.
+ if (hwInfo->romAddrSpace == 0 )
+ {
+ // Get the entire ROM address space.
+ hwInfo->romAddrSpace = ScsiPortGetDeviceBase(
+ DeviceExtension,
+ ConfigInfo->AdapterInterfaceType, // Bus type
+ ConfigInfo->SystemIoBusNumber, // Bus number
+ ScsiPortConvertUlongToPhysicalAddress(
+ FIRST_ROM_ADDRESS ),
+ ROM_ADDRESS_SPACE_SIZE, // Map entire ROM region
+ // from C0000 - FFFFF
+ FALSE ); // Memory mapped
+
+ // If GetDeviceBase returned a zero, there was some
+ // error -- return to NT.
+ if ( hwInfo->romAddrSpace == 0 )
+ {
+ DebugPrint(( 3, "NCR SDMS: NCRFindAdapter ...Null pointer for ROM space \n"));
+ return( SP_RETURN_ERROR );
+ }
+
+ // Setup a pointer to the current virtual address we will
+ // be checking form SDMS ROMs.
+ hwInfo->currentVirtAddr = hwInfo->romAddrSpace;
+ }
+
+
+ // Check if maximum number of HBAs found. If so, clear the
+ // device base (if it exists), tell NT not to call FindAdapter
+ // anymore, and return to NT.
+
+ if ( hwInfo->hbaCount >= MAX_NT_HBAS )
+ {
+ DebugPrint(( 3, "NCR SDMS: NCRFindAdapter ...maximum HBA count exceeded \n" ));
+ if ( hwInfo->romAddrSpace != 0 )
+ ScsiPortFreeDeviceBase( DeviceExtension, hwInfo->romAddrSpace );
+
+ *Again = FALSE;
+
+ return( SP_RETURN_NOT_FOUND );
+ }
+
+ DebugPrint(( 2, "NCR SDMS: NCRFindAdapter ...before FindCore \n"));
+
+ FCReturnValue = FindCore( DeviceExtension,
+ ConfigInfo,
+ HwContext,
+ Again );
+
+ DebugPrint(( 2, "NCR SDMS: NCRFindAdapter ...after FindCore \n"));
+
+ // If no adapter found, return status to NT.
+ if ( FCReturnValue != SP_RETURN_FOUND )
+ return ( FCReturnValue );
+
+ // Initialize CAMcore and CoreGlobals. Call CAMinit in CAMcore
+ // with CoreInitialized = 0 .
+
+ // Noncached Extension was allocated in FindCore. Initialize the
+ // extension so the ConfigInfo data structure can be set up.
+ noncachedExtension = DeviceExtension->NoncachedExtension;
+
+ noncachedExtension->CoreGlobals.CoreInitialized = 0;
+
+ // Call CAMInit. Delays for hardware to reset are in the CAMcore.
+ (*DeviceExtension->initPtr)(&noncachedExtension->CoreGlobals);
+
+ // Initialize PORT_CONFIGURATION_INFORMATION
+
+ ConfigInfo->BusInterruptLevel = noncachedExtension->CoreGlobals.IRQNum;
+
+
+ // Update the DMA information if changed by CAMInit.
+ if ( noncachedExtension->CoreGlobals.DMAChannel == 0xFF ||
+ noncachedExtension->CoreGlobals.DMAChannel == 0x00 )
+ ConfigInfo->DmaChannel = 0xFFFFFFFF;
+ else
+ ConfigInfo->DmaChannel = noncachedExtension->CoreGlobals.DMAChannel;
+
+
+ // ConfigInfo->MaximumTransferLength = noncachedExtension->CoreGlobals.;
+
+ // Since we are doing the DMA programming (not NT), do not have to
+ // set DmaWidth.
+ // ConfigInfo->DmaWidth = xxx;
+
+ // Currently unused:
+ // ConfigInfo->DmaSpeed = xxx;
+
+ // Future: possibly need to get this info from CAMcore globals to
+ // accomodate dual SCSI channel or more.
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InitiatorBusId[0] = noncachedExtension->CoreGlobals.HASCSIID;
+
+ // Currently unused.
+ // ConfigInfo->AtdiskPrimaryClaimed
+ // ConfigInfo->AtdiskSecondaryClaimed
+
+ // Check whether we are I/O mapped or memory mapped.
+ if ( noncachedExtension->CoreGlobals.BasePort )
+ {
+ // IO mapped SCSI chip.
+ (*ConfigInfo->AccessRanges)
+ [AccessRangeChipIndex].RangeInMemory = FALSE;
+
+ (*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ noncachedExtension->CoreGlobals.BasePort );
+ }
+
+ // Return SP_RETURN_FOUND, SP_RETURN_NOT_FOUND,
+ // SP_RETURN_ERROR or SP_RETURN_BAD_CONFIG.
+
+ return SP_RETURN_FOUND;
+
+} // End NCRFindAdapter
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// FindCore
+//
+// Locates CAMcore in the ROM BIOS address space from
+// 0xC0000 to 0x100000. Initializes global values for ROM address
+// (HAPhysAddr, HAVirtAddr, HARAMVirtAddr), chip addresses
+// (ChipVirtAddr) and address of globals (GlobalPhysAddr).
+// Allocates noncachedExtension.
+//
+// Arguments: HwDeviceExtension -
+//
+// Returns: Address of CAMcore or SP_RETURN_ERROR if it could not
+// allocate noncachedExtension.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+ULONG
+FindCore(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PHWInfo hwInfo,
+ OUT PBOOLEAN Again
+ )
+{
+ PNONCACHED_EXTENSION noncachedExtension;
+ ROMCAMcoreFields * ROMHeader;
+ PUCHAR basePtr;
+ REXHeader * rp;
+ CAM32Header * cp;
+ ULONG fileSize;
+ PULONG relocTable;
+ ULONG i;
+ PCHAR src;
+ ULONG Length;
+
+ BOOLEAN NoSdmsRom;
+ PULONG itemPtr;
+ ULONG foundRomAddr;
+
+ CONST UCHAR magicStr1[] = MAGIC_STR_1 ;
+
+ DebugPrint(( 1, "NCR SDMS: FindCore \n"));
+
+ DeviceExtension->initPtr = 0;
+
+ // Set up virtual address pointer.
+ basePtr = hwInfo->currentVirtAddr;
+
+ // Check the ROM address space every 2K for SDMS CAMcore.
+ for ( ; hwInfo->currentRomAddr < LAST_ROM_ADDRESS;
+ basePtr += ROM_CHECK_STEP,
+ hwInfo->currentRomAddr += ROM_CHECK_STEP )
+ {
+
+ DebugPrint(( 3, "NCR SDMS: FindCore ...VirtAddr = 0x%x RomAddr = 0x%x \n",
+ basePtr, hwInfo->currentRomAddr ));
+
+
+ // Check for ROM identifier.
+ if ( gByte(basePtr,MARK_55) != 0x55
+ || gByte(basePtr,MARK_AA) != 0xAA )
+ {
+ continue; // Check next ROM address space.
+ }
+
+ // Search for ROM SIM string present in all CAMCores.
+ NoSdmsRom = FALSE;
+
+ // Check for the identifying string in the ROM.
+ for (i = 0; i < sizeof(magicStr1) - 1; i++)
+ {
+
+ if ( gByte(basePtr,ROM_SIM_STR+i) != magicStr1[i] )
+ {
+ NoSdmsRom = TRUE;
+ break; // Not SDMS ROM -- stop checking identifying
+ // string.
+ }
+ } // End for loop
+
+ if ( NoSdmsRom )
+ continue; // Check next ROM address location
+
+ // At this point, we apparently have found a SDMS CAMcore.
+
+ // Store SDMS CAMcore version.
+ DeviceExtension->SdmsVersion = gWord(basePtr, CORE_VERSION);
+
+ DebugPrint(( 1, "NCR SDMS: FindCore ...SDMS Version = %d \n",
+ DeviceExtension->SdmsVersion ));
+
+ // If V1.6 or newer CAMcore, set up pointer to REX header.
+ // If not at least V1.6, continue searching ROM address space.
+ if ( DeviceExtension->SdmsVersion >= SDMS_V16 )
+ {
+ if (gWord(basePtr,REX_OFFSET) != 0)
+ rp = (REXHeader *)(basePtr + gWord(basePtr,REX_OFFSET));
+
+ // Look for the REX header signature of "MQ" and end of the
+ // REX header = 0x0001. This should be the SDMS CAMcore.
+ // If this is true break out of the loop checking the
+ // ROM address space. If REX header not found, fall
+ // through to bottom of FOR loop, clear device base
+ // and continue checking ROM address space.
+
+ if ( ( rp->sig == 0x514D ) && (rp->ooo1 == 1) )
+ break;
+ }
+
+ // Not at SDMS V1.6 or above, so clear the saved version number.
+ DeviceExtension->SdmsVersion = 0;
+
+ } // End of For loop checking ROM address space.
+
+
+ // Check if we searched outside of ROM address space. If outside of
+ // ROM address space, return to caller indicating no CAMcore found.
+ if ( hwInfo->currentRomAddr >= LAST_ROM_ADDRESS )
+ {
+ ScsiPortFreeDeviceBase( DeviceExtension, hwInfo->romAddrSpace );
+
+ hwInfo->currentVirtAddr = 0;
+ hwInfo->romAddrSpace = 0;
+
+ // Entire ROM address space has been searched.
+ *Again = FALSE;
+
+ return( SP_RETURN_NOT_FOUND );
+ }
+
+ // Set found ROM address.
+ foundRomAddr = hwInfo->currentRomAddr;
+
+ // Increment current ROM address so next time in FindCore, search
+ // will start at the proper location.
+ hwInfo->currentRomAddr += ROM_CHECK_STEP;
+
+ // Increment current virtual pointer to next possible ROM location.
+ hwInfo->currentVirtAddr = basePtr + ROM_CHECK_STEP;
+
+ // Allocate a smaller device base that only includes the 32K
+ // ROM that we have found.
+ basePtr = ScsiPortGetDeviceBase(
+ DeviceExtension,
+ ConfigInfo->AdapterInterfaceType, // bus type
+ ConfigInfo->SystemIoBusNumber, // bus number
+ ScsiPortConvertUlongToPhysicalAddress( foundRomAddr ),
+ ROM_SIZE, // 32K allocated, must allocate
+ // enough to be able to access
+ // all of the 32 bit code.
+ FALSE); // Memory mapped
+
+ // Tell NT that we should be called again.
+ *Again = TRUE;
+
+ // At this point, we have located a SDMS V1.6 (or above) CAMcore
+ // and identified the REX section of the CAMcore.
+
+ // Now "basePtr" points to the ROM header and "rp" points to the REX
+ // header in the ROM structure, and "foundRomAddr" is the
+ // physical address of the ROM.
+
+ DebugPrint(( 1, "NCR SDMS: FindCore ...CAMcore found at 0x%x \n",
+ foundRomAddr ));
+
+ // Get information from ROM header so that we can call
+ // GetUncachedExtension to initialize our CoreGlobals.
+ // GetUncachedExtension needs DmaChannel, DmaPort, DmaSpeed,
+ // MaximumLength, ScatterGather, Master and NumberOfPageBreaks
+ // (if scatter/gather is supported) initialized in the ConfigInfo
+ // data structure.
+
+ // Setup pointer to ROMHeader.
+
+ ROMHeader = (ROMCAMcoreFields *)basePtr;
+
+ // Save path id in device extension (for ScsiPortNotification).
+ DeviceExtension->scsiBusId = hwInfo->scsiBusId;
+
+ // Save DMA channel.
+ if ( ROMHeader->dmachannel == 0xFF || ROMHeader->dmachannel == 0x00 )
+ ConfigInfo->DmaChannel = 0xFFFFFFFF;
+ else
+ ConfigInfo->DmaChannel = ROMHeader->dmachannel;
+
+ // Master is always true because the CAMcore already programs
+ // the DMA channel not NT.
+ ConfigInfo->Master = TRUE;
+
+ // Initialize maximum transfer length if maxdma is not zero.
+ // If maxdma is zero there is no limit so leave MaximumTransferLength
+ // to its default of 0xffffffff which means no limit to NT.
+
+ if ( ROMHeader->maxdma )
+ ConfigInfo->MaximumTransferLength = ROMHeader->maxdma;
+
+ // Do not support scatter/gather with this release of the
+ // driver.
+ ConfigInfo->ScatterGather = FALSE;
+
+ // Only one break without scatter/gather. However, changing
+ // this to one causes run time errors -- so leave at 16 for now.
+ ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_BRKS;
+
+ // In future to support caching adapters (CachesData=TRUE)
+ // we need this info in CAMcore globals or ROM header.
+ ConfigInfo->CachesData = FALSE;
+ ConfigInfo->Length = sizeof( PORT_CONFIGURATION_INFORMATION );
+
+ if ( ( gByte( basePtr, ROM_TYPE_1 ) == 'A' ) &&
+ ( gByte( basePtr, ROM_TYPE_2 ) == 'T' ) )
+ {
+ // Insure that data buffers are below 16MB.
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->Dma32BitAddresses = FALSE;
+ }
+ else
+ {
+ ConfigInfo->InterruptMode = LevelSensitive;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+ }
+
+ // Allocate a Noncached Extension to use for CoreGlobals.
+
+ DeviceExtension->NoncachedExtension = ScsiPortGetUncachedExtension(
+ DeviceExtension,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ noncachedExtension = DeviceExtension->NoncachedExtension;
+
+ // If Noncached extension could not be allocated, log error.
+ if (DeviceExtension->NoncachedExtension == NULL)
+ {
+ ScsiPortLogError( DeviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 7 << 8
+ );
+
+ return(SP_RETURN_ERROR);
+ }
+
+ // Zero out noncachedExtension which contains the CoreGlobals.
+ for ( i = 0; i < sizeof(NONCACHED_EXTENSION); i++)
+ ((PUCHAR)noncachedExtension)[i] = 0;
+
+ // Address of host adapter.
+ noncachedExtension->CoreGlobals.HAOrigPhysAddr = foundRomAddr;
+
+ // Address of ROM image.
+ noncachedExtension->CoreGlobals.HAPhysAddr = foundRomAddr;
+
+ // Get Virtual address space for the HBA ROM from basePtr pointer.
+ noncachedExtension->CoreGlobals.HAVirtAddr = (ULONG)basePtr;
+
+ noncachedExtension->CoreGlobals.GlobalPhysAddr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(
+ DeviceExtension,
+ NULL,
+ &DeviceExtension->NoncachedExtension->CoreGlobals,
+ &Length));
+
+ // CHIP_PHYS is the physical address of a memory mapped SCSI chip
+ // on the mother board. This value is in the ROM header of the
+ // CAMcore.
+
+ if ( gLong(basePtr,CHIP_PHYS) )
+ noncachedExtension->CoreGlobals.ChipVirtAddr =
+ noncachedExtension->CoreGlobals.HAVirtAddr + gLong(basePtr,CHIP_PHYS);
+
+ // CHIP_OFFSET is the offset from the beginning of the ROM for
+ // a memory mapped SCSI chip on an HBA. This is also in the
+ // ROM header of the CAMcore initialized from the .RSP file
+ // when the CAMcore is built.
+
+ else
+ noncachedExtension->CoreGlobals.ChipVirtAddr =
+ noncachedExtension->CoreGlobals.HAVirtAddr + gWord(basePtr,CHIP_OFFSET);
+
+ if ( gWord(basePtr,RAM_OFFSET) )
+ noncachedExtension->CoreGlobals.HARAMVirtAddr =
+ noncachedExtension->CoreGlobals.HAVirtAddr + gWord(basePtr,RAM_OFFSET);
+
+ ConfigInfo->NumberOfAccessRanges = 2;
+
+ // Initialize AccessRanges in the ConfigInfo data structure
+ // for the ROM CAMcore and the SCSI chip on HBA.
+
+ (*ConfigInfo->AccessRanges)[AccessRangeROMIndex].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ noncachedExtension->CoreGlobals.HAPhysAddr );
+
+ // Length of ROM in 3rd byte of ROMHeader.
+
+ (*ConfigInfo->AccessRanges)[AccessRangeROMIndex].RangeLength =
+ ROMHeader->ROMlen * 512;
+
+ (*ConfigInfo->AccessRanges)[AccessRangeROMIndex].RangeInMemory = TRUE;
+
+ // Initialize AccessRanges for Chip on HBA.
+ // Number of chip ports is set to 200 -- 53C720 is 92 bytes (0x5c).
+
+ (*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeLength = 200;
+
+ // Check whether we are I/O mapped or memory mapped.
+ if ( noncachedExtension->CoreGlobals.BasePort )
+ {
+ // IO mapped SCSI chip.
+ (*ConfigInfo->AccessRanges)
+ [AccessRangeChipIndex].RangeInMemory = FALSE;
+
+ (*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ noncachedExtension->CoreGlobals.BasePort );
+ }
+ else
+ {
+ // Memory mapped SCSI chip
+ (*ConfigInfo->AccessRanges)
+ [AccessRangeChipIndex].RangeInMemory = TRUE;
+
+ if ( gLong(basePtr,CHIP_PHYS) )
+ (*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ noncachedExtension->CoreGlobals.HAPhysAddr + gLong(basePtr,CHIP_PHYS) );
+ else
+ (*ConfigInfo->AccessRanges)[AccessRangeChipIndex].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ noncachedExtension->CoreGlobals.HAPhysAddr + gWord(basePtr,CHIP_OFFSET) );
+ }
+
+ // Now extract information from the REX header
+
+ // Size of the 32-bit code.
+
+ fileSize = rp->sizeQuo * 512 + rp->sizeRem - 512;
+ fileSize -= rp->headSize * 16;
+
+ DebugPrint((1, "NCR SDMS: FindCore ...REX file size = %d \n", fileSize));
+
+ // Point "src" to beginning of the 32-bit code. Have to skip
+ // around the REX header information.
+
+ src = (char *)((long)rp + rp->headSize * 16);
+
+ // Copy the 32-bit code from the ROM into the Device Extension.
+
+ for ( i = 0; i < fileSize; i++ )
+ DeviceExtension->base32BitCode[i] = src[i];
+
+ // Perform relocation.
+
+ // Set "relocTable" to first item to be relocated.
+
+ relocTable = (ulong *)( (long)rp + rp->relocOffset );
+
+ // Relocate all items in relocation table. Insure that each
+ // item has the high bit set before relocation.
+ for ( i = 0; i < rp->numReloc; i++ )
+ {
+ // The high bit of the values in the relocation table is
+ // set if 32 bits wide so, it should be set since
+ // this is 32 bit code. If it is not set, free device
+ // extension and return to caller.
+ if ( (relocTable[i] & 0x80000000) == 0 )
+ {
+ ScsiPortFreeDeviceBase( DeviceExtension, basePtr );
+ return( SP_RETURN_ERROR );
+ }
+ itemPtr = (ulong *)(DeviceExtension->base32BitCode +
+ (relocTable[i] & 0x7fffffff));
+
+ *itemPtr += (long)DeviceExtension->base32BitCode;
+ }
+
+ // Setup pointer to relocated 32-bit code. Note, must use "src"
+ // rather than base32BitCode because relocation changes
+ // CAM32Header.
+
+ cp = (CAM32Header *)src;
+
+ // Pointer to CAMInit.
+
+ DeviceExtension->initPtr =
+ (PVOID)(DeviceExtension->base32BitCode +
+ cp->initOffset);
+
+ // Pointer to CAMStart.
+
+ DeviceExtension->startPtr =
+ (PVOID)(DeviceExtension->base32BitCode +
+ cp->startOffset);
+
+ // Pointer to CAMInterrupt.
+
+ DeviceExtension->interruptPtr =
+ (PVOID)(DeviceExtension->base32BitCode +
+ cp->interruptOffset);
+
+ // Pointer to chsMap.
+
+ DeviceExtension->chsPtr =
+ (PVOID)(DeviceExtension->base32BitCode +
+ cp->chsOffset);
+
+ // Increment HBA count.
+ hwInfo->hbaCount++;
+
+ return SP_RETURN_FOUND;
+
+} // End FindCore
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// InitPath
+//
+// Initializes the CAMCore after it is found by FindCore.
+// Sets up CAMCore globals.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+VOID
+InitPath(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+{
+ PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
+
+ DebugPrint(( 1, "NCR SDMS: InitPath \n"));
+
+ noncachedExtension->CoreGlobals.CoreInitialized = 0;
+
+ // Call CAMInit. Delays for hardware to reset are in the CAMcore.
+ (*DeviceExtension->initPtr)(&noncachedExtension->CoreGlobals);
+
+ // Tell the port driver the bus has been reset.
+ ScsiPortNotification( ResetDetected, DeviceExtension, DeviceExtension->scsiBusId );
+
+ DebugPrint(( 1, "NCR SDMS: InitPath ...after CAMInit \n"));
+
+} // End InitPath
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// NCRHwInitialize
+//
+// This routine is called by the OS specific port driver
+// when the host bus adapter needs to be initialized
+// after a boot or a power failure. This routine only
+// needs to initialize the hardware host bus adapter
+// but should avoid resetting the SCSI bus.
+//
+// Arguments:
+//
+// DeviceExtension - supplies the HBA miniport driver's
+// storage for adapter data.
+//
+// Returns TRUE or FALSE.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+BOOLEAN
+NCRHwInitialize(
+ IN PVOID HwDeviceExtension
+ )
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
+
+ DebugPrint(( 1, "NCR SDMS: NCRHwInitialize \n"));
+
+ // Don't reset SCSI bus.
+ noncachedExtension->CoreGlobals.config_info |=
+ CORHDR_DO_NOT_RESET_SCSI_BUS;
+
+ // Call CAMInit in CAMcore to reset and initialize the SCSI chip
+ // and CoreGlobals. Delays for hardware to reset are in the CAMcore.
+ InitPath( DeviceExtension );
+
+ noncachedExtension->CoreGlobals.config_info &=
+ !(CORHDR_DO_NOT_RESET_SCSI_BUS);
+
+ DebugPrint(( 1, "NCR SDMS: NCRHwInitialize ...exiting\n"));
+
+ return TRUE;
+
+} // End NCRHwInitialize
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// NCRResetBus
+//
+/////////////////////////////////////////////////////////////////////////////
+
+BOOLEAN
+NCRResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
+
+ DebugPrint(( 1, "NCR SDMS: NCRResetBus \n" ));
+
+ // Calls CAMInit routine in CAMcore to Reset SCSI Bus
+ // and initialize CoreGlobals.
+ noncachedExtension->CoreGlobals.config_info &=
+ !(CORHDR_DO_NOT_RESET_SCSI_BUS);
+
+
+ DebugPrint(( 2, "NCR SDMS: NCRResetBus ...entering InitPath\n"));
+
+ // Call CAMInit. Delays for hardware to reset are in the CAMcore.
+ InitPath( DeviceExtension );
+
+ DebugPrint(( 2, "NCR SDMS: NCRResetBus ...after InitPath\n"));
+
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET
+ ScsiPortCompleteRequest( DeviceExtension,
+ (UCHAR)PathId,
+ 0xFF,
+ 0xFF,
+ SRB_STATUS_BUS_RESET );
+
+ DebugPrint(( 2, "NCR SDMS: NCRResetBus ...complete\n"));
+
+ return TRUE;
+
+} // End NCRResetBus
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// NCRStartIo
+//
+////////////////////////////////////////////////////////////////////////////
+
+BOOLEAN
+NCRStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
+ PROMscsiCCB pROMCcb = Srb->SrbExtension;
+
+ DebugPrint(( 1, "NCR SDMS: NCRStartIo \n"));
+
+ switch ( Srb->Function )
+ {
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ // For SDMS V1.6, reject all LUNs except zero. The
+ // version cannot handle the LUNs.
+ if ( ( DeviceExtension->SdmsVersion == SDMS_V16 ) &&
+ ( Srb->Lun != 0x00 ) )
+ {
+ Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+
+ DebugPrint((3, "NCR SDMS: StartIO ...LUN %d aborted\n",
+ Srb->Lun ));
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb);
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL);
+ return TRUE;
+ }
+
+ BuildCCBFromSRB( DeviceExtension, Srb );
+
+ // If BuildCCBFromSRB was unsuccessful, it will set the
+ // SRB Status field to indicate that the I/O request should
+ // be aborted.
+ if ( Srb->SrbStatus == SRB_STATUS_ABORTED)
+ {
+ DebugPrint(( 3, "NCR SDMS: StartIO ...abort request\n"));
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb);
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL);
+ return TRUE;
+ }
+
+ DebugPrint(( 2, "NCR SDMS: StartIO ...call CAMStart \n"));
+
+ // Call CAMstart
+ ( *DeviceExtension->startPtr )
+ ( &noncachedExtension->CoreGlobals,
+ Srb->SrbExtension );
+
+ DebugPrint(( 2, "NCR SDMS: StartIO ...back from CAMStart \n"));
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint(( 3, "NCR SDMS: NCRStartIo ...Abort command received \n"));
+
+ // Abort not supported --- once CAMstart is called with a valid
+ // CCB it can't be aborted unless a reset is done.
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb);
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL);
+ return TRUE;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ if ( !NCRResetBus( DeviceExtension, Srb->PathId) )
+ {
+
+ DebugPrint(( 3, "NCR SDMS: NCRStartIo ...Reset Bus failed \n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ }
+ else
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb);
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL);
+ return TRUE;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ DebugPrint(( 3, "NCR SDMS: NCRStartIo ...Reset device not supported. \n"));
+
+ // Reset device not supported. drop through to default.
+
+ // Return bad function SRB status for unsupported functions.
+ default:
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb);
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL);
+ return TRUE;
+ break;
+
+ } // End switch
+
+ return TRUE;
+
+} // End NCRStartIo
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// BuildCCBFromSRB
+//
+// Translates the NT I/O request data structure (Srb) into a
+// SDMS CAMcore I/O data structure (CCB).
+//
+/////////////////////////////////////////////////////////////////////////////
+
+VOID
+BuildCCBFromSRB(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+{
+
+ PROMscsiCCB pROMCcb = Srb->SrbExtension;
+ ULONG i;
+ ULONG Length;
+
+ DebugPrint(( 1, "NCR SDMS: BuildCCBFromSRB \n"));
+
+ // Zero out the CCB storage area.
+ for ( i = 0; i < sizeof(ROMscsiCCB); i++)
+ ((PUCHAR)pROMCcb)[i] = 0;
+
+ // Save the SRB address in the CCB
+ pROMCcb->SCSIReq.PeripheralPtr = (ULONG)Srb;
+
+ pROMCcb->SCSIReq.Header.CCBLength = sizeof( SCSIRequestCCB );
+ pROMCcb->SCSIReq.Header.FunctionCode = FUNC_EXECUTE_SCSI_IO;
+ pROMCcb->SCSIReq.Header.CAMStatus = STAT_REQUEST_IN_PROGRESS;
+ pROMCcb->SCSIReq.Header.SCSIStatus = 0;
+ pROMCcb->SCSIReq.Header.PathID = Srb->PathId;
+
+ if ( Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE )
+ pROMCcb->SCSIReq.Header.CAMFlags |= CAM_QUEUE_ACTION_SPECIFIED;
+
+ if ( Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT )
+ pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DO_NOT_ALLOW_DISCONNECT;
+
+ if ( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER )
+ pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DISABLE_SYNC_TRAN;
+
+ // Disable auto request sense
+ pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DISABLE_AUTOSENSE;
+
+ // Don't check this now because we don't currently support autosense.
+ // if ( Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE )
+ // pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DISABLE_AUTOSENSE;
+
+ if ( Srb->SrbFlags & SRB_FLAGS_DATA_IN )
+ pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DIR_DATA_IN;
+ else if ( Srb->SrbFlags & SRB_FLAGS_DATA_OUT )
+ pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DIR_DATA_OUT;
+ else
+ pROMCcb->SCSIReq.Header.CAMFlags |= CAM_DIR_NO_DATA;
+
+ // SRB_FLAGS not supported
+ //
+ // SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x00000010
+ // SRB_FLAGS_NO_QUEUE_FREEZE 0x00000100
+ // SRB_FLAGS_ADAPTER_CACHE_ENABLE 0x00000200
+ // SRB_FLAGS_IS_ACTIVE 0x00010000
+ // SRB_FLAGS_ALLOCATED_FROM_ZONE 0x00020000
+
+ pROMCcb->SCSIReq.TargetID = Srb->TargetId;
+ pROMCcb->SCSIReq.LUN = Srb->Lun;
+ pROMCcb->SCSIReq.Queue_Action = Srb->QueueAction;
+
+ // Following field has no SRB equivalent.
+ // pROMCcb->SCSIReq.VendorFlags = xxx;
+
+ (UCHAR)pROMCcb->SCSIReq.CDBLength = Srb->CdbLength;
+ (UCHAR)pROMCcb->ROMFields.CDBLength = Srb->CdbLength;
+ (UCHAR)pROMCcb->SCSIReq.SenseLength = Srb->SenseInfoBufferLength;
+
+ // No SRB equivalent -- already set to zero.
+ // pROMCcb->SCSIReq.MessageLength = 0;
+
+ // Set Scatter/Gather list length to zero.
+ pROMCcb->SCSIReq.SGListLength = 0;
+
+ // Set data length to SRB data length.
+ pROMCcb->SCSIReq.DataLength = Srb->DataTransferLength;
+
+ pROMCcb->SCSIReq.TimeOut = Srb->TimeOutValue;
+
+ // Unique fields added to end of CAM CCB for CAMcore code.
+ // This is here probably because some core at some time
+ // under a specific operating system needed physical as
+ // well as virtual addresses.
+ // This should be removed from SDMS 3.0.
+
+ pROMCcb->SCSIReq.DataPtr = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ Srb,
+ Srb->DataBuffer,
+ &Length));
+
+ // If available memory not enough for data buffer, set the
+ // Srb Status field to ABORT and NCRStartIo will handle
+ // aborting the request.
+ if ( Length < Srb->DataTransferLength )
+ {
+ DebugPrint(( 2, "NCR SDMS: BuildCCBFromSrb ...Phys buffer length < SRB->DataTransferLength \n" ));
+ DebugPrint(( 2, " Physical Buffer Length = 0x%lx\n",
+ Length));
+ DebugPrint(( 2, " SRB Data Transfer Length = 0x%lx\n",
+ Srb->DataTransferLength));
+
+ Srb->SrbStatus = SRB_STATUS_ABORTED;
+
+ return;
+ }
+
+ pROMCcb->ROMFields.DataPhys = pROMCcb->SCSIReq.DataPtr;
+
+ // Setup data buffer virtual address.
+
+ pROMCcb->ROMFields.DataVirt = (ULONG)Srb->DataBuffer;
+
+ // Since AutoSense is disabled, set the sense buffers to zero.
+ pROMCcb->SCSIReq.SensePtr = 0;
+ pROMCcb->ROMFields.SensePhys = 0;
+
+ // Setup virtual address of Sense buffer.
+ pROMCcb->ROMFields.SenseVirt = (ULONG)Srb->SenseInfoBuffer;
+
+ // Following fields have already been cleared when CCB zeroed.
+ // They have no SRB equivalent.
+
+ // pROMCcb->SCSIReq.MessagePtr = 0;
+ // pROMCcb->SCSIReq.LinkPtr = 0;
+ // pROMCcb->SCSIReq.PeripheralPtr = 0;
+ // pROMCcb->SCSIReq.CallBackPtr[0] = 0;
+ // pROMCcb->SCSIReq.CallBackPtr[1] = 0;
+ // pROMCcb->SCSIReq.CallBackPtr[2] = 0;
+
+ // Copy the SRB CDB to the CCB CDB (and ROMFields CCB)
+ for ( i=0; i<Srb->CdbLength; i++) {
+ pROMCcb->SCSIReq.CDB[i] = Srb->Cdb[i];
+ pROMCcb->ROMFields.CDB[i] = Srb->Cdb[i];
+ }
+
+ DebugPrint(( 2, "NCR SDMS: BuildCCBFromSRB ...return \n"));
+
+} // End BuildCCBFromSRB
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// NCRInterrupt
+//
+// Return value:
+// TRUE -- interrupt belonged to this HBA.
+// FALSE -- interrupt did not belong to this HBA.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+BOOLEAN
+NCRInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension = DeviceExtension->NoncachedExtension;
+
+ ULONG returnValue; // Return value from CAMInterrupt
+ ULONG newReturnValue;
+
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSIRequestCCB pScsiRequestCcb;
+
+ // Leave the debug level at 3 in case we have to debug the
+ // NTLDR program.
+ DebugPrint(( 3, "NCR SDMS: NCRInterrupt \n"));
+
+ // Tell the Core that this was a true interrupt from NT.
+ noncachedExtension->CoreGlobals.GlobalFlags |= GLOBAL_FLAGS_TRUE_INT;
+
+ // Call CAMInterrupt
+
+ returnValue = ( *DeviceExtension->interruptPtr )(&noncachedExtension->CoreGlobals);
+
+ // Set the flag to tell the Core the driver is calling again
+ // for interrupt servicing.
+ noncachedExtension->CoreGlobals.GlobalFlags &= ~GLOBAL_FLAGS_TRUE_INT;
+
+ // Leave the debug level at 3 in case we have to debug the
+ // NTLDR program.
+ DebugPrint(( 3, "NCR SDMS: NCRInterrupt ...after CAMInterrupt\n"));
+
+ // If CAMInterrupt returns 0, interrupt was not ours. Signal
+ // this fact to NT. If CAMInterrupt returns any other value,
+ // the interrupt was ours.
+ if (returnValue == 0)
+ {
+ // Leave the debug level at 3 in case we have to debug
+ // the NTLDR program.
+ DebugPrint(( 3, "NCR SDMS: NCRInterrupt ...not our interrupt \n"));
+ return FALSE;
+ }
+
+ // Return value of "1" or "2" indicates the interrupt was ours, but
+ // no other action occurred (i.e. the CCB is still outstanding).
+ // Poll CAMInterrupt until the CCB is complete.
+
+ // Return value of "1" indicates the interrupt was ours, but we
+ // must wait for NT to call us again.
+ if( returnValue == 1 )
+ return TRUE;
+
+ // Save the original return value from CAMInterrupt.
+ newReturnValue = returnValue;
+
+ while ( newReturnValue >= 2 )
+ {
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...return value >= 2 \n"));
+ newReturnValue = ( *DeviceExtension->interruptPtr )(&noncachedExtension->CoreGlobals);
+
+ // If return value is greater than "2", this is a pointer
+ // to our CCB.
+ if ( newReturnValue > 2 )
+ returnValue = newReturnValue;
+ }
+
+ // If return value greater than "2", we tell NT that the
+ // interrupt was ours and wait for NT to call us again.
+ // If the inner loop (above) returned a "1" or "2", then the
+ // orignal value will still be "2".
+ if( returnValue == 2 )
+ return TRUE;
+
+ // CAMInterrupt returns the CCB that was serviced.
+ pScsiRequestCcb = (PSCSIRequestCCB)returnValue;
+
+ // Get the SRB from the CCB.
+ Srb = (PSCSI_REQUEST_BLOCK)pScsiRequestCcb->PeripheralPtr;
+
+ // Translate the CAM Status Flag to a SRB Status Flag.
+
+ // Update SCSI status (only if it is equal to 0x02).
+ if ( (UCHAR)pScsiRequestCcb->Header.SCSIStatus == 0x02 )
+ Srb->ScsiStatus = (UCHAR)pScsiRequestCcb->Header.SCSIStatus;
+
+ // Print the Data Length information.
+ DebugPrint(( 3, "NCR SDMS: NCRInterrupt ...CCB Data Length = 0x%lx\n",
+ (ULONG)pScsiRequestCcb->DataLength));
+
+ DebugPrint(( 3, "NCR SDMS: NCRInterrupt ...SRB Data Length = 0x%lx\n",
+ (ULONG)Srb->DataTransferLength));
+
+ switch ( (UCHAR)pScsiRequestCcb->Header.CAMStatus )
+ {
+
+ case STAT_REQUEST_IN_PROGRESS:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_PENDING;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_PENDING\n"));
+ return TRUE; // Current SRB is not completed.
+ break;
+
+ case STAT_REQUEST_DONE_NO_ERROR:
+
+ // Update the data length -- SDMS 1.6 only. SDMS 3.0 uses
+ // a different data field for residual count. The CCB
+ // data length will be zero if all data transferred.
+ // If the value is non-zero, this is the number of bytes
+ // NOT transferred.
+
+ if ((ULONG)pScsiRequestCcb->DataLength > 0)
+ {
+ Srb->DataTransferLength = (ULONG)pScsiRequestCcb->DataLength;
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_DATA_OVERRUN;
+ }
+ else
+ {
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_SUCCESS;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_SUCCESS\n"));
+ }
+
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...Adjusted SRB Data Length = 0x%x\n",
+ (ULONG)Srb->DataTransferLength));
+ break;
+
+ case STAT_ABORTED_BY_HOST:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_ABORTED;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ABORTED\n"));
+ break;
+
+ case STAT_UNABLE_TO_ABORT:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_ABORT_FAILED;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ABORT_FAILED\n"));
+ break;
+
+ case STAT_COMPLETE_WITH_ERROR:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_ERROR;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ERROR\n"));
+ break;
+
+ // Ask for another SRB???
+ case STAT_CAM_BUSY:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_BUSY;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BUSY\n"));
+ break;
+
+ case STAT_INVALID_REQUEST:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_INVALID_REQUEST;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_INVALID REQUEST\n"));
+ break;
+
+ case STAT_INVALID_PATH_ID:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_INVALID_PATH_ID;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_INVALID_PATH_ID\n"));
+ break;
+
+ case STAT_SCSI_DEVICE_NOT_INSTALLED:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_NO_DEVICE;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_NO_DEVICE\n"));
+ break;
+
+ case STAT_WAIT_FOR_TIMEOUT:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_TIMEOUT;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_TIMEOUT\n"));
+ break;
+
+ case STAT_SELECTION_TIMEOUT:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_SELECTION_TIMEOUT;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_SELECTION_TIMEOUT\n"));
+ break;
+
+ case STAT_COMMAND_TIMEOUT:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_COMMAND_TIMEOUT;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_COMMAND_TIMEOUT \n"));
+ break;
+
+ // Ask for another SRB ??
+ case STAT_SCSI_BUS_BUSY: // No equivalent SRB Flag
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_BUSY;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BUSY \n"));
+ return TRUE; // Current SRB not complete
+ break;
+
+ case STAT_MESSAGE_REJECT_RECIEVED:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_MESSAGE_REJECTED;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_MESSAGE_REJECTED \n"));
+ break;
+
+ case STAT_SCSI_BUS_RESET:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_BUS_RESET;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BUS_RESET \n"));
+ // Notify port driver of SCSI Reset
+ ScsiPortNotification( ResetDetected,
+ DeviceExtension,
+ Srb->PathId);
+ return TRUE;
+
+ break;
+
+ case STAT_UNCORRECTED_PARITY_ERROR:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_PARITY_ERROR;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_PARITY_ERROR \n"));
+ break;
+
+ case STAT_REQUEST_SENSE_FAILED:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_REQUEST_SENSE_FAILED;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_SENSE_FAILED \n"));
+ break;
+
+ case STAT_NO_HBA_DETECTED_ERROR:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_NO_HBA;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_NO_HBA \n"));
+ break;
+
+ case STAT_DATA_OVERRUN_OR_UNDERRUN:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_DATA_OVERRUN;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_DATA_OVERRUN \n"));
+ break;
+
+ case STAT_UNEXPECTED_BUS_FREE:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_UNEXPECTED_BUS_FREE;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_UNEXPECTED_BUS_FREE \n"));
+ break;
+
+ case STAT_PHASE_SEQUENCE_FAILURE:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_PHASE_SEQUENCE_FAILURE \n"));
+ break;
+
+ case STAT_CCB_LENGTH_INADEQUATE:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_BAD_SRB_BLOCK_LENGTH;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BAD_SRB_BLOCK_LENGTH \n"));
+ break;
+
+ case STAT_CANNOT_PROVIDE_CAPABILITY: // No equivalent SRB Flag
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_ERROR;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ERROR \n"));
+ break;
+
+ case STAT_INVALID_LUN:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_INVALID_LUN;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_INVALID_LEN \n"));
+ break;
+
+ case STAT_INVALID_TARGET_ID:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_INVALID_TARGET_ID;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_INALID_TARGET_ID \n"));
+ break;
+
+ case STAT_FUNCTION_NOT_IMPLEMENTED:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_BAD_FUNCTION;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_BAD_FUNCTION \n"));
+ break;
+
+ // The following CAM Status flags have no SRB equivalent.
+
+ case STAT_NEXUS_NOT_ESTABLISHED:
+ case STAT_INVALID_INTIATOR_ID:
+ case STAT_INVALID_DATA_BUFFER:
+ case STAT_NO_CAM_PRESENT:
+ case STAT_GENERAL_FAILURE:
+ default:
+ Srb->SrbStatus = (UCHAR)SRB_STATUS_ERROR;
+ DebugPrint(( 2, "NCR SDMS: NCRInterrupt ...SRB_STATUS_ERROR \n"));
+ break;
+
+ } // End CAMStatus switch
+
+ // Notify the SCSI Port driver that this SRB is complete.
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb );
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL );
+
+ // Indicate that the interrupt was ours.
+ return TRUE;
+
+} // End NCRInterrupt
+
+#else // not i386
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+{
+ return SP_RETURN_NOT_FOUND;
+} // DriverEntry
+
+#endif // i386
+
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.h b/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.h
new file mode 100644
index 000000000..198f1822d
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.h
@@ -0,0 +1,109 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 1992 NCR Corporation
+//
+// NCRSDMS.H
+//
+// This is the include file for the Windows NT NCR MiniPort driver for
+// all NCR CAMcores.
+//
+// Revisions:
+//
+//
+// Note: Search for the word "future" for things that may need to
+// be upgraded for SDMS 3.0 or to support other enhanced
+// features.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#define SDMS_V16 2
+#define SDMS_V30 3
+
+#define MAX_NT_HBAS 2
+#define MAX_32BIT_SIZE 12288
+
+#define FIRST_ROM_ADDRESS 0x0C0000
+#define LAST_ROM_ADDRESS 0x100000
+#define ROM_CHECK_STEP 0x800
+
+#define ROM_SIZE 0x8000
+#define ROM_ADDRESS_SPACE_SIZE 0x40000
+
+#define MAGIC_STR_1 { 0x42, 0x41, 0x4C, 0x4C, 0x41, 0x52, 0x44, 0x5F, \
+ 0x53, 0x59, 0x4E, 0x45, 0x52, 0x47, 0x59, 0x5F, \
+ 0x52, 0x4F, 0x4D, 0x5F, 0x53, 0x00 }
+
+
+typedef struct
+{
+ ULONG currentRomAddr;
+ ULONG scsiBusId;
+ PVOID romAddrSpace;
+ PVOID currentVirtAddr;
+ ULONG hbaCount;
+} HWInfo, *PHWInfo;
+
+typedef struct
+{
+ ushort sig; // 00
+ ushort sizeRem; // 02
+ ushort sizeQuo; // 04
+ ushort numReloc; // 06
+ ushort headSize; // 08
+ ushort minData; // 0A
+ ushort maxData; // 0C
+ ushort initialESP[2]; // 0E
+ ushort checksum; // 12
+ ushort initialEIP[2]; // 14
+ ushort relocOffset; // 18
+ ushort overlay; // 1A
+ ushort ooo1; // 1C
+} REXHeader;
+
+#define MARK_55 0x00
+#define MARK_AA 0x01
+
+#define ROM_TYPE_1 0x0C
+#define ROM_TYPE_2 0x0D
+
+#define CORE_VERSION 0x71
+
+#define CHIP_PHYS 0x73
+#define CHIP_OFFSET 0x77
+
+#define RAM_OFFSET 0x7b
+
+#define ROM_SIM_STR 0x55
+
+#define REX_OFFSET 0x89
+
+#define gByte(base,offset) (*(unsigned char *)((base)+(offset)))
+#define gWord(base,offset) (*(unsigned short *)((base)+(offset)))
+#define gLong(base,offset) (*(unsigned long *)((base)+(offset)))
+
+
+#define AccessRangeROMIndex 0
+#define AccessRangeChipIndex 1
+#define AccessRangeLocalRAMIndex 2 // If local memory on HBA
+
+typedef struct
+{
+ ulong future[8]; // 00
+ ulong initOffset; // 20
+ ulong startOffset; // 24
+ ulong interruptOffset; // 26
+ ulong chsOffset; // 28
+} CAM32Header;
+
+////////////////////////////////////////////////////////////////////////////
+// Scatter/Gather List definitions
+////////////////////////////////////////////////////////////////////////////
+
+#define MAX_SG_BRKS 16
+
+typedef struct _SGL {
+ SGListEntry SgEntry[MAX_SG_BRKS];
+} SGL, *PSGL;
+
+
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.rc b/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.rc
new file mode 100644
index 000000000..983c7e85b
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/ncrsdms.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "NCR MPD SCSI MiniPort Driver"
+#define VER_INTERNALNAME_STR "ncrmport.sys"
+#define VER_ORIGINALFILENAME_STR "ncrmport.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/sources b/private/ntos/miniport/scsiwdl/ncrcam/sources
new file mode 100644
index 000000000..c038ea086
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/sources
@@ -0,0 +1,36 @@
+!IF 0
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=ncrcam
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=ncrsdms.c ncrsdms.rc
diff --git a/private/ntos/miniport/scsiwdl/ncrcam/typedefs.h b/private/ntos/miniport/scsiwdl/ncrcam/typedefs.h
new file mode 100644
index 000000000..14ba81804
--- /dev/null
+++ b/private/ntos/miniport/scsiwdl/ncrcam/typedefs.h
@@ -0,0 +1,30 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 1992 NCR Corporation
+//
+// TYPEDEFS.H
+//
+// Revisions:
+//
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef TYPEDEFS_H
+#define TYPEDEFS_H
+
+#ifdef _32bit
+#define far
+#endif
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+typedef unsigned long (*pfl)();
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef MK_FP
+#define MK_FP(seg,ofs) ((void far *)(((unsigned long)(seg)<<16)|(ofs)))
+#endif
+
+#endif
diff --git a/private/ntos/miniport/spock/makefile b/private/ntos/miniport/spock/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/spock/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/spock/mca.h b/private/ntos/miniport/spock/mca.h
new file mode 100644
index 000000000..77ceb4d2f
--- /dev/null
+++ b/private/ntos/miniport/spock/mca.h
@@ -0,0 +1,245 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ mca.h
+
+Abstract:
+
+ This is the include file for the IBM MCA SCSI adapter drivers.
+
+Author:
+
+ Mike Glass (mglass)
+
+Notes:
+
+Revision History:
+
+--*/
+
+#define MAXIMUM_SDL_SIZE 16
+
+//
+// Termination Status Block
+//
+
+typedef struct _TSB {
+ USHORT ScbStatus;
+ USHORT Reserved;
+ ULONG ResidualByteCount;
+ PVOID SgDescriptorAddress;
+ USHORT DeviceStatusLength;
+ UCHAR DeviceStatus;
+ UCHAR CommandStatus;
+ UCHAR DeviceError;
+ UCHAR CommandError;
+ ULONG Reserved2;
+ PVOID ScbAddress;
+} TSB, *PTSB;
+
+//
+// TSB End Status
+//
+
+#define TSB_STATUS_NO_ERROR 0x0000
+#define TSB_STATUS_SHORT_RECORD 0x0002
+#define TSB_STATUS_INVALID_COMMAND 0x0004
+#define TSB_STATUS_SCB_REJECTED 0x0008
+#define TSB_STATUS_SCB_SPECIFIC_CHECK 0x0010
+#define TSB_STATUS_LONG_RECORD 0x0020
+#define TSB_STATUS_SCB_HALTED 0x0040
+#define TSB_STATUS_SCB_INTERRUPT_QUEUED 0x0080
+#define TSB_STATUS_ADDITIONAL_STATUS 0x0100
+#define TSB_STATUS_DEVICE_STATUS 0x0200
+#define TSB_STATUS_DEVICE_NOT_INIT 0x0800
+#define TSB_STATUS_MAJOR_EXCEPTION 0x1000
+
+//
+// TSB Command Error Codes
+//
+
+#define TSB_COMMAND_ERROR_DEVICE_NOT_ASSIGNED 0x0A
+
+//
+// Scatter/Gather Descriptor and List
+//
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Address;
+ ULONG Length;
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+typedef struct _SDL {
+ SG_DESCRIPTOR Descriptor[MAXIMUM_SDL_SIZE];
+} SDL, *PSDL;
+
+//
+// Subsystem Control Block
+//
+
+typedef struct _SCB {
+
+ USHORT Command;
+ USHORT EnableFlags;
+ USHORT CdbSize;
+ USHORT Reserved;
+ ULONG BufferAddress;
+ ULONG BufferLength;
+ ULONG StatusBlock;
+ struct _SCB *NextScb;
+ UCHAR Cdb[12];
+ TSB Tsb;
+ SDL Sdl;
+ PVOID SrbAddress;
+
+} SCB, *PSCB;
+
+//
+// SCB Commands
+//
+
+#define SCB_COMMAND_ABORT 0x040F
+#define SCB_COMMAND_ASSIGN 0x000E
+#define SCB_COMMAND_INQUIRY 0x000B
+#define SCB_COMMAND_DMA_CONTROL 0x000D
+#define SCB_COMMAND_FEATURE_CONTROL 0x040C
+#define SCB_COMMAND_FORMAT_PREPARE 0x0017
+#define SCB_COMMAND_FORMAT 0x0016
+#define SCB_COMMAND_GET_STATUS 0x0007
+#define SCB_COMMAND_GET_POS 0x1c0a
+#define SCB_COMMAND_READ 0x0001
+#define SCB_COMMAND_READ_CAPACITY 0x1c09
+#define SCB_COMMAND_READ_VERIFY 0x0003
+#define SCB_COMMAND_REASSIGN_BLOCK 0x0018
+#define SCB_COMMAND_REQUEST_SENSE 0x0008
+#define SCB_COMMAND_RESET 0x0400
+#define SCB_COMMAND_SEND_SCSI 0x241F
+#define SCB_COMMAND_WRITE 0x0002
+#define SCB_COMMAND_WRITE_VERIFY 0x0004
+
+//
+// SCB Command Masks
+//
+
+#define SCB_NO_DISCONNECT 0x0080
+#define SCB_NO_SYNCHRONOUS_TRANSFER 0x0040
+
+//
+// SCB Enable Options Masks
+//
+
+#define SCB_ENABLE_WRITE 0x0000
+#define SCB_ENABLE_READ 0x8000
+#define SCB_ENABLE_TSB_ON_ERROR 0x4000
+#define SCB_ENABLE_RETRY_ENABLE 0x2000
+#define SCB_ENABLE_SG_LIST 0x1000
+#define SCB_ENABLE_SHORT_TRANSFER 0x0400
+#define SCB_ENABLE_BYPASS_BUFFER 0x0200
+#define SCB_ENABLE_CHAINING 0x0100
+
+//
+// SCB Command Status
+//
+
+#define SCB_STATUS_SUCCESS 0x01
+#define SCB_STATUS_SUCCESS_WITH_RETRIES 0x05
+#define SCB_STATUS_ADAPTER_FAILED 0x07
+#define SCB_STATUS_IMMEDIATE_COMMAND_COMPLETE 0x0A
+#define SCB_STATUS_COMMAND_COMPLETE_WITH_FAILURE 0x0C
+#define SCB_STATUS_COMMAND_ERROR 0x0E
+#define SCB_STATUS_SOFTWARE_SEQUENCING_ERROR 0x0F
+
+//
+// SCB Device Status
+//
+
+#define SCB_DEV_STATUS_GOOD 0x00
+#define SCB_DEV_STATUS_CHECK_CONDITION 0x01
+#define SCB_DEV_STATUS_CONDITION_MET 0x02
+#define SCB_DEV_STATUS_BUSY 0x04
+#define SCB_DEV_STATUS_INTERMEDIATE_GOOD 0x08
+#define SCB_DEV_STATUS_INTERMEDIATE_CONDITION_MET 0x0A
+#define SCB_DEV_STATUS_RESERVATION_CONFLICT 0x0C
+
+//
+// MCA SCSI Adapter Registers
+//
+
+typedef struct _MCA_REGISTERS {
+ ULONG CommandInterface;
+ UCHAR Attention;
+ UCHAR BaseControl;
+ UCHAR InterruptStatus;
+ UCHAR BasicStatus;
+} MCA_REGISTERS, *PMCA_REGISTERS;
+
+//
+// Attention Register Request Codes
+//
+
+#define IMMEDIATE_COMMAND 0x10
+#define START_SCB 0x30
+#define START_LONG_SCB 0x40
+#define END_OF_INTERRUPT 0xE0
+
+//
+// Basic Control Register
+//
+
+#define INTERRUPT_ENABLE 0x01
+#define DMA_ENABLE 0x02
+#define HARDWARE_RESET 0x80
+
+//
+// Basic Status Register
+//
+
+#define BASIC_STATUS_BUSY 0x01
+#define BASIC_STATUS_INTERRUPT 0x02
+#define BASIC_STATUS_CI_EMPTY 0x04
+#define BASIC_STATUS_CI_FULL 0x08
+
+#define MAXIMUM_DATA_TRANSFER (16 * 1024 * 1024) - 1
+
+//
+// Disk Activity Light Macros
+//
+
+#define DISK_ACTIVITY_LIGHT_ON() { \
+ UCHAR portContents; \
+ portContents = ScsiPortReadPortUchar((PUCHAR)0x92); \
+ portContents |= 0x40; \
+ ScsiPortWritePortUchar((PUCHAR)0x92, portContents); \
+}
+
+#define DISK_ACTIVITY_LIGHT_OFF() { \
+ UCHAR portContents; \
+ portContents = ScsiPortReadPortUchar((PUCHAR)0x92); \
+ portContents &= ~0x40; \
+ ScsiPortWritePortUchar((PUCHAR)0x92, portContents); \
+}
+
+//
+// POS and Adapter Information
+//
+
+typedef struct _ADAPTER_INFORMATION {
+ USHORT AdapterId;
+ UCHAR PosRegister3;
+ UCHAR PosRegister2;
+ UCHAR PosRegister4;
+ UCHAR InterruptLevel;
+ USHORT RevisionLevel:12;
+ USHORT ChannelConnector:4;
+ UCHAR NumberOfDevicesSupported;
+ UCHAR NumberOfLogicalUnitsSupported;
+ UCHAR NumberOfLogicalDevicesSupported;
+ UCHAR DmaPacingFactor;
+ UCHAR MaximumAdapterBusyTime;
+ UCHAR EoiToInterruptOffTime;
+ USHORT Reserved;
+ USHORT DisableRetryDeviceBitMap;
+} ADAPTER_INFORMATION, *PADAPTER_INFORMATION;
diff --git a/private/ntos/miniport/spock/sources b/private/ntos/miniport/spock/sources
new file mode 100644
index 000000000..48b03ea65
--- /dev/null
+++ b/private/ntos/miniport/spock/sources
@@ -0,0 +1,36 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+TARGETNAME=spock
+
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=spock.c spock.rc
+
+INCLUDES=..\..\inc
diff --git a/private/ntos/miniport/spock/spock.c b/private/ntos/miniport/spock/spock.c
new file mode 100644
index 000000000..fbcad5932
--- /dev/null
+++ b/private/ntos/miniport/spock/spock.c
@@ -0,0 +1,2150 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ spock.c
+
+Abstract:
+
+ This is the NT SCSI miniport driver for the IBM MCA SCSI adapter.
+
+Author:
+
+ Mike Glass
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+#include "miniport.h"
+#include "mca.h"
+#include "scsi.h"
+
+#define MAXIMUM_ERRORS 10
+
+//
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//
+
+CONST ULONG AdapterAddresses[] = {0X3540, 0X3548, 0X3550, 0X3558,
+ 0X3560, 0X3568, 0x3570, 0x3578, 0};
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ //
+ // Adapter parameters
+ //
+
+ PMCA_REGISTERS Registers;
+
+ //
+ // Disk activity light count
+ //
+
+ ULONG ActiveRequests;
+
+ ULONG ErrorCount;
+
+ UCHAR HostTargetId;
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+//
+// Logical unit extension
+//
+
+typedef struct _HW_LOGICAL_UNIT {
+
+ PSCB Scb;
+ PSCSI_REQUEST_BLOCK AbortSrb;
+ PSCSI_REQUEST_BLOCK CurrentSrb;
+
+} HW_LOGICAL_UNIT, *PHW_LOGICAL_UNIT;
+
+//
+// Noncached version extension.
+//
+
+typedef struct _HW_ADAPTER_INFOMATION {
+ SCB Scb;
+ ADAPTER_INFORMATION AdapterInfo;
+}HW_ADAPTER_INFOMATION, *PHW_ADAPTER_INFOMATION;
+
+
+//
+// Function declarations
+//
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+SpockConfiguration(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+SpockInitialize(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+SpockStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+SpockInterrupt(
+ IN PVOID HwDeviceExtension
+ );
+
+BOOLEAN
+SpockResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+BOOLEAN
+SpockAbortIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+BuildScb(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+BuildSgl(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+BuildReadCapacity(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+ULONG
+McaAdapterPresent(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount,
+ OUT PBOOLEAN Again
+ );
+
+VOID
+MapTsbError(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PTSB Tsb
+ );
+
+BOOLEAN
+IssueScbCommand(
+ IN PVOID DeviceExtension,
+ IN ULONG PhysicalScb,
+ IN UCHAR TargetId
+ );
+
+BOOLEAN
+IssueImmediateCommand(
+ IN PVOID HwDeviceExtension,
+ IN ULONG ImmediateCommand,
+ IN UCHAR TargetId
+ );
+
+
+//
+// Routines start
+//
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object is passed to ScsiPortInitialize()
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG adapterCount;
+ ULONG i;
+
+ DebugPrint((1,"\n\nMCA SCSI Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = SpockInitialize;
+ hwInitializationData.HwFindAdapter = SpockConfiguration;
+ hwInitializationData.HwStartIo = SpockStartIo;
+ hwInitializationData.HwInterrupt = SpockInterrupt;
+ hwInitializationData.HwResetBus = SpockResetBus;
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LOGICAL_UNIT);
+
+ //
+ // Set number of access ranges and bus type..
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = MicroChannel;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Ask for SRB extensions for SCBs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(SCB);
+
+ //
+ // The adapter count is used by McaAdapterPresent routine to track
+ // which adapter addresses have been searched.
+ //
+
+ adapterCount = 0;
+
+ return ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &adapterCount);
+
+} // end DriverEntry()
+
+
+ULONG
+SpockConfiguration(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ Called from ScsiPortInitialize to collect adapter configuration
+ and capability information.
+
+Arguments:
+
+ HwDevice Extension
+ Context - Pointer to adapters initialized count
+ BusInformation
+ ArgumentString - Not used
+ ConfigInfo - Configuration information structure describing HBA
+ Again - Indicates init routine should be called again
+
+Return Value:
+
+ ULONG
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PHW_ADAPTER_INFOMATION adapterInfo;
+ ULONG physicalAdapterInfo;
+ ULONG status;
+ UCHAR basicStatus;
+
+ //
+ // Assume initialization will not need to be called again.
+ //
+
+ *Again = FALSE;
+
+ //
+ // Search for IBM SCSI adapters.
+ //
+
+ status = McaAdapterPresent(HwDeviceExtension,
+ ConfigInfo,
+ Context,
+ Again);
+
+ //
+ // If there are not adapter's found then return.
+ //
+
+ if (status != SP_RETURN_FOUND) {
+ return(status);
+ }
+
+ //
+ // Set IRQ to 14.
+ //
+
+ ConfigInfo->BusInterruptLevel = 14;
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InterruptMode = LevelSensitive;
+ ConfigInfo->InitiatorBusId[0] = 7;
+ deviceExtension->HostTargetId = 7;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->ScatterGather = TRUE;
+
+ //
+ // Indicate maximum transfer length is 16M.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_DATA_TRANSFER;
+
+ //
+ // Maximum number of physical segments is 16.
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SDL_SIZE;
+
+ //
+ // Get an noncached extension for the adapter information.
+ //
+
+ adapterInfo = ScsiPortGetUncachedExtension(HwDeviceExtension,
+ ConfigInfo,
+ sizeof(HW_ADAPTER_INFOMATION));
+
+ if (adapterInfo == NULL) {
+ return SP_RETURN_BAD_CONFIG;
+ }
+
+ physicalAdapterInfo = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(
+ HwDeviceExtension,
+ NULL,
+ adapterInfo,
+ &status));
+
+ if (status == 0 || physicalAdapterInfo == SP_UNINITIALIZED_VALUE) {
+ return SP_RETURN_BAD_CONFIG;
+ }
+
+ //
+ // Disable the adapter interrupt. The interrupts will be enabled
+ // when the adapter is initialized.
+ //
+
+ basicStatus = ScsiPortReadPortUchar(
+ &deviceExtension->Registers->BaseControl);
+
+ basicStatus &= ~INTERRUPT_ENABLE;
+
+ ScsiPortWritePortUchar(&deviceExtension->Registers->BaseControl, basicStatus);
+
+ //
+ // Build a get POS and adapter information command.
+ //
+
+ adapterInfo->Scb.Command = SCB_COMMAND_GET_POS;
+ adapterInfo->Scb.EnableFlags = SCB_ENABLE_READ | SCB_ENABLE_TSB_ON_ERROR |
+ SCB_ENABLE_RETRY_ENABLE | SCB_ENABLE_BYPASS_BUFFER;
+ adapterInfo->Scb.CdbSize = 0;
+ adapterInfo->Scb.Reserved = 0;
+ adapterInfo->Scb.BufferAddress = physicalAdapterInfo +
+ offsetof(HW_ADAPTER_INFOMATION, AdapterInfo);
+ adapterInfo->Scb.BufferLength = sizeof(adapterInfo->AdapterInfo);
+ adapterInfo->Scb.StatusBlock = physicalAdapterInfo +
+ offsetof(HW_ADAPTER_INFOMATION, Scb.Tsb);
+ adapterInfo->Scb.NextScb = NULL;
+
+ if (!IssueScbCommand(HwDeviceExtension, physicalAdapterInfo, 0x0f)) {
+
+ DebugPrint((1, "SpockConfiguration: Could not issue get POS command.\n"));
+
+ //
+ // Assume this is a bad adapter. Force no disconnects for all
+ // requests.
+ //
+
+ deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
+
+ return SP_RETURN_FOUND;
+ }
+
+ //
+ // Wait for the request to complete.
+ //
+
+ for (status = 0; status < 1000; status++) {
+
+ basicStatus = ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus);
+
+ if (basicStatus & BASIC_STATUS_INTERRUPT) {
+ break;
+ }
+
+ ScsiPortStallExecution(10);
+ }
+
+
+ if (!(--deviceExtension->ActiveRequests)) {
+
+ //
+ // Turn disk activity light off.
+ //
+
+ DISK_ACTIVITY_LIGHT_OFF();
+ }
+
+ if (!(basicStatus & BASIC_STATUS_INTERRUPT)) {
+
+ DebugPrint((1, "SpockConfiguration: Get POS command timed out.\n"));
+
+ //
+ // Assume this is a bad adapter. Force no disconnects for all
+ // requests.
+ //
+
+ deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
+ return SP_RETURN_FOUND;
+
+ }
+
+ //
+ // Read interrupt status register to determine
+ // interrupting device and status.
+ //
+
+ basicStatus = ScsiPortReadPortUchar(
+ &deviceExtension->Registers->InterruptStatus);
+
+ //
+ // Acknowledge interrupt.
+ //
+
+ status = 0;
+ while (ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) &
+ BASIC_STATUS_BUSY){
+
+ ScsiPortStallExecution(1);
+
+ if (status++ > 10000) {
+
+ DebugPrint((1, "SpockConfiguration: Wait for non-busy timed out.\n"));
+
+ //
+ // Assume this is a bad adapter. Force no disconnects for all
+ // requests.
+ //
+
+ deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
+ return SP_RETURN_FOUND;
+
+ }
+ }
+
+ ScsiPortWritePortUchar(&deviceExtension->Registers->Attention,
+ (0x0f | END_OF_INTERRUPT));
+
+ //
+ // Bits 4-7 are interrupt status id.
+ //
+
+ status = basicStatus >> 4;
+
+ if (status != SCB_STATUS_SUCCESS &&
+ status != SCB_STATUS_SUCCESS_WITH_RETRIES) {
+
+ DebugPrint((1, "SpockConfiguration: Get POS command failed. Status = %hx\n", status));
+
+ //
+ // Assume this is a bad adapter. Force no disconnects for all
+ // requests.
+ //
+
+ deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
+ return SP_RETURN_FOUND;
+
+ }
+
+ DebugPrint((1, "SpockConfiguration: Retrived data is: %0.4hx\n",adapterInfo->AdapterInfo.RevisionLevel));
+
+ if (adapterInfo->AdapterInfo.RevisionLevel == 0xf) {
+
+ DebugPrint((1, "SpockConfiguration: Found old firmware disabling disconnect!\n"));
+ deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
+
+ //
+ // Log nasty firmware.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_BAD_FW_WARNING,
+ (10 << 16));
+ }
+
+ return SP_RETURN_FOUND;
+
+} // end SpockConfiguration()
+
+
+BOOLEAN
+SpockInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Reset and inititialize Adapter.
+
+Arguments:
+
+ DeviceExtension - Adapter object device extension.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ UCHAR basicStatus;
+
+ //
+ // Issue feature control immediate command to disable
+ // adapter timing of SCBs.
+ //
+
+ if (!IssueImmediateCommand(HwDeviceExtension,
+ (ULONG)SCB_COMMAND_FEATURE_CONTROL,
+ 0x0f)) {
+
+ DebugPrint((1,"SpockInitialize: Set feature control failed\n"));
+ }
+
+ //
+ // Enable the adapter interrupt.
+ //
+
+ basicStatus = ScsiPortReadPortUchar(&deviceExtension->Registers->BaseControl);
+
+ basicStatus |= INTERRUPT_ENABLE;
+
+ ScsiPortWritePortUchar(&deviceExtension->Registers->BaseControl, basicStatus);
+
+ return TRUE;
+
+} // end SpockInitialize()
+
+BOOLEAN
+SpockStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Issue call to build SCB and SDL and write address and
+ command to adapter.
+
+Arguments:
+
+ HwDeviceExtension
+ Srb
+
+Return Value:
+
+ TRUE.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCB scb;
+ ULONG physicalScb;
+ ULONG length;
+ PHW_LOGICAL_UNIT logicalUnit;
+
+ //
+ // Make sure that the request is for a valid SCSI bus and LUN as
+ // the IBM SCSI card does random things if address is wrong.
+ //
+
+ if (Srb->PathId != 0 || Srb->Lun != 0) {
+
+ //
+ // The spock card only supports logical unit zero and one bus.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get logical unit extension.
+ //
+
+ logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Save SRB in logical unit extension.
+ //
+
+ ASSERT(!logicalUnit->CurrentSrb);
+ logicalUnit->CurrentSrb = Srb;
+
+ scb = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in SCB.
+ //
+
+ scb->SrbAddress = Srb;
+
+ //
+ // Get SCB physical address.
+ //
+
+ physicalScb =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, scb, &length));
+
+ //
+ // Assume physical address is contiguous for size of SCB.
+ //
+
+ ASSERT(length >= sizeof(SCB));
+
+ //
+ // Save Scb in logical unit extension.
+ //
+
+ logicalUnit->Scb = scb;
+
+ //
+ // Build SCB.
+ //
+
+ BuildScb(deviceExtension, Srb);
+
+ //
+ // Issue send SCB command to adapter.
+ //
+
+ DebugPrint((2, "BuildSCB: Function %0.4hx LDN %0.4hx \n",
+ Srb->Cdb[0], Srb->TargetId));
+
+ if (!IssueScbCommand(deviceExtension,
+ physicalScb,
+ Srb->TargetId)) {
+
+ //
+ // Fail SRB.
+ //
+
+ DebugPrint((1, "SpockStartIo: IssueScbCommand failed\n"));
+
+ Srb->SrbStatus = SRB_STATUS_TIMEOUT;
+
+ logicalUnit->CurrentSrb = NULL;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ }
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((3,"SpockStartIo: Abort command\n"));
+
+ //
+ // Check to see if SRB to abort is still around.
+ //
+
+ if (!logicalUnit->CurrentSrb) {
+
+ //
+ // Request must of already completed.
+ //
+
+ DebugPrint((1,"SpockStartIo: Srb to abort already complete\n"));
+
+ //
+ // Complete ABORT SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ } else if (!SpockAbortIo(deviceExtension, Srb)) {
+
+ DebugPrint((1,"SpockStartIo: Abort command failed\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ }
+
+ break;
+
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ DebugPrint((1,"SpockStartIo: Invalid SRB request\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ } // end switch
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end SpockStartIo()
+
+
+BOOLEAN
+SpockInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler for the IBM MCA SCSI adapter.
+
+Arguments:
+
+ Device Object
+
+Return Value:
+
+ Returns TRUE if interrupt expected.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PSCB scb;
+ PSCSI_REQUEST_BLOCK srb;
+ UCHAR srbStatus;
+ UCHAR scsiStatus;
+ PTSB tsb;
+ UCHAR status;
+ UCHAR targetId;
+ PHW_LOGICAL_UNIT logicalUnit;
+ ULONG logError = 0;
+ BOOLEAN srbValid = TRUE;
+ ULONG j;
+
+ if (!(ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) &
+ BASIC_STATUS_INTERRUPT)) {
+
+ //
+ // Spurious interrupt.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Read interrupt status register to determine
+ // interrupting device and status.
+ //
+
+ status = ScsiPortReadPortUchar(&deviceExtension->Registers->InterruptStatus);
+
+ //
+ // Bits 0-3 are device id and
+ // bits 4-7 are interrupt id.
+ //
+
+ targetId = status & 0x0F;
+ status = status >> 4;
+
+ //
+ // Acknowledge interrupt.
+ //
+
+ j = 0;
+ while (ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) &
+ BASIC_STATUS_BUSY){
+
+ ScsiPortStallExecution(1);
+
+ if (j++ > 10000) {
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (9 << 16) | status
+ );
+
+ }
+ }
+
+ ScsiPortWritePortUchar(&deviceExtension->Registers->Attention,
+ (UCHAR)(targetId | END_OF_INTERRUPT));
+
+ switch (status) {
+
+ case SCB_STATUS_SUCCESS_WITH_RETRIES:
+ case SCB_STATUS_SUCCESS:
+
+ srbStatus = SRB_STATUS_SUCCESS;
+ scsiStatus = SCSISTAT_GOOD;
+ DebugPrint((2, "Interupt Success: %0.4hx \n",
+ targetId));
+
+ break;
+
+ case SCB_STATUS_IMMEDIATE_COMMAND_COMPLETE:
+
+ if ((targetId & 7) != 7) {
+
+ DebugPrint((1, "SpockInterrupt: Abort command complete\n"));
+
+ //
+ // This is an ABORT command completion.
+ //
+
+
+ logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension,
+ 0,
+ targetId,
+ 0);
+
+ if (logicalUnit == NULL) {
+ break;
+ }
+
+ if (logicalUnit->AbortSrb == NULL) {
+ logicalUnit = NULL;
+ break;
+ }
+
+ //
+ // Get the SRB aborted.
+ //
+
+ srb = logicalUnit->AbortSrb->NextSrb;
+
+ srb->SrbStatus = SRB_STATUS_TIMEOUT;
+
+ //
+ // Remove the aborted SRB from the logical unit.
+ //
+
+ logicalUnit->CurrentSrb = NULL;
+ logicalUnit->Scb = NULL;
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ //
+ // Complete the ABORT SRB.
+ //
+
+ logicalUnit->AbortSrb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ logicalUnit->AbortSrb);
+
+ } else {
+
+ DebugPrint((1,"SpockInterrupt: Immediate command complete\n"));
+ }
+
+ return TRUE;
+
+ case SCB_STATUS_ADAPTER_FAILED:
+ case SCB_STATUS_COMMAND_ERROR:
+ case SCB_STATUS_SOFTWARE_SEQUENCING_ERROR:
+
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+
+ case SCB_STATUS_COMMAND_COMPLETE_WITH_FAILURE:
+
+ DebugPrint((2, "SpockInterrupt: Error\n"));
+
+ srbStatus = SRB_STATUS_ERROR;
+
+ break;
+
+ default:
+
+ srbValid = FALSE;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ return TRUE;
+
+ } // end switch()
+
+ if (srbValid) {
+
+ //
+ // Get SCB address from logical unit extension.
+ //
+
+ logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension,
+ 0,
+ targetId,
+ 0);
+
+ if (logicalUnit == NULL || logicalUnit->Scb == NULL) {
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (6 << 16) | status
+ );
+
+ return TRUE;
+ }
+
+ scb = logicalUnit->Scb;
+ logicalUnit->Scb = NULL;
+ }
+
+ if (logError != 0 ) {
+
+ deviceExtension->ErrorCount++;
+
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 1 << 16 | status
+ );
+
+ if (!srbValid) {
+
+ //
+ // If the srb is not valid for this type of interrupt the
+ // return.
+ //
+
+ return TRUE;
+ }
+ }
+
+ //
+ // Get virtual TSB address.
+ //
+
+ tsb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(scb->StatusBlock));
+
+ if (tsb == NULL) {
+
+ deviceExtension->ErrorCount++;
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (5 << 16) | status
+ );
+
+ return TRUE;
+ }
+
+ //
+ // Get SRB and update status.
+ //
+
+ srb = scb->SrbAddress;
+
+ if (status == SCB_STATUS_COMMAND_COMPLETE_WITH_FAILURE) {
+
+ //
+ // Get statuses from TSB.
+ //
+
+ MapTsbError(deviceExtension, srb, tsb);
+
+ } else {
+
+ srb->SrbStatus = srbStatus;
+ srb->ScsiStatus = scsiStatus;
+ }
+
+ //
+ // Remove the SRB from the logical unit extension.
+ //
+
+ logicalUnit->CurrentSrb = NULL;
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ if (!(--deviceExtension->ActiveRequests)) {
+
+ //
+ // Turn disk activity light off.
+ //
+
+ DISK_ACTIVITY_LIGHT_OFF();
+ }
+
+ return TRUE;
+
+} // end SpockInterrupt()
+
+BOOLEAN
+SpockResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Reset adapter and SCSI bus.
+
+Arguments:
+
+ DeviceExtension
+ Pathid - identifies which bus on adapter that supports multiple
+ SCSI buses.
+
+Return Value:
+
+ TRUE if reset completed
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PMCA_REGISTERS mcaRegisters = deviceExtension->Registers;
+ ULONG i;
+
+ UNREFERENCED_PARAMETER(PathId);
+
+ deviceExtension->ErrorCount++;
+
+ //
+ // Issue RESET command.
+ //
+
+ if (!IssueImmediateCommand(HwDeviceExtension,
+ (ULONG)SCB_COMMAND_RESET,
+ 0x0f)) {
+
+ DebugPrint((1,"SpockResetBus: Reset failed\n"));
+ return FALSE;
+ }
+
+ //
+ // Wait 2 seconds for bus to quiet down.
+ //
+
+ for (i=0; i<10; i++) {
+
+ //
+ // Stall 200 milliseconds.
+ //
+
+ ScsiPortStallExecution(200 * 1000);
+ }
+
+ //
+ // Wait up to 3 more seconds for adapter to become ready.
+ //
+
+ for (i=0; i<100; i++) {
+
+ //
+ // Stall 3 milliseconds.
+ //
+
+ ScsiPortStallExecution(30 * 1000);
+
+ //
+ // If busy bit is set then reset adapter has not completed.
+ //
+
+ if (ScsiPortReadPortUchar(
+ &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) {
+
+ continue;
+
+ } else {
+
+ break;
+ }
+ }
+
+ if (i == 100) {
+
+ DebugPrint((1,"SpockResetBus: Reset failed\n"));
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 7 << 16
+ );
+
+ return FALSE;
+ }
+
+ //
+ // Issue feature control immediate command to disable
+ // adapter timing of SCBs.
+ //
+
+ if (!IssueImmediateCommand(HwDeviceExtension,
+ (ULONG)SCB_COMMAND_FEATURE_CONTROL,
+ 0x0f)) {
+
+ DebugPrint((1,"SpockResetBus: Set feature controls failed\n"));
+ }
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)PathId,
+ 0xFF,
+ 0xFF,
+ (ULONG)SRB_STATUS_BUS_RESET);
+
+ //
+ // Turn disk activity light off.
+ //
+
+ DISK_ACTIVITY_LIGHT_OFF();
+
+ deviceExtension->ActiveRequests = 0;
+
+ return TRUE;
+
+} // end SpockResetBus()
+
+
+BOOLEAN
+SpockAbortIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Abort command in progress.
+
+Arguments:
+
+ DeviceExtension
+ SRB
+
+Return Value:
+
+ True, if command aborted.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PMCA_REGISTERS mcaRegisters = deviceExtension->Registers;
+ PHW_LOGICAL_UNIT logicalUnit;
+ ULONG i;
+
+ //
+ // Wait up to 10 milliseconds until adapter is not busy.
+ //
+
+ for (i=0; i<1000; i++) {
+
+ if (ScsiPortReadPortUchar(
+ &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) {
+
+ //
+ // Wait 10 microseconds.
+ //
+
+ ScsiPortStallExecution(10);
+
+ } else {
+
+ //
+ // Busy bit clear. Exit loop.
+ //
+
+ break;
+ }
+ }
+
+ if (i < 1000) {
+
+ //
+ // Save SRB in logical unit extension.
+ //
+
+ logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ logicalUnit->AbortSrb = Srb;
+
+ //
+ // Issue abort to the command interface register.
+ //
+
+ ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, SCB_COMMAND_ABORT);
+
+ //
+ // Write immediate command code to attention register.
+ //
+
+ ScsiPortWritePortUchar(&mcaRegisters->Attention, (UCHAR)(Srb->TargetId | IMMEDIATE_COMMAND));
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Timed out waiting for adapter to be in state to accept
+ // immediate command. Return TRUE so that the abort command
+ // will appear to have been sent and will time out causing a
+ // SCSI bus reset to occur.
+
+ DebugPrint((1,"SpockAbortIo: Timed out waiting on BUSY adapter\n"));
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 8 << 16
+ );
+
+ return TRUE;
+ }
+
+} // end SpockAbortIo()
+
+
+VOID
+BuildScb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build SCB
+
+Arguments:
+
+ DeviceExtension
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+
+ PSCB scb = Srb->SrbExtension;
+ ULONG length;
+
+ //
+ // Check for read capacity CDB. IBM boot devices store IML
+ // code near the end of the boot device that must be preserved.
+ // Send the operation specific SCB instead of the generic
+ // SCSI CDB.
+ //
+
+ if (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
+
+ //
+ // Call routine to build special SCB.
+ //
+
+ BuildReadCapacity(DeviceExtension,
+ Srb);
+ return;
+ }
+
+ scb->Command = SCB_COMMAND_SEND_SCSI;
+
+ //
+ // Set SCB command flags.
+ //
+
+ //
+ // Some the spock controllers do not work well with multiple devices.
+ // If too many errors are detected then disable disconnects.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT ||
+ DeviceExtension->ErrorCount > MAXIMUM_ERRORS) {
+ scb->Command |= SCB_NO_DISCONNECT;
+ }
+
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) {
+ scb->Command |= SCB_NO_SYNCHRONOUS_TRANSFER;
+ }
+
+ //
+ // Set SCB request control flags.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ //
+ // Write request.
+ //
+
+ scb->EnableFlags = SCB_ENABLE_SG_LIST |
+ SCB_ENABLE_WRITE |
+ SCB_ENABLE_RETRY_ENABLE |
+ SCB_ENABLE_TSB_ON_ERROR;
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ //
+ // Read request.
+ //
+
+ scb->EnableFlags = SCB_ENABLE_SG_LIST |
+ SCB_ENABLE_READ |
+ SCB_ENABLE_SHORT_TRANSFER |
+ SCB_ENABLE_RETRY_ENABLE |
+ SCB_ENABLE_TSB_ON_ERROR;
+ } else {
+
+ //
+ // No data transfer.
+ //
+
+ scb->EnableFlags = SCB_ENABLE_TSB_ON_ERROR;
+ }
+
+ //
+ // Set CDB length and copy to SCB.
+ //
+
+ scb->CdbSize = Srb->CdbLength;
+
+ ScsiPortMoveMemory(scb->Cdb, Srb->Cdb, Srb->CdbLength);
+
+ //
+ // Build SDL in SCB if data transfer.
+ //
+
+ if (Srb->DataTransferLength) {
+ BuildSgl(DeviceExtension, Srb);
+ } else {
+ scb->BufferAddress = 0;
+ scb->BufferLength = 0;
+ }
+
+ //
+ // Put physical address of TSB in SCB.
+ //
+
+ scb->StatusBlock = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ &scb->Tsb, &length));
+
+ return;
+
+} // end BuildScb()
+
+
+VOID
+BuildSgl(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build scatter/gather descriptor list in SCB.
+
+Arguments:
+
+ DeviceExtension
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PSCB scb = Srb->SrbExtension;
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PSDL sdl = &scb->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG descriptorCount = 0;
+
+ DebugPrint((3,"BuildSgl: Enter routine\n"));
+
+ //
+ // Zero first SDL descriptor.
+ //
+
+ sdl->Descriptor[descriptorCount].Address = 0;
+ sdl->Descriptor[descriptorCount].Length = 0;
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SDL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SDL));
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+
+ DebugPrint((3, "BuildSgl: Data buffer %lx\n", dataPointer));
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "BuildSgl: Physical address %lx\n", physicalAddress));
+ DebugPrint((3, "BuildSgl: Data length %lx\n", length));
+ DebugPrint((3, "BuildSgl: Bytes left %lx\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ //
+ // Check for adjacent physical memory descriptors.
+ //
+
+ if (descriptorCount &&
+ ((sdl->Descriptor[descriptorCount-1].Address +
+ sdl->Descriptor[descriptorCount-1].Length) == physicalAddress)) {
+
+ DebugPrint((3,"BuildSgl: Concatenate adjacent descriptors\n"));
+
+ sdl->Descriptor[descriptorCount-1].Length += length;
+
+ } else {
+
+ sdl->Descriptor[descriptorCount].Address = physicalAddress;
+ sdl->Descriptor[descriptorCount].Length = length;
+ descriptorCount++;
+ }
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+
+ } while (bytesLeft);
+
+ //
+ // Write SDL length to SCB.
+ //
+
+ scb->BufferLength = descriptorCount * sizeof(SG_DESCRIPTOR);
+
+ DebugPrint((3,"BuildSgl: SDL length is %d\n", descriptorCount));
+
+ //
+ // Write SDL address to SCB.
+ //
+
+ scb->BufferAddress = physicalSdl;
+
+ DebugPrint((3,"BuildSgl: SDL address is %lx\n", sdl));
+
+ DebugPrint((3,"BuildSgl: SCB address is %lx\n", scb));
+
+ return;
+
+} // end BuildSgl()
+
+VOID
+BuildReadCapacity(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build SCB for read capacity command.
+
+Arguments:
+
+ DeviceExtension
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PSCB scb = Srb->SrbExtension;
+ ULONG length;
+
+ DebugPrint((1, "Spock: BuildReadCapacity: Building spock read capacity\n"));
+
+ //
+ // Set SCB command.
+ //
+
+ scb->Command = SCB_COMMAND_READ_CAPACITY;
+ scb->Command |= SCB_NO_SYNCHRONOUS_TRANSFER | SCB_NO_DISCONNECT;
+
+ scb->EnableFlags = SCB_ENABLE_TSB_ON_ERROR |
+ SCB_ENABLE_READ |
+ SCB_ENABLE_BYPASS_BUFFER |
+ SCB_ENABLE_RETRY_ENABLE;
+
+ //
+ // Get physical buffer address.
+ //
+
+ scb->BufferAddress = (ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ Srb->DataBuffer,
+ &length)));
+
+ scb->BufferLength = Srb->DataTransferLength;
+
+ //
+ // Put physical address of TSB in SCB.
+ //
+
+ scb->StatusBlock = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ &scb->Tsb, &length));
+
+ return;
+
+} // end BuildReadCapacity()
+
+
+ULONG
+McaAdapterPresent(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if Spock adapter present in sytem by reading
+ interrupt status register.
+
+Arguments:
+
+ HwDeviceExtension - miniport device extension
+
+ ConfigInfo - Supplies the known configuraiton information.
+
+ AdapterCount - Supplies the count of adapter slots which have been tested.
+
+ Again - Returns whether the OS-specific driver should call again.
+
+Return Value:
+
+ Returns TRUE if adapter exists
+
+--*/
+
+{
+ PMCA_REGISTERS baseIoAddress;
+ PUCHAR ioSpace;
+
+ //
+ // Get the system physical address for this card. The card uses I/O space.
+ //
+
+ ioSpace = ScsiPortGetDeviceBase(
+ HwDeviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress(0),
+ 0x400, // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+ //
+ // Scan though the adapter address looking for adapters.
+ //
+
+ while (AdapterAddresses[*AdapterCount] != 0) {
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ baseIoAddress = (PMCA_REGISTERS)(ioSpace +
+ AdapterAddresses[*AdapterCount]);
+
+ //
+ // Update the adapter count.
+ //
+
+ (*AdapterCount)++;
+
+ if (ScsiPortReadPortUchar((PUCHAR)baseIoAddress) != 0xFF) {
+
+ DebugPrint((1,"Spock: Base IO address is %x\n", baseIoAddress));
+
+ //
+ // An adapter has been found. Set the base address in the device
+ // extension, and request another call.
+ //
+
+ HwDeviceExtension->Registers = baseIoAddress;
+ *Again = TRUE;
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(
+ AdapterAddresses[*AdapterCount - 1]);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(MCA_REGISTERS);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ return(SP_RETURN_FOUND);
+ }
+ }
+
+ //
+ // The entire table has been searched and no adapters have been found.
+ // There is no need to call again and the device base can now be freed.
+ // Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *(AdapterCount) = 0;
+
+ ScsiPortFreeDeviceBase(
+ HwDeviceExtension,
+ ioSpace
+ );
+
+ return(SP_RETURN_NOT_FOUND);
+
+} // end McaAdapterPresent()
+
+
+BOOLEAN
+IssueScbCommand(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PhysicalScb,
+ IN UCHAR TargetId
+ )
+
+/*++
+
+Routine Description:
+
+ Send SCB to adapter.
+
+Arguments:
+
+ DeviceExtension
+ Physical SCB
+ TargeId
+
+Return Value:
+
+ TRUE if command sent.
+ FALSE if wait for BUSY bit timed out.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PMCA_REGISTERS mcaRegisters = deviceExtension->Registers;
+ ULONG i;
+
+ //
+ // Wait up to 10 milliseconds until adapter is not busy.
+ //
+
+ for (i=0; i<1000; i++) {
+
+ if (ScsiPortReadPortUchar(
+ &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) {
+
+ //
+ // Wait 10 microseconds.
+ //
+
+ ScsiPortStallExecution(10);
+
+ } else {
+
+ //
+ // Busy bit clear. Exit loop.
+ //
+
+ break;
+ }
+ }
+
+ if (i < 1000) {
+
+ //
+ // Write physical SCB address to command interface register.
+ //
+
+ ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, PhysicalScb);
+
+ //
+ // Write targetid and command code to attention register.
+ //
+
+ ScsiPortWritePortUchar(&mcaRegisters->Attention, (UCHAR)(TargetId | START_SCB));
+
+ if (!deviceExtension->ActiveRequests++) {
+
+ //
+ // Turn disk activity light on.
+ //
+
+ DISK_ACTIVITY_LIGHT_ON();
+ }
+
+ return TRUE;
+
+ } else {
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4 << 16
+ );
+
+ return FALSE;
+ }
+
+} // end IssueScbCommand()
+
+
+BOOLEAN
+IssueImmediateCommand(
+ IN PVOID HwDeviceExtension,
+ IN ULONG ImmediateCommand,
+ IN UCHAR TargetId
+ )
+
+/*++
+
+Routine Description:
+
+ Send SCB to adapter.
+
+Arguments:
+
+ DeviceExtension
+ ImmediateCommand
+ TargeId
+
+Return Value:
+
+ TRUE if command sent.
+ FALSE if wait for BUSY bit timed out.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PMCA_REGISTERS mcaRegisters = deviceExtension->Registers;
+ ULONG i;
+
+ //
+ // Wait up to 10 milliseconds until adapter is not busy.
+ //
+
+ for (i=0; i<1000; i++) {
+
+ if (ScsiPortReadPortUchar(
+ &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) {
+
+ //
+ // Wait 10 microseconds.
+ //
+
+ ScsiPortStallExecution(10);
+
+ } else {
+
+ //
+ // Busy bit clear. Exit loop.
+ //
+
+ break;
+ }
+ }
+
+ if (i < 1000) {
+
+ //
+ // Write immediate command to command interface register.
+ //
+
+ ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, ImmediateCommand);
+
+ //
+ // Write targetid and command code to attention register.
+ //
+
+ ScsiPortWritePortUchar(&mcaRegisters->Attention,
+ (UCHAR)(TargetId | IMMEDIATE_COMMAND));
+
+ return TRUE;
+
+ } else {
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4 << 16
+ );
+
+ return FALSE;
+ }
+
+} // end IssueImmediateCommand()
+
+
+VOID
+MapTsbError(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PTSB Tsb
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ TSB - Termination Status Block
+
+Return Value:
+
+ SCSI error code
+
+--*/
+
+{
+ ULONG logError = 0;
+
+ DebugPrint((2, "MapTsbError: TSB ending status %lx\n", Tsb->ScbStatus));
+
+ switch (Tsb->ScbStatus & 0x003F) {
+
+ case TSB_STATUS_NO_ERROR:
+
+ //
+ // Check if device is not assigned.
+ //
+
+ if (Tsb->CommandError == TSB_COMMAND_ERROR_DEVICE_NOT_ASSIGNED) {
+
+ //
+ // Check for check condition.
+ //
+
+ if (Tsb->DeviceStatus == SCB_DEV_STATUS_CHECK_CONDITION) {
+
+ //
+ // Adjust count of bytes transferred.
+ //
+
+ Srb->DataTransferLength -= Tsb->ResidualByteCount;
+ }
+
+ Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ }
+
+ break;
+
+ case TSB_STATUS_SHORT_RECORD:
+
+ DebugPrint((1, "MapTsbError: Short record exception\n"));
+
+ Srb->DataTransferLength -= Tsb->ResidualByteCount;
+
+ Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ break;
+
+ case TSB_STATUS_INVALID_COMMAND:
+
+ DebugPrint((1, "MapTsbError: Invalid command rejected\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+
+ break;
+
+ case TSB_STATUS_SCB_REJECTED:
+
+ DebugPrint((1, "MapTsbError: SCB rejected\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+
+ break;
+
+ case TSB_STATUS_SCB_SPECIFIC_CHECK:
+
+ DebugPrint((1, "MapTsbError: SCB speicific check\n"));
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+
+ break;
+
+ case TSB_STATUS_LONG_RECORD:
+
+ DebugPrint((1, "MapTsbError: Long record exception\n"));
+
+ Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ break;
+
+ default:
+
+ DebugPrint((1, "MapTsbError: Unknown end status %lx\n",Tsb->ScbStatus));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+
+ } // end switch
+
+ DebugPrint((2,
+ "MapTsbError: Device status %x, DeviceError = %x\n",
+ Tsb->DeviceStatus,
+ Tsb->DeviceError));
+ DebugPrint((2,
+ "MapTsbError: Command status %x, CommandError = %x\n",
+ Tsb->CommandStatus,
+ Tsb->CommandError));
+
+ if (logError != 0) {
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ 2 << 16 | Tsb->ScbStatus
+ );
+
+ }
+
+ Srb->ScsiStatus = Tsb->DeviceStatus;
+
+ return;
+
+} // end MapTsbError()
diff --git a/private/ntos/miniport/spock/spock.rc b/private/ntos/miniport/spock/spock.rc
new file mode 100644
index 000000000..016f46aa5
--- /dev/null
+++ b/private/ntos/miniport/spock/spock.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "IBM MCA SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "spock.sys"
+#define VER_ORIGINALFILENAME_STR "spock.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/symbios/dirs b/private/ntos/miniport/symbios/dirs
new file mode 100644
index 000000000..803baf6a6
--- /dev/null
+++ b/private/ntos/miniport/symbios/dirs
@@ -0,0 +1,26 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= \
+ \
+ symc810
+
diff --git a/private/ntos/miniport/symbios/symc810/makefile b/private/ntos/miniport/symbios/symc810/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/symbios/symc810/scrpt810.asm b/private/ntos/miniport/symbios/symc810/scrpt810.asm
new file mode 100644
index 000000000..2e6fe2eb5
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/scrpt810.asm
@@ -0,0 +1,667 @@
+;/************************************************************************
+;* *
+;* Copyright 1994 Symbios Logic Inc. All rights reserved. *
+;* *
+;* This file is confidential and a trade secret of Symbios Logic *
+;* The receipt of or possession of this file does not convey any *
+;* rights to reproduce or disclose its contents or to manufacture, *
+;* use, or sell anything is may describe, in whole, or in part, *
+;* without the specific written consent of Symbios Logic *
+;* *
+;************************************************************************/
+;
+;/*+++HDR
+; *
+; * Version History
+; * ---------------
+; *
+; * Date Who? Description
+; * -------- ---- -------------------------------------------------------
+; *
+; * 1/12/96 SPD Add new script entry point to restart negotiations for
+; * synch transfer mode on same IO as wide negotiation.
+; * Fix for parity error on wide data transfers.
+; *
+;---*/
+;
+
+;
+; Successful operation codes
+;
+
+Absolute CommandOk = 0x0aa00 ; command completed successfully
+Absolute Save_Pointers = 0x0aa01 ; SDP message received
+Absolute Save_with_Disc = 0x0aa02 ; SDP + Disconnect messages received
+Absolute Device_Discon = 0x0aa03 ; Disconnect message received
+Absolute Restore_Pointers = 0x0aa04 ; RDP message received.
+Absolute ScriptsAborted = 0x0aa05 ; scripts aborted by device driver
+Absolute Tag_Received = 0x0aa06 ; RDP message received.
+Absolute SynchNegotComp = 0x0aa0c ; synchronous negotiation completed
+Absolute WideNegotComp = 0x0aa1c ; wide negotiation completed
+
+;
+; Error codes
+;
+
+Absolute DeviceReset = 0x0ff07 ; had to bail out
+Absolute ResetFailed = 0x0ff08 ; ...but couldn't.
+Absolute RestSenseComplete = 0x0ff09 ; request sense has completed
+Absolute ParityMessageSent = 0x0ff0a ; parity message has been sent
+Absolute SynchNotSupported = 0x0ff0b ; synchronous xfer is not supported
+Absolute WideNotSupported = 0x0ff1b ; wide xfer is not supported
+Absolute InvalidReselector = 0x0ff0d ; reselecting drive id invalid
+Absolute MessageRejected = 0x0ff0e ; target rejected our message
+Absolute InvalidTaggedMessage = 0x0ff0f ; target did not send a tagged message.
+
+Absolute DeviceAborted = 0x0ff10 ; device accepted abort message
+Absolute AbortFailed = 0x0ff11 ; abort message failed
+
+Absolute ReselByTarget = 0x0080
+
+
+;
+; offsets in DSA structure follow
+; THESE OFFSETS MUST BE CHANGED IF SCRIPT DATA STRUCTURE IN DEVICE EXTENSION
+; CHANGES.
+;
+
+Absolute SelectDataOff = 0
+Absolute CDBDataOff = SelectDataOff + 4
+Absolute MsgOutOff = CDBDataOff + 8
+Absolute StatusDataOff = MsgOutOff + 8
+Absolute OneByteMsgOff = StatusDataOff + 8
+Absolute RejectMsgOff = OneByteMsgOff + 8
+Absolute ParityMsgOff = RejectMsgOff + 8
+Absolute AbortMsgOff = ParityMsgOff + 8
+Absolute BDRMsgOff = AbortMsgOff + 8
+Absolute TwoByteMsgOff = BDRMsgOff + 8
+Absolute SGEntry18Off = TwoByteMsgOff + 8
+Absolute SGEntry17Off = SGEntry18Off + 8
+Absolute SGEntry16Off = SGEntry17Off + 8
+Absolute SGEntry15Off = SGEntry16Off + 8
+Absolute SGEntry14Off = SGEntry15Off + 8
+Absolute SGEntry13Off = SGEntry14Off + 8
+Absolute SGEntry12Off = SGEntry13Off + 8
+Absolute SGEntry11Off = SGEntry12Off + 8
+Absolute SGEntry10Off = SGEntry11Off + 8
+Absolute SGEntry09Off = SGEntry10Off + 8
+Absolute SGEntry08Off = SGEntry09Off + 8
+Absolute SGEntry07Off = SGEntry08Off + 8
+Absolute SGEntry06Off = SGEntry07Off + 8
+Absolute SGEntry05Off = SGEntry06Off + 8
+Absolute SGEntry04Off = SGEntry05Off + 8
+Absolute SGEntry03Off = SGEntry04Off + 8
+Absolute SGEntry02Off = SGEntry03Off + 8
+Absolute SGEntry01Off = SGEntry02Off + 8
+
+;
+; 53C8xx register bits used by scripts
+;
+;
+;Absolute CTEST2_sigp = 0x40
+;Absolute CTEST7_notime = 0x10
+;
+;
+; SCSI definitions used by scripts
+;
+
+Absolute SCSIMESS_ABORT = 0x06
+Absolute SCSIMESS_ABORT_WITH_TAG = 0x0D
+Absolute SCSIMESS_BUS_DEVICE_RESET = 0X0C
+Absolute SCSIMESS_CLEAR_QUEUE = 0X0E
+Absolute SCSIMESS_DISCONNECT = 0X04
+Absolute SCSIMESS_EXTENDED_MESSAGE = 0X01
+Absolute SCSIMESS_IDENTIFY = 0X80
+Absolute SCSIMESS_IDENTIFY_WITH_DISCON = 0XC0
+Absolute SCSIMESS_IGNORE_WIDE_RESIDUE = 0X23
+Absolute SCSIMESS_INITIATE_RECOVERY = 0X0F
+Absolute SCSIMESS_INIT_DETECTED_ERROR = 0X05
+Absolute SCSIMESS_LINK_CMD_COMP = 0X0A
+Absolute SCSIMESS_LINK_CMD_COMP_W_FLAG = 0X0B
+Absolute SCSIMESS_MESS_PARITY_ERROR = 0X09
+Absolute SCSIMESS_MESSAGE_REJECT = 0X07
+Absolute SCSIMESS_NO_OPERATION = 0X08
+Absolute SCSIMESS_HEAD_OF_QUEUE_TAG = 0X21
+Absolute SCSIMESS_ORDERED_QUEUE_TAG = 0X22
+Absolute SCSIMESS_SIMPLE_QUEUE_TAG = 0X20
+Absolute SCSIMESS_RELEASE_RECOVERY = 0X10
+Absolute SCSIMESS_RESTORE_POINTERS = 0X03
+Absolute SCSIMESS_SAVE_DATA_POINTER = 0X02
+Absolute SCSIMESS_TERMINATE_IO_PROCESS = 0X11
+Absolute SCSIMESS_COMMAND_COMPLETE = 0X00
+Absolute SCSIMESS_SYNCHRONOUS_DATA_REQ = 0X01
+Absolute SCSIMESS_WIDE_DATA_REQUEST = 0X03
+Absolute SCSISTAT_CHECK_CONDITION = 0x02
+
+;
+; Script entry point declarations follow
+;
+
+Entry EndOfScript
+Entry ResetDevice
+Entry AbortDevice
+Entry AbortExecution
+Entry ProcessSelectReselect
+Entry ReselectScript
+Entry SendErrorMessage
+Entry RejectReceived
+Entry RejectIN
+Entry SendReject
+Entry RejectMessage
+Entry ExtMsgRcvd
+Entry ProcessDisconnect
+Entry RestPtrsRcvd
+Entry SaveDataPointers
+Entry MessageIn
+Entry RestartScript
+Entry SyncMsgNegot
+
+Entry DataOutJump
+Entry DataInJump
+Entry DataOut18
+Entry DataOut01
+Entry DataIn18
+Entry DataIn01
+
+Entry GetStatus
+Entry SendCommand
+Entry SendID
+Entry CommandScriptStart
+Entry QueueTagMessage
+Entry ContNegScript
+
+CommandScriptStart:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; This is the entry point for initiating SCSI I/O
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ select ATN from SelectDataOff, rel( ReselectScript ) ; Select device
+ move GPREG & 0xFE to GPREG ; turn LED on
+ jump rel ( GetStatus ), when STATUS ; If status exit
+ jump rel ( ResetSelectedDev ), if not MSG_OUT ; Bad phase check
+
+SendID:
+ move from MsgOutOff, when MSG_OUT ; Send ID message
+ jump rel ( SendCommand ) when CMD ; Expected next phase
+ jump rel ( GetStatus ) if STATUS ; Handle status phase
+ jump rel ( MessageIn ) if MSG_IN ; Handle message phase
+ jump rel ( ResetSelectedDev ) ; Error - reset device
+
+SendCommand:
+ move from CDBDataOff, when CMD ; Move the CDB
+;; new entry to take care of a posible SCSI parity error
+ move SOCL & 0xFD to SOCL
+
+ jump rel ( ResetSelectedDev ) when CMD ; Error - reset device
+
+ jump rel ( GetStatus ) if STATUS ; Handle status phase
+ jump rel ( MessageIn ) if MSG_IN ; Handle message phase
+
+
+ProcessDataPhase:
+
+; Jump to the data in handling when in data-in phase. This jump
+; may be patched by the miniport.
+
+DataInJump:
+
+ jump rel ( DataIn18 ) if DATA_IN ; Handle data in
+
+; Jump to the data in handling when in data-in phase. This jump
+; may be patched by the miniport.
+
+DataOutJump:
+ jump rel ( DataOut18 ) if DATA_OUT ; Handle data out
+
+ jump rel ( ResetSelectedDev ) ; Bad phase encountered
+
+GetStatus:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; This script routine handles status phase
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ move from StatusDataOff, when STATUS ; Get status
+
+;
+; MESSAGE IN phase should follow STATUS phase.
+;
+
+ jump rel ( MessageIn ) when MSG_IN ; Handle message in phase
+ jump rel ( ResetSelectedDev ) ; Error - reset device
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; This the data out section of scripts.
+; Up to 18 gather moves can be processed at once.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+DataOut18:
+ chmov from SGEntry18Off, when DATA_OUT
+ chmov from SGEntry17Off, when DATA_OUT
+ chmov from SGEntry16Off, when DATA_OUT
+ chmov from SGEntry15Off, when DATA_OUT
+ chmov from SGEntry14Off, when DATA_OUT
+ chmov from SGEntry13Off, when DATA_OUT
+ chmov from SGEntry12Off, when DATA_OUT
+ chmov from SGEntry11Off, when DATA_OUT
+ chmov from SGEntry10Off, when DATA_OUT
+ chmov from SGEntry09Off, when DATA_OUT
+ chmov from SGEntry08Off, when DATA_OUT
+ chmov from SGEntry07Off, when DATA_OUT
+ chmov from SGEntry06Off, when DATA_OUT
+ chmov from SGEntry05Off, when DATA_OUT
+ chmov from SGEntry04Off, when DATA_OUT
+ chmov from SGEntry03Off, when DATA_OUT
+ chmov from SGEntry02Off, when DATA_OUT
+
+DataOut01:
+ chmov from SGEntry01Off, when DATA_OUT
+
+ jump rel ( GetStatus) when STATUS ; Handle status
+ jump rel ( MessageIn) if MSG_IN ; Handle messages
+ jump rel ( ResetSelectedDev) ; Error - reset device
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; This the data in section of scripts.
+; Up to 18 scatter moves can be processed at once.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+DataIn18:
+ chmov from SGEntry18Off, when DATA_IN
+ chmov from SGEntry17Off, when DATA_IN
+ chmov from SGEntry16Off, when DATA_IN
+ chmov from SGEntry15Off, when DATA_IN
+ chmov from SGEntry14Off, when DATA_IN
+ chmov from SGEntry13Off, when DATA_IN
+ chmov from SGEntry12Off, when DATA_IN
+ chmov from SGEntry11Off, when DATA_IN
+ chmov from SGEntry10Off, when DATA_IN
+ chmov from SGEntry09Off, when DATA_IN
+ chmov from SGEntry08Off, when DATA_IN
+ chmov from SGEntry07Off, when DATA_IN
+ chmov from SGEntry06Off, when DATA_IN
+ chmov from SGEntry05Off, when DATA_IN
+ chmov from SGEntry04Off, when DATA_IN
+ chmov from SGEntry03Off, when DATA_IN
+ chmov from SGEntry02Off, when DATA_IN
+
+DataIn01:
+ chmov from SGEntry01Off, when DATA_IN
+
+ jump rel ( GetStatus) when STATUS ; Handle status
+ jump rel ( MessageIn) if MSG_IN ; Handle messages
+ jump rel ( ResetSelectedDev) ; Error - reset device
+
+
+ContNegScript:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; ContNegScript
+;
+; Entry point for continuing negotiations for sync after wide negotiations
+; have occurred.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ set ATN ; bring target back to
+ ; msg in phase
+ clear ACK ; still need to ack
+ ; last wide neg. byte
+ jump rel ( ResetSelectedDev ), when not MSG_OUT ; Bad phase check
+ move from MsgOutOff, when MSG_OUT ; Send synch messages
+ jump rel ( RestartPlus ), when MSG_IN
+ jump rel ( ResetSelectedDev )
+
+
+RestartScript:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; RestartScript
+;
+; Entry point for restarting script after reselect, etc.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; new command to take care of possibel parity error
+ move SOCL & 0xFD to SOCL
+ clear ACK and ATN ; Clear pending conditions
+
+RestartPlus:
+;
+; note that the call to message in will return only if the message is IDENTIFY
+;
+
+ jump rel ( SendCommand ) when CMD ; Process phase
+ call rel ( MessageIn ) if MSG_IN ; Handle messages
+ jump rel ( GetStatus ) if STATUS ; Handle status
+ jump rel ( ProcessDataPhase ) if DATA_IN ;
+ jump rel ( ProcessDataPhase ) if DATA_OUT ;
+ jump rel ( SendErrorMessage ) if MSG_OUT ;
+ jump rel ( ResetSelectedDev ) ; Error - reset device
+
+
+MessageIn:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; This script routine processes message from target
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ move from OneByteMsgOff, when MSG_IN
+
+; steved -
+; do we need to move identify further up?
+
+;
+; Handle command complete message
+;
+
+ jump rel ( ProcessCommandComplete ) if SCSIMESS_COMMAND_COMPLETE
+
+;
+; Handle disconnect
+;
+
+ jump rel ( ProcessDisconnect ) if SCSIMESS_DISCONNECT
+
+;
+; Handle Save Data Pointers
+;
+
+ jump rel ( SaveDataPointers ) if SCSIMESS_SAVE_DATA_POINTER
+
+;
+; Handle Restore Pointers
+;
+
+ jump rel ( RestPtrsRcvd ) if SCSIMESS_RESTORE_POINTERS
+
+;
+; Handle extended message
+;
+
+ jump rel ( ExtMsgRcvd ) if SCSIMESS_EXTENDED_MESSAGE
+
+;
+; Handle Message Reject
+;
+
+ jump rel ( RejectReceived ) if SCSIMESS_MESSAGE_REJECT
+
+;
+; If not Identify, reject the message
+;
+
+ jump rel ( RejectMessage ) if not SCSIMESS_IDENTIFY and mask 0x0F
+
+;
+; Process Identify message. Note that we throw away the Identify message
+; at this point because it has already been processed by the driver.
+;
+
+ clear ACK ; Throw message away
+ jump rel ( MessageIn ) when MSG_IN ; Handle more messages
+
+;
+; Note that this routine is CALLed only by the reselection script routine.
+; We should only receive an identify message immediately after a
+; reselection. Therefore, the RETURN below will be executed only when this
+; routine is called by the reselection code.
+;
+ return ; Return to caller
+
+SaveDataPointers:
+ clear ACK ; Acknowledge SDP
+
+;
+; Normally, disconnect message will follow SDP. We save ourselves an interrupt
+; by assuming this is the case.
+;
+
+ int Save_Pointers when not MSG_IN ; Another message?
+ move from OneByteMsgOff, when MSG_IN ; If so move it
+
+;
+; bugbug-
+; although it is very improbable that a device would send a message other
+; than DISCONNECT after an SDP, we need to handle this case more gracefully.
+;
+ jump rel ( ResetSelectedDev ) if not SCSIMESS_DISCONNECT
+ ; If not disconnect,
+ ; error - reset device
+
+ move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect
+ move GPREG | 0x01 to GPREG ; LED off ; Clear disconnect message
+ clear ACK
+ wait DISCONNECT ;
+ int Save_with_Disc ; Indicate SDP and
+ ; disconnect
+
+RestPtrsRcvd:
+ clear ACK ; Accept message
+ int Restore_Pointers ; Indicate restore pointers
+
+
+ProcessDisconnect:
+
+ move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect
+ move GPREG | 0x01 to GPREG ; LED off ; Clear disconnect message
+ clear ACK ; Clear disconnect message
+ wait DISCONNECT ; Wait for disconnect to happen
+ int Device_Discon ; Indicate device disconnected
+
+
+ProcessCommandComplete:
+
+ move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect
+ move GPREG | 0x01 to GPREG ; LED off ; Clear disconnect message
+ clear ACK ; Acknowledge message
+ wait DISCONNECT ; Wait for disconnect to happen
+ int CommandOk ; Indicate command complete
+
+ExtMsgRcvd:
+ clear ACK ; Accept first byte of message
+ jump rel ( ResetSelectedDev ) when not MSG_IN ; If not MSG-IN, error - reset device
+ move from OneByteMsgOff, when MSG_IN ; Get next message byte
+
+ jump rel ( SyncMsgNegot ) if 3 ; If not two byte message,
+ jump rel ( RejectMessage ) if not 2
+
+ clear ACK ; Accept first byte of wide message
+ move from OneByteMsgOff, when MSG_IN ; Get next byte of message
+
+ jump rel ( RejectMessage ) if not SCSIMESS_WIDE_DATA_REQUEST
+
+
+ clear ACK ; Accept SDTR byte
+;
+; the following code processes the SDTR extended message
+;
+ move from OneByteMsgOff, when MSG_IN ; Get wide parameters
+
+ int WideNegotComp ; Indicate wide supported
+
+
+SyncMsgNegot:
+;
+; NOTE: the following extended message lengths are currently supported:
+;
+; 3 byte messages
+;
+ clear ACK ; Accept first byte of sync message
+ move from OneByteMsgOff, when MSG_IN ; Get next byte of message
+ jump rel ( RejectMessage ) if not SCSIMESS_SYNCHRONOUS_DATA_REQ
+
+ clear ACK ; Accept SDTR byte
+;
+; the following code processes the SDTR extended message
+;
+
+ move from TwoByteMsgOff, when MSG_IN ; Get sync parameters
+ int SynchNegotComp ; Indicate synchronous supported
+
+
+RejectMessage:
+ set ATN
+ clear ACK ; Clear the message
+ jump rel ( RejectIN ) when MSG_IN ; If still MSG IN, jump to
+ ; clear extended message
+SendReject:
+ jump ResetSelectedDev, if not MSG_OUT ; If not MSG OUT, error - reset device
+ move from RejectMsgOff, when MSG_OUT ; Send REJECT message
+ jump rel ( ResetSelectedDev) when MSG_OUT ; If not accepted, error - reset device
+ jump rel ( RestartScript ) ; Reject successful - restart
+ ; the state machine
+
+RejectIN:
+ move from OneByteMsgOff, when MSG_IN ; Get message
+ clear ACK ; Acknowledge it
+ jump rel ( RejectIN ) when MSG_IN ; If more message bytes, process them
+ jump rel ( SendReject ) ; Send REJECT message
+
+RejectReceived:
+ ;clear ACK ; Clear the message
+ int MessageRejected ; Indicate message rejected
+
+SendErrorMessage:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Send either INITIATOR DETECTED ERROR or MESSAGE PARITY ERROR message
+; (set by driver before calling) to target.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ set ATN ; Ask for message out
+ clear ACK ; Clear any pending msgs
+
+;
+; If the device does not go immediately to message out, we don't try to
+; coax it.
+;
+ jump rel ( ResetSelectedDev ) when not MSG_OUT ; Error - reset device
+
+DoParityMove:
+ move from ParityMsgOff, when MSG_OUT ; Move the error message
+ int ParityMessageSent ; Indicate message sent
+
+ReselectScript:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Wait for a Reselection/selection
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ wait reselect rel ( AbortExecution )
+ move GPREG & 0xFE to GPREG ;LED on
+
+ProcessSelectReselect:
+
+ jump rel( ProcessSelectReselect ) if not MSG_IN
+
+ move from OneByteMsgOff, when MSG_IN
+
+ReselectInterrupt:
+
+ int ReselByTarget
+
+AbortExecution:
+
+ move CTEST2 to SFBR ; Signal that we are stalled
+ int ScriptsAborted
+
+
+ResetDevice:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; ResetDevice:
+;
+; Select device, reset device and exit.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; First have to select the device.
+
+ select ATN from SelectDataOff, rel( ReselectScript ) ; Select device
+ move GPREG & 0xFE to GPREG ; LED on
+ jump rel ( ResetSendMsg )
+
+ResetSelectedDev:
+
+ set ATN ; Set ATN before releasing any messages
+ clear ACK ; Release messages
+
+;
+; if the wayward device does not immediately go into message phase, we
+; will bail out. No attempt is made to coax the drive by transferring
+; any additional data or message bytes.
+;
+
+ResetSendMsg:
+ int ResetFailed when not MSG_OUT ; Interrupt the reset failed
+
+DoBDRMove:
+ move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect
+ move from BDRMsgOff, when MSG_OUT ; Send BDR message
+
+ move GPREG | 0x01 to GPREG ; LED off
+ wait DISCONNECT ; Wait for device to disconnect
+ int DeviceReset ; Indicate device reset
+
+AbortDevice:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; AbortDevice:
+;
+; Abort all I/Os for the device and exit.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; First have to select the device.
+
+ select ATN from SelectDataOff, rel( ReselectScript ) ; Select device
+ move GPREG & 0xFE to GPREG ; LED on
+
+;
+; if the wayward device does not immediately go into message phase, we
+; will bail out. No attempt is made to coax the drive by transferring
+; any additional data or message bytes.
+;
+
+ int AbortFailed when not MSG_OUT ; Interrupt the abort failed
+
+
+DoAbortMove:
+ move SCNTL2 & 0x7F to SCNTL2 ; Disable unexpected disconnect
+ move from AbortMsgOff, when MSG_OUT ; Send abort message
+
+ move GPREG | 0x01 to GPREG ; LED off
+ wait DISCONNECT ; Wait for device to disconnect
+ int DeviceAborted ; Indicate device aborted
+
+
+QueueTagMessage:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; QueueTagMessage -
+;
+; This routine processes a queue tagged message.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ clear ACK ; Acknowledge identify message
+ move from OneByteMsgOff, when MSG_IN ; Get the first message byte
+
+ int InvalidTaggedMessage, if not SCSIMESS_SIMPLE_QUEUE_TAG
+ ; If not simple queue tag message,
+ ; indicate this to driver
+
+ clear ACK ; Acknowledge queue tag message
+ move from OneByteMsgOff, when MSG_IN ; Get the queue tag message
+ int Tag_Received ; Indicate queue tag received
+
+
+EndOfScript:
diff --git a/private/ntos/miniport/symbios/symc810/scrpt810.h b/private/ntos/miniport/symbios/symc810/scrpt810.h
new file mode 100644
index 000000000..1199b5262
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/scrpt810.h
@@ -0,0 +1,273 @@
+typedef unsigned long ULONG;
+
+ULONG SCRIPT[] = {
+ 0x47000000L, 0x00000470L,
+ 0x7C07FE00L, 0x00000000L,
+ 0x838B0000L, 0x00000070L,
+ 0x86820000L, 0x000004A8L,
+ 0x1E000000L, 0x0000000CL,
+ 0x828B0000L, 0x00000018L,
+ 0x838A0000L, 0x00000050L,
+ 0x878A0000L, 0x00000228L,
+ 0x80880000L, 0x00000480L,
+ 0x1A000000L, 0x00000004L,
+ 0x7C09FD00L, 0x00000000L,
+ 0x828B0000L, 0x00000468L,
+ 0x838A0000L, 0x00000020L,
+ 0x878A0000L, 0x000001F8L,
+ 0x818A0000L, 0x000000D0L,
+ 0x808A0000L, 0x00000020L,
+ 0x80880000L, 0x00000440L,
+ 0x1B000000L, 0x00000014L,
+ 0x878B0000L, 0x000001D0L,
+ 0x80880000L, 0x00000428L,
+ 0x10000000L, 0x0000004CL,
+ 0x10000000L, 0x00000054L,
+ 0x10000000L, 0x0000005CL,
+ 0x10000000L, 0x00000064L,
+ 0x10000000L, 0x0000006CL,
+ 0x10000000L, 0x00000074L,
+ 0x10000000L, 0x0000007CL,
+ 0x10000000L, 0x00000084L,
+ 0x10000000L, 0x0000008CL,
+ 0x10000000L, 0x00000094L,
+ 0x10000000L, 0x0000009CL,
+ 0x10000000L, 0x000000A4L,
+ 0x10000000L, 0x000000ACL,
+ 0x10000000L, 0x000000B4L,
+ 0x10000000L, 0x000000BCL,
+ 0x10000000L, 0x000000C4L,
+ 0x10000000L, 0x000000CCL,
+ 0x10000000L, 0x000000D4L,
+ 0x838B0000L, 0xFFFFFF50L,
+ 0x878A0000L, 0x00000128L,
+ 0x80880000L, 0x00000380L,
+ 0x11000000L, 0x0000004CL,
+ 0x11000000L, 0x00000054L,
+ 0x11000000L, 0x0000005CL,
+ 0x11000000L, 0x00000064L,
+ 0x11000000L, 0x0000006CL,
+ 0x11000000L, 0x00000074L,
+ 0x11000000L, 0x0000007CL,
+ 0x11000000L, 0x00000084L,
+ 0x11000000L, 0x0000008CL,
+ 0x11000000L, 0x00000094L,
+ 0x11000000L, 0x0000009CL,
+ 0x11000000L, 0x000000A4L,
+ 0x11000000L, 0x000000ACL,
+ 0x11000000L, 0x000000B4L,
+ 0x11000000L, 0x000000BCL,
+ 0x11000000L, 0x000000C4L,
+ 0x11000000L, 0x000000CCL,
+ 0x11000000L, 0x000000D4L,
+ 0x838B0000L, 0xFFFFFEA8L,
+ 0x878A0000L, 0x00000080L,
+ 0x80880000L, 0x000002D8L,
+ 0x58000008L, 0x00000000L,
+ 0x60000040L, 0x00000000L,
+ 0x86830000L, 0x000002C0L,
+ 0x1E000000L, 0x0000000CL,
+ 0x878B0000L, 0x00000018L,
+ 0x80880000L, 0x000002A8L,
+ 0x7C09FD00L, 0x00000000L,
+ 0x60000048L, 0x00000000L,
+ 0x828B0000L, 0xFFFFFE10L,
+ 0x8F8A0000L, 0x00000028L,
+ 0x838A0000L, 0xFFFFFE40L,
+ 0x818A0000L, 0xFFFFFE20L,
+ 0x808A0000L, 0xFFFFFE18L,
+ 0x868A0000L, 0x000001F0L,
+ 0x80880000L, 0x00000260L,
+ 0x1F000000L, 0x0000001CL,
+ 0x808C0000L, 0x000000C8L,
+ 0x808C0004L, 0x00000098L,
+ 0x808C0002L, 0x00000038L,
+ 0x808C0003L, 0x00000078L,
+ 0x808C0001L, 0x000000D0L,
+ 0x808C0007L, 0x000001A8L,
+ 0x80840F80L, 0x00000148L,
+ 0x60000040L, 0x00000000L,
+ 0x878B0000L, 0xFFFFFFB0L,
+ 0x90080000L, 0x00000000L,
+ 0x60000040L, 0x00000000L,
+ 0x9F030000L, 0x0000AA01L,
+ 0x1F000000L, 0x0000001CL,
+ 0x80840004L, 0x000001E8L,
+ 0x7C027F00L, 0x00000000L,
+ 0x7A070100L, 0x00000000L,
+ 0x60000040L, 0x00000000L,
+ 0x48000000L, 0x00000000L,
+ 0x98080000L, 0x0000AA02L,
+ 0x60000040L, 0x00000000L,
+ 0x98080000L, 0x0000AA04L,
+ 0x7C027F00L, 0x00000000L,
+ 0x7A070100L, 0x00000000L,
+ 0x60000040L, 0x00000000L,
+ 0x48000000L, 0x00000000L,
+ 0x98080000L, 0x0000AA03L,
+ 0x7C027F00L, 0x00000000L,
+ 0x7A070100L, 0x00000000L,
+ 0x60000040L, 0x00000000L,
+ 0x48000000L, 0x00000000L,
+ 0x98080000L, 0x0000AA00L,
+ 0x60000040L, 0x00000000L,
+ 0x87830000L, 0x00000150L,
+ 0x1F000000L, 0x0000001CL,
+ 0x808C0003L, 0x00000038L,
+ 0x80840002L, 0x00000060L,
+ 0x60000040L, 0x00000000L,
+ 0x1F000000L, 0x0000001CL,
+ 0x80840003L, 0x00000048L,
+ 0x60000040L, 0x00000000L,
+ 0x1F000000L, 0x0000001CL,
+ 0x98080000L, 0x0000AA1CL,
+ 0x60000040L, 0x00000000L,
+ 0x1F000000L, 0x0000001CL,
+ 0x80840001L, 0x00000018L,
+ 0x60000040L, 0x00000000L,
+ 0x1F000000L, 0x00000044L,
+ 0x98080000L, 0x0000AA0CL,
+ 0x58000008L, 0x00000000L,
+ 0x60000040L, 0x00000000L,
+ 0x878B0000L, 0x00000020L,
+ 0x86020000L, 0x000004C8L,
+ 0x1E000000L, 0x00000024L,
+ 0x868B0000L, 0x000000A8L,
+ 0x80880000L, 0xFFFFFDF8L,
+ 0x1F000000L, 0x0000001CL,
+ 0x60000040L, 0x00000000L,
+ 0x878B0000L, 0xFFFFFFE8L,
+ 0x80880000L, 0xFFFFFFC0L,
+ 0x98080000L, 0x0000FF0EL,
+ 0x58000008L, 0x00000000L,
+ 0x60000040L, 0x00000000L,
+ 0x86830000L, 0x00000060L,
+ 0x1E000000L, 0x0000002CL,
+ 0x98080000L, 0x0000FF0AL,
+ 0x54000000L, 0x00000020L,
+ 0x7C07FE00L, 0x00000000L,
+ 0x87820000L, 0xFFFFFFF8L,
+ 0x1F000000L, 0x0000001CL,
+ 0x98080000L, 0x00000080L,
+ 0x721A0000L, 0x00000000L,
+ 0x98080000L, 0x0000AA05L,
+ 0x47000000L, 0xFFFFFFC0L,
+ 0x7C07FE00L, 0x00000000L,
+ 0x80880000L, 0x00000010L,
+ 0x58000008L, 0x00000000L,
+ 0x60000040L, 0x00000000L,
+ 0x9E030000L, 0x0000FF08L,
+ 0x7C027F00L, 0x00000000L,
+ 0x1E000000L, 0x0000003CL,
+ 0x7A070100L, 0x00000000L,
+ 0x48000000L, 0x00000000L,
+ 0x98080000L, 0x0000FF07L,
+ 0x47000000L, 0xFFFFFF68L,
+ 0x7C07FE00L, 0x00000000L,
+ 0x9E030000L, 0x0000FF11L,
+ 0x7C027F00L, 0x00000000L,
+ 0x1E000000L, 0x00000034L,
+ 0x7A070100L, 0x00000000L,
+ 0x48000000L, 0x00000000L,
+ 0x98080000L, 0x0000FF10L,
+ 0x60000040L, 0x00000000L,
+ 0x1F000000L, 0x0000001CL,
+ 0x98040020L, 0x0000FF0FL,
+ 0x60000040L, 0x00000000L,
+ 0x1F000000L, 0x0000001CL,
+ 0x98080000L, 0x0000AA06L
+
+};
+
+#define A_SCSIMESS_COMMAND_COMPLETE 0x00000000L
+#define A_SelectDataOff 0x00000000L
+#define A_SCSIMESS_EXTENDED_MESSAGE 0x00000001L
+#define A_SCSIMESS_SYNCHRONOUS_DATA_REQ 0x00000001L
+#define A_SCSIMESS_SAVE_DATA_POINTER 0x00000002L
+#define A_SCSIMESS_WIDE_DATA_REQUEST 0x00000003L
+#define A_SCSIMESS_RESTORE_POINTERS 0x00000003L
+#define A_SCSIMESS_DISCONNECT 0x00000004L
+#define A_CDBDataOff 0x00000004L
+#define A_SCSIMESS_MESSAGE_REJECT 0x00000007L
+#define A_MsgOutOff 0x0000000CL
+#define A_StatusDataOff 0x00000014L
+#define A_OneByteMsgOff 0x0000001CL
+#define A_SCSIMESS_SIMPLE_QUEUE_TAG 0x00000020L
+#define A_RejectMsgOff 0x00000024L
+#define A_ParityMsgOff 0x0000002CL
+#define A_AbortMsgOff 0x00000034L
+#define A_BDRMsgOff 0x0000003CL
+#define A_TwoByteMsgOff 0x00000044L
+#define A_SGEntry18Off 0x0000004CL
+#define A_SGEntry17Off 0x00000054L
+#define A_SGEntry16Off 0x0000005CL
+#define A_SGEntry15Off 0x00000064L
+#define A_SGEntry14Off 0x0000006CL
+#define A_SGEntry13Off 0x00000074L
+#define A_SGEntry12Off 0x0000007CL
+#define A_ReselByTarget 0x00000080L
+#define A_SCSIMESS_IDENTIFY 0x00000080L
+#define A_SGEntry11Off 0x00000084L
+#define A_SGEntry10Off 0x0000008CL
+#define A_SGEntry09Off 0x00000094L
+#define A_SGEntry08Off 0x0000009CL
+#define A_SGEntry07Off 0x000000A4L
+#define A_SGEntry06Off 0x000000ACL
+#define A_SGEntry05Off 0x000000B4L
+#define A_SGEntry04Off 0x000000BCL
+#define A_SGEntry03Off 0x000000C4L
+#define A_SGEntry02Off 0x000000CCL
+#define A_SGEntry01Off 0x000000D4L
+#define A_CommandOk 0x0000AA00L
+#define A_Save_Pointers 0x0000AA01L
+#define A_Save_with_Disc 0x0000AA02L
+#define A_Device_Discon 0x0000AA03L
+#define A_Restore_Pointers 0x0000AA04L
+#define A_ScriptsAborted 0x0000AA05L
+#define A_Tag_Received 0x0000AA06L
+#define A_SynchNegotComp 0x0000AA0CL
+#define A_WideNegotComp 0x0000AA1CL
+#define A_DeviceReset 0x0000FF07L
+#define A_ResetFailed 0x0000FF08L
+#define A_ParityMessageSent 0x0000FF0AL
+#define A_MessageRejected 0x0000FF0EL
+#define A_InvalidTaggedMessage 0x0000FF0FL
+#define A_DeviceAborted 0x0000FF10L
+#define A_AbortFailed 0x0000FF11L
+#define Ent_AbortExecution 0x000004A0L
+#define Ent_AbortDevice 0x00000508L
+#define Ent_CommandScriptStart 0x00000000L
+#define Ent_ContNegScript 0x000001F0L
+#define Ent_DataIn01 0x000001D0L
+#define Ent_DataIn18 0x00000148L
+#define Ent_DataOut01 0x00000128L
+#define Ent_DataOut18 0x000000A0L
+#define Ent_DataInJump 0x00000070L
+#define Ent_DataOutJump 0x00000078L
+#define Ent_ExtMsgRcvd 0x00000368L
+#define Ent_EndOfScript 0x00000578L
+#define Ent_GetStatus 0x00000088L
+#define Ent_MessageIn 0x00000268L
+#define Ent_ProcessDisconnect 0x00000318L
+#define Ent_ProcessSelectReselect 0x00000488L
+#define Ent_QueueTagMessage 0x00000548L
+#define Ent_RejectMessage 0x000003F0L
+#define Ent_RejectIN 0x00000428L
+#define Ent_RejectReceived 0x00000448L
+#define Ent_ReselectScript 0x00000478L
+#define Ent_ResetDevice 0x000004B0L
+#define Ent_RestPtrsRcvd 0x00000308L
+#define Ent_RestartScript 0x00000220L
+#define Ent_SaveDataPointers 0x000002C0L
+#define Ent_SendCommand 0x00000048L
+#define Ent_SendErrorMessage 0x00000450L
+#define Ent_SendID 0x00000020L
+#define Ent_SendReject 0x00000408L
+#define Ent_SyncMsgNegot 0x000003C0L
+
+
+ULONG LABELPATCHES[] = {
+ 0x00000103L
+};
+
+#define INSTRUCTIONS 0x000000AFL
diff --git a/private/ntos/miniport/symbios/symc810/sources b/private/ntos/miniport/symbios/symc810/sources
new file mode 100644
index 000000000..df6c3b7ae
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/sources
@@ -0,0 +1,39 @@
+!IF 0
+/************************************************************************
+* *
+* Copyright 1994 Symbios Logic inc. All rights reserved. *
+* *
+* This file is confidential and a trade secret of Sybios Corp. *
+* The receipt of or possession of this file does not convey any *
+* rights to reproduce or disclose its contents or to manufacture, *
+* use, or sell anything is may describe, in whole, or in part, *
+* without the specific written consent of Symbios Logic Inc. *
+* *
+************************************************************************/
+
+/*+++HDR
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Who? Description
+ * -------- ---- -------------------------------------------------------
+ *
+ *
+---*/
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=symc810
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\..\inc
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES= symc810.c \
+ symc810.rc
+
diff --git a/private/ntos/miniport/symbios/symc810/symc810.c b/private/ntos/miniport/symbios/symc810/symc810.c
new file mode 100644
index 000000000..89abf9b23
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/symc810.c
@@ -0,0 +1,9200 @@
+/*
+***********************************************************************
+* *
+* Copyright 1994 Symbios Logic Inc. All rights reserved. *
+* *
+* This file is confidential and a trade secret of Sybios Logic Inc. *
+* The receipt of or possession of this file does not convey any *
+* rights to reproduce or disclose its contents or to manufacture, *
+* use, or sell anything is may describe, in whole, or in part, *
+* without the specific written consent of Symbios Logic Inc. *
+* *
+************************************************************************/
+
+/*+++HDR
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Who? Description
+ * -------- ---- -------------------------------------------------------
+ * 2-23-95 SAM no longer negotiate wide/sync only on LUN 0
+ * on reselections we now set the chip to the wide and sync
+ * parms of the reselecting Target values.
+ * above changes for 1.02.03
+ *
+ * 3-14-95 SAM incorporated SCAM code to the 1.02.05 base
+ *
+ * 3-14-95 SAM incorporated FAST20 Logic into code
+ *
+ * 7-7-95 SAM put in support for the 825A and 875 Script Ram buffer.
+ * Increased burst sizes of all chips to 16 from 8 and for
+ * the 825A and 875 it is 128.
+ * Converted to memory mapped IO instead of port IO.
+ *
+ * 7-14-95 SAM Incorporated the nvram utilities. Changed the burst length
+ * to 8 on all chips except the 875 and 825A parts which are
+ * set to 64. This should allow for better system utilization
+ * since we will get onto the PCI bus when the fifo is half
+ * full and not full leaving more room for bus latency.
+ * For 875/825A parts- do not use the prefetch unit because it
+ * gives problems when using burst lengths of 64 ( since we're
+ * using scripts ram on these parts anyway the prefetch unit
+ * doesn't really buy us a thing)
+ *
+ * 4XX BIOS config utility leaves the SCAM Portion of the
+ * nvram all zeroes. Therefore no work was done on incorp-
+ * orating the users SCAM ID values onto SCAM devices was done.
+ * (the structure is still read at this time, nothing done in
+ * SCAM code though)
+ * Base for DULUTH 1.92.01 code - initial GCA source base
+ *
+ * 7-20-95 SAM made a change so 95 will run with Port IO and NT memory
+ * mapped. If 95 changed to memory mapped too remember to
+ * change the scsiportreadPORTuchar call in the de_glitch rtn
+ * to do REGISTER IO. DULUTH-1.92.02
+ *
+ * 7-21-95 SAM added a parameter fro scam code - initial_run - so the scam
+ * function will be done all at once on the driver initializa-
+ * tion pass, and use the system timer calls to split up the
+ * function during reset processing. change needed because
+ * with timer calls the driver was holding off the OS during
+ * its initial bus scan ( waiting for scam to finish ) that it
+ * would stop looking for device ID 0 and first see devices
+ * with ID of 1. DULUTH-1.92.03
+ *
+ * 7-25-95 SAM took out the script ram feature for Windows 95, the access-
+ * ing of the physical memory during Script loading (?) causes
+ * 95 to bomb. Also changed the device ID to F from f for the
+ * 875 chip. 95 wants the ID in upper case.
+ *
+ * 7-26-95 SAM Well NT wants the ID of the 875 part in lower case, so now
+ * there is an ifdef around this declaration.
+ *
+ * 9-26-95 SAM Added autorequest sense capabilities to the driver.
+ *
+ * 1-2-96 SPD 1) PreFetch has been disabled due to chip problems.
+ * 2) If an unexpected disconnect occurrs during wide/sync
+ * negotiations, mark the dev. as not supporting wide/sync
+ * 3) Added a check in ISR_Service_Next to verify the function
+ * being requested before calling 'StartSCSIRequest'.
+ *
+ * 1-23-96 SPD 1) Deleted the bus reset done in SymHWInitialize. In order
+ * to acheive the same results without doing the reset, we
+ * will negotiate async/narrow on first I/O to every device
+ * until the O/S tells us to go Sync and/or Wide.
+ * 2) Changes to do wide/sync negotiations on same IO.
+ * 3) Added new conditional compile define 'PORT_IO', replaced
+ * 'FOR_95' in FinadAdapter routine to determine port or
+ * memory mapped IO.
+ * 4) Set/reset DFLAGS QUE_Bit on Reselection for Queueing.
+ * DULUTH-2.00.04
+ *
+ * 3-15-96 SCH Modified save_reg, restore_reg, & AdapterState to save
+ * SIOP registers at driver init and restore them at driver
+ * shutdown. (Used only by Win 95 at shutdown and for
+ * reboot to MS-DOS mode.) Eliminated setting of HAB SCSI ID
+ * in FindAdapter (it's done in InitializeSIOP). Also moved
+ * setting of large FIFO from FindAdapter to InitializeSIOP.
+ *
+ * 4-1-96 SPD For Win95, added back in the bus reset at init time.
+ * In general, added verify for memory mapped addrs, change to
+ * add device exclusion option, put an entry in the error log
+ * with ASC/ASCQ values for check conditions.
+ *
+ * 4-26-96 SCH Fixed multiple problems with auto request sense routines.
+ * - Clear SCSI/DMA interrupts (DSTAT,SIST0,SIST1)
+ * - Added code to handle phase mismatch during reselection
+ * - Scatter/Gather changed to use proper (current) SRB
+ * - Changed ReqSnsCmdDoneRtn to use ISR_Service_Next routine
+ * (scripts were not always being restarted after Req Sns
+ * Changed ResetSCSIBus to check for valid Srb before using
+ * LuFlags
+ * Changed SetupLuFlags to keep WIDE_NEGOT_DONE set after a
+ * bus reset if wide negotiation had failed
+ * Fixed problem with hang if bus reset called during auto
+ * request sense processing
+ * Added read of SIST1 in AbortScript routine to clear SIP
+ * bit in ISTAT
+ *
+ * 6-10-96 SCH Removed auto request sense routines at Microsoft's
+ * request. Use ScsiPortWriteRegister routines when using
+ * Scripts RAM to copy scripts and patch instructions.
+ * (Alpha Scripts RAM fix.) Added target ID parameter to
+ * ProcessWideNotSupported (fix blue screen on some bus
+ * resets). Read SIST1 in AbortCurrentScript.
+ *
+---*/
+
+//
+// include files used by the Miniport
+//
+//#define FOR_95 // this define opens up the SCAM protocall code.
+//#define PORT_IO // this define specifies port IO for Win95 or Winnt driver.
+
+#include "miniport.h"
+#include "scsi.h"
+#include "symc810.h"
+#include "scrpt810.h"
+#include "symsiop.h"
+#include "symnvm.h"
+
+#ifdef FOR_95
+#include "symscam.h"
+#endif
+
+//
+// Define the 53C8xx Logical Unit Extension structure
+//
+
+typedef struct _SPECIFIC_LOGICAL_UNIT_EXTENSION {
+ PSCSI_REQUEST_BLOCK UntaggedRequest;
+} SPECIFIC_LOGICAL_UNIT_EXTENSION, *PSPECIFIC_LOGICAL_UNIT_EXTENSION;
+
+//
+// Define the SRB Extension.
+//
+
+typedef struct _SRB_EXTENSION {
+ CDB Cdb;
+ ULONG SavedDataPointer; // saved data pointer and
+ ULONG SavedDataLength; // length
+ ULONG DataTransferred; // data transferred so far
+ UCHAR SGMovesComplete; // # of scatter/gather moves
+ UCHAR PhysBreakCount; // physical break count
+}SRB_EXTENSION, *PSRB_EXTENSION;
+
+
+#define SRB_EXT(x) ((PSRB_EXTENSION)(x->SrbExtension))
+
+//
+// Symbios 53C8xx script data structure
+//
+
+typedef struct _SCRIPT_DATA_STRUCT {
+
+//
+// Define the Scripts firmware interface structure.
+//
+// NOTE THAT THIS STRUCTURE MUST BE IN SYNC WITH THE STRUCTURE IN SCRIPTS.
+// IF ANYTHING IN THIS STRUCTURE CHANGES, THE EQUIVALENT STRUCTURE
+// IN SCRIPTS.ASM MUST ALSO BE CHANGED, SINCE THERE IS NO WAY TO LINK UP THE
+// TWO STRUCTURES AUTOMATICALLY.
+//
+
+//
+// set up the data table for selection
+//
+
+ UCHAR SelectDataRes1; // reserved - MBZ
+ UCHAR SelectDataSXFER; // Synchronous parameters
+ UCHAR SelectDataID; // ID to be selected
+ UCHAR SelectDataSCNTL3; // SCSI Control 3
+
+//
+// set up the structure for the CDB
+//
+
+ ULONG CDBDataCount; // size of CDB
+ ULONG CDBDataBuff; // pointer to CDB
+
+//
+// set up the structure for the MESSAGE OUT buffer
+//
+
+ ULONG MsgOutCount; // number of bytes of MESSAGE OUT data
+ ULONG MsgOutBuf; // pointer to MESSAGE OUT buffer
+
+//
+// set up the structure for status
+//
+
+ ULONG StatusDataCount; // size of STATUS buffer
+ ULONG StatusDataBuff; // pointer to STATUS buffer
+
+//
+// set up the structure for one-byte messages
+//
+
+ ULONG OneByteMsgCount; // size of one-byte message !!
+ ULONG OneByteMsgBuff; // pointer to message-in buff
+
+//
+// set up the structure for MESSAGE REJECT message
+//
+
+ ULONG RejectMsgCount; // size of reject message
+ ULONG RejectMsgBuff; // pointer to reject message
+
+//
+// set up the structure for parity error message
+//
+
+ ULONG ParityMsgCount; // size of parity message
+ ULONG ParityMsgBuff; // pointer to parity message
+
+//
+// set up the structure for ABORT message
+//
+
+ ULONG AbortMsgCount; // size of abort message
+ ULONG AbortMsgBuff; // pointer to abort message
+
+//
+// set up the structure for the BUS DEVICE RESET message
+//
+ ULONG BDRMsgCount; // size of BDR message
+ ULONG BDRMsgBuff; // pointer to BDR message
+
+//
+// set up the structure for two-byte messages
+//
+
+ ULONG TwoByteMsgCount; // # of bytes in two byte message
+ ULONG TwoByteMsgBuff; // pointer to two byte message buff
+
+//
+// what follows are the data blocks for each scatter/gather move instruction
+//
+ SCRIPTSG SGBufferArray[ MAX_PHYS_BREAK_COUNT];
+
+} SCRIPTDATASTRUCT, *PSCRIPTDATASTRUCT;
+
+//
+// Define the noncached extension. Data items are placed in the noncached
+// extension because they are accessed via DMA.
+//
+
+typedef struct _HW_NONCACHED_EXTENSION {
+
+//
+// define the array for the SCSI scripts
+//
+
+ SCRIPTINS ScsiScripts[ sizeof(SCRIPT) / sizeof(SCRIPTINS) ];
+
+//
+// define area for script data structure.
+//
+
+ SCRIPTDATASTRUCT ScriptData; // 53C8xx script data structure
+
+//
+// define storage locations for the messages sent by SCSI scripts.
+// an element in the script data structure is set up for each of these
+// storage locations.
+//
+
+ UCHAR MsgOutBuf[MESSAGE_BUFFER_SIZE]; // buffer for message out data
+ UCHAR MsgInBuf[MESSAGE_BUFFER_SIZE]; // buffer for message in data
+ UCHAR StatusData; // buffer for status
+ UCHAR RejectMsgData; // buffer for reject message
+ UCHAR ParityMsgData; // buffer for parity message
+ UCHAR AbortMsgData; // buffer for abort message
+ UCHAR BDRMsgData; // buffer for BDR message
+
+} HW_NONCACHED_EXTENSION, *PHW_NONCACHED_EXTENSION;
+
+//
+// Define the 53C8xx Device Extension structure
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ PHW_NONCACHED_EXTENSION NonCachedExtension; // pointer to noncached
+ // device extension
+ PSIOP_REGISTER_BASE SIOPRegisterBase; // 53C8xx SIOP register base.
+
+ USHORT DeviceFlags; // bus specific flags
+ UCHAR SIOPBusID; // SCSI bus ID in integer form.
+ UCHAR ScsiBusNumber; // This value increments up for each SCSI
+ // bus on the system, starting with zero.
+ UCHAR BusNumber; // This value is the bus number for this
+ // particular SCSI controller. Since all
+ // current Symbios controllers support only one
+ // bus, this value is always zero.
+
+//
+// script physical address entry points follow...
+//
+
+ ULONG DataOutStartPhys; // phys ptr to data out script
+ ULONG DataInStartPhys; // phys ptr to data in script
+ ULONG WaitReselectScriptPhys; // phys ptr to wait resel script
+ ULONG RestartScriptPhys; // phys ptr to restart script
+ ULONG ContNegScriptPhys; // phys ptr to continue negotiations script
+ ULONG CommandScriptPhys; // phys ptr to cmd start script
+ ULONG SendIDEScriptPhys; // phys ptr to IDE message script
+ ULONG AbortScriptPhys; // phys ptr to abort message script
+ ULONG ResetDevScriptPhys; // phys ptr to bus device reset msg script
+ ULONG RejectScriptPhys; // phys ptr to reject message script
+ ULONG QueueTagPhys; // phys ptr to queue tag script
+ ULONG DSAAddress; // phys ptr to script buffer
+
+//
+// Used for script patching
+//
+ PVOID DataInJumpVirt;
+ PVOID DataOutJumpVirt;
+
+//
+// define depth counter for disconnected requests. we only start the WAIT
+// RESELECT script instruction if there are disconnected requests pending.
+//
+
+ ULONG DisconnectedCount[SYM_MAX_TARGETS];
+
+//
+// define pointers to the active logical unit object and request
+//
+
+ PSCSI_REQUEST_BLOCK ActiveRequest; // pointer to active LU
+ PSCSI_REQUEST_BLOCK NextSrbToProcess; // pointer to the next SRB.
+//
+// logical unit specific flags and logical unit index
+//
+
+ USHORT LuFlags[SYM_MAX_TARGETS]; // logical unit spec. flags
+ UCHAR SyncParms[SYM_MAX_TARGETS]; // synch parameter composite
+ UCHAR WideParms[SYM_MAX_TARGETS]; // wide parameter composite
+ UCHAR ClockSpeed; // SIOP clock speed
+ UCHAR TargetId;
+ UCHAR LUN;
+ UCHAR scam_completed;
+ USHORT hbaCapability;
+ UCHAR nextstate;
+ UCHAR current_state;
+ ULONG timer_value;
+
+//
+// Set up patch array for both data in and data out. Note that
+// the array size is larger than the number of scatter/gather
+// elements to aid ease of patching.
+//
+
+ ULONG dataInPatches[MAX_SG_ELEMENTS + 1];
+ ULONG dataOutPatches[MAX_SG_ELEMENTS + 1];
+
+// used to hold off system queued cmds to a target that has a contingient
+// allegience condition
+ UCHAR CA_Condition[SYM_MAX_TARGETS][SCSI_MAXIMUM_LOGICAL_UNITS];
+
+ UCHAR preserved_reg;
+
+#ifdef FOR_95
+//
+// SCAM variables
+//
+ SIOP_REG_STORE AdapStateStore; // SIOP reg storage for AdapterState
+ SIOP_REG_STORE ScamStore; // SIOP reg storage for SCAM
+ UCHAR initial_run;
+ UCHAR checkseen;
+ UCHAR sna_delay;
+ UCHAR eatint_flag;
+ ULONG ID_map;
+ UINT8 NumValidScamDevices;
+ SCAM_TABLE ScamTables[HW_MAX_SCAM_DEVICES];
+#endif
+
+ ULONG ScriptRamPhys;
+ PULONG ScriptRamVirt;
+
+// extra resources for the nvram values
+ UINT8 UsersHBAId;
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+typedef struct
+{
+ UCHAR hbaCount;
+ USHORT hbaCapability;
+ ULONG hbaDeviceID;
+} HWInfo, *PHWInfo;
+
+// variable used for a loop within the SCAM protocall code
+ UCHAR i;
+
+/* The following macros are used to simplify reading of the nvram code.
+ *
+ * DATA_MASK - This is the GPREG bit used as a data line.
+ * CLOCK_MASK - This is the GPREG bit used as a clock line.
+ */
+
+#define DATA_OUTPUT() WRITE_SIOP_UCHAR(GPCNTL,(UCHAR)(READ_SIOP_UCHAR(GPCNTL) \
+ & (~DATA_MASK)) )
+
+#define DATA_INPUT() WRITE_SIOP_UCHAR(GPCNTL,(UCHAR)(READ_SIOP_UCHAR(GPCNTL) \
+ | DATA_MASK) )
+
+#define SET_DATA() WRITE_SIOP_UCHAR( GPREG,(UCHAR)(READ_SIOP_UCHAR(GPREG) \
+ | DATA_MASK) )
+
+#define RESET_DATA() WRITE_SIOP_UCHAR(GPREG,(UCHAR)(READ_SIOP_UCHAR(GPREG) \
+ & (~DATA_MASK)) )
+
+#define SET_CLOCK() WRITE_SIOP_UCHAR(GPREG,(UCHAR)(READ_SIOP_UCHAR(GPREG) \
+ | CLOCK_MASK) )
+
+#define RESET_CLOCK() WRITE_SIOP_UCHAR(GPREG,(UCHAR)(READ_SIOP_UCHAR(GPREG) \
+ & (~CLOCK_MASK)) )
+
+//
+// Symbios 53C8xx miniport driver function declarations.
+//
+
+BOOLEAN NvmDetect( PHW_DEVICE_EXTENSION DeviceExtension );
+void NvmSendStop( PHW_DEVICE_EXTENSION DeviceExtension );
+void NvmSendStart( PHW_DEVICE_EXTENSION DeviceExtension );
+UINT NvmSendData( PHW_DEVICE_EXTENSION DeviceExtension, UINT Value );
+UINT8 NvmReadData( PHW_DEVICE_EXTENSION DeviceExtension );
+void NvmSendAck( PHW_DEVICE_EXTENSION DeviceExtension );
+UINT NvmReceiveAck( PHW_DEVICE_EXTENSION DeviceExtension );
+void NvmSendNoAck( PHW_DEVICE_EXTENSION DeviceExtension);
+
+MEMORY_STATUS HwReadNonVolatileMemory( PHW_DEVICE_EXTENSION DeviceExtension,
+ UINT8 *Buffer,
+ UINT Offset, UINT Length );
+
+UINT16 CalculateCheckSum(UINT8 * PNvmData, UINT16 Length);
+BOOLEAN RetrieveNvmData( PHW_DEVICE_EXTENSION DeviceExtension);
+void InvalidateNvmData( PHW_DEVICE_EXTENSION DeviceExtension );
+UCHAR set_8xx_clock(PHW_DEVICE_EXTENSION DeviceExtension);
+UCHAR set_875_multipler( PHW_DEVICE_EXTENSION DeviceExtension );
+
+
+#ifdef FOR_95
+VOID scam_scan(PHW_DEVICE_EXTENSION DeviceExtension);
+UCHAR EatInts(PHW_DEVICE_EXTENSION DeviceExtension);
+VOID EnterLLM(PHW_DEVICE_EXTENSION DeviceExtension);
+VOID ExitLLM(PHW_DEVICE_EXTENSION DeviceExtension);
+VOID init_send_byte(LONG dbyte,PHW_DEVICE_EXTENSION DeviceExtension);
+UCHAR init_recv_byte(PHW_DEVICE_EXTENSION DeviceExtension);
+VOID SCAM_Arbitrate(PHW_DEVICE_EXTENSION DeviceExtension);
+VOID SCAM_release(PHW_DEVICE_EXTENSION DeviceExtension);
+VOID SCAM_master_select(PHW_DEVICE_EXTENSION DeviceExtension);
+UCHAR SCAM_xfer(UCHAR quintet,PHW_DEVICE_EXTENSION DeviceExtension);
+LONG SCAM_isolate(UCHAR *outstr, UCHAR *instr, UCHAR *greatest_ID,
+ UCHAR *desired_ID, UCHAR function,
+ PHW_DEVICE_EXTENSION DeviceExtension);
+VOID SCAM_assign_IDs(PHW_DEVICE_EXTENSION DeviceExtension);
+VOID Find_nonSCAM_IDs(PHW_DEVICE_EXTENSION DeviceExtension);
+VOID restore_reg (PHW_DEVICE_EXTENSION DeviceExtension,
+ PSIOP_REG_STORE RegStore);
+VOID save_reg (PHW_DEVICE_EXTENSION DeviceExtension,
+ PSIOP_REG_STORE RegStore);
+VOID ISR_Service_Next(PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR ISRDisposition);
+VOID de_glitch(ULONG offset,UCHAR value,PHW_DEVICE_EXTENSION DeviceExtension);
+void delay_mils( USHORT counter);
+#endif
+
+BOOLEAN
+AbortCurrentScript(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+BusResetPostProcess(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+clear_CA_Condition(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+ComputeSCSIScriptVectors(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+VOID
+InitializeSIOP(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+IsCompaqSystem(
+ IN PVOID DeviceExtension,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ );
+
+BOOLEAN
+Sym8xxAdapterState(
+ IN PVOID Context,
+ IN PVOID ConfigContext,
+ IN BOOLEAN SaveState
+ );
+
+ULONG
+Sym8xxFindAdapter(
+ PVOID Context,
+ PVOID ConfigContext,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+Sym8xxHWInitialize(
+ IN PVOID Context
+ );
+
+BOOLEAN
+Sym8xxISR(
+ IN PVOID Context
+ );
+
+BOOLEAN
+Sym8xxReset(
+ IN PVOID DeviceExtension,
+ IN ULONG PathId
+ );
+
+BOOLEAN
+Sym8xxStartIo(
+ IN PVOID Context,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+UCHAR
+ProcessAbortOccurred(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessBusResetReceived(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessCommandComplete(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessDeviceResetFailed(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessDeviceResetOccurred(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessDisconnect(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessDMAInterrupt(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR DmaStatus
+ );
+
+UCHAR
+ProcessErrorMsgSent(
+ VOID
+ );
+
+UCHAR
+ProcessGrossError(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessIllegalInstruction(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessInvalidReselect(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessParityError(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessPhaseMismatch(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+ProcessParseArgumentString(
+ PCHAR String,
+ PCHAR WantedString,
+ PULONG ValueWanted
+ );
+
+UCHAR
+ProcessQueueTagReceived(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessRejectReceived(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessReselection(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR TargetID
+ );
+
+UCHAR
+ProcessRestorePointers(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessSaveDataPointers(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessSCSIInterrupt(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR ScsiStatus
+ );
+
+UCHAR
+ProcessSelectionTimeout(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessSynchNegotComplete(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessSynchNotSupported(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+UCHAR
+ProcessUnexpectedDisconnect(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+ResetPeripheral(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+ResetSCSIBus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+ScatterGatherScriptSetup(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSRB_EXTENSION SrbExtension
+ );
+
+VOID
+SetupLuFlags(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR ResetFlag
+ );
+
+UCHAR
+ProcessWideNotSupported(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR DestId
+ );
+
+UCHAR
+ProcessWideNegotComplete(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+StartSCSIRequest(
+ PSCSI_REQUEST_BLOCK Srb,
+ PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+StartSIOP(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG ScriptPhysAddr
+ );
+
+
+BOOLEAN
+AbortCurrentScript(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+
+ This routine aborts the script instruction currently processing,
+ and clears the SCRIPT_RUNNING flag after scripts have stopped.
+
+Arguments:
+
+ DeviceExtension - Supplies the device Extension for the SCSI bus adapter.
+
+Return Value:
+
+ True - abort sucessful
+ False - abort unsucessful
+
+--*/
+
+{
+ UCHAR IntStat;
+ UCHAR AbortIteration = 0;
+
+AbortScript:
+
+ //
+ // set script abort bit high
+ //
+
+ WRITE_SIOP_UCHAR( ISTAT, ISTAT_ABORT);
+
+ //
+ // spin for an interrupt (either DMA or SCSI)
+ //
+
+ do
+ {
+ IntStat = READ_SIOP_UCHAR( ISTAT);
+
+ //
+ // if we are in the second or greater iteration of this loop..
+ //
+
+ if (AbortIteration++)
+ {
+
+ //
+ // wait a moment
+ //
+
+ ScsiPortStallExecution( ABORT_STALL_TIME);
+
+ //
+ // if we have exceeded our maximum loop count, we reset the
+ // SIOP and SCSI bus in hopes that whatever has freaked the
+ // SIOP out will be corrected.
+ //
+
+ if (AbortIteration > MAX_ABORT_TRIES)
+ {
+
+ DebugPrint((1,
+ "Sym8xx(%2x): AbortCurrentScript timeout - ISTAT = %x\n",
+ DeviceExtension->SIOPRegisterBase,
+ IntStat));
+
+ // If can't get DMA_INT bit to set, assume that abort of script
+ // worked and break to check DSTAT for abort bit below. If not
+ // set, will loop to restart abort sequence again
+ break;
+
+ } // if
+ } // if
+ } while ( !( IntStat & ( ISTAT_SCSI_INT | ISTAT_DMA_INT)));
+
+ if ( IntStat & ISTAT_SCSI_INT)
+ {
+
+ //
+ // Note that we ignore any SCSI interrupts at this time,
+ // since no SCSI error should occur in this section of
+ // code. We make this assumption since nothing was
+ // connected to the bus when this path was entered, and
+ // interrupts are synchronized, so the only thing a device
+ // could have done at this point is reselected.
+ //
+
+ //
+ // read SCSI interrupts to clear ISTAT.
+ //
+
+ READ_SIOP_UCHAR(SIST0);
+ READ_SIOP_UCHAR(SIST1);
+
+ //
+ // go back to abort
+ //
+
+ goto AbortScript;
+ } // if
+
+ //
+ // A DMA interrupt has occured.
+ //
+ // Note that we ignore any DMA interrupts other than ABORTED
+ // at this time, since no DMA error should occur in this section
+ // of code. We make this assumption since nothing was connected
+ // to the bus when this path was entered, and interrupts are
+ // synchronized, so the only thing a device could have done
+ // at this point is reselected.
+ //
+
+ //
+ // clear the ABORT bit in ISTAT.
+ //
+
+ WRITE_SIOP_UCHAR( ISTAT, 0);
+
+ //
+ // if interrupt was not ABORT, just go back to try to abort again.
+ //
+
+ if ( !( READ_SIOP_UCHAR( DSTAT) & DSTAT_ABORTED))
+ {
+ goto AbortScript;
+ }
+
+ //
+ // We have now successfully aborted script execution, so indicate
+ // that scripts have stopped.
+ //
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_SCRIPT_RUNNING;
+
+ //
+ // write script buffer start address to DSA register.
+ //
+
+ WRITE_SIOP_ULONG( DSA, DeviceExtension->DSAAddress);
+
+ return TRUE;
+
+} // AbortCurrentScript
+
+
+VOID
+BusResetPostProcess(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine aborts any pending requests after a bus reset is received.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to device extension for the bus that
+ was reset.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ USHORT i;
+ UCHAR max_targets;
+
+
+ //
+ // Prepare the LU Flags for work.
+ //
+
+ SetupLuFlags( DeviceExtension, 1 );
+
+ //
+ // indicate no pending requests (these guys will be aborted below).
+ //
+
+ DeviceExtension->NextSrbToProcess = NULL;
+
+ DeviceExtension->ActiveRequest = NULL;
+
+ // clear the Contigent Allegience blocker
+ clear_CA_Condition(DeviceExtension);
+
+ //
+ // Complete all requests outstanding on this SCSI bus with
+ // SRB_STATUS_BUS_RESET completion code.
+ //
+
+ ScsiPortCompleteRequest( DeviceExtension,
+ DeviceExtension->BusNumber,
+ SP_UNTAGGED,
+ SP_UNTAGGED,
+ SRB_STATUS_BUS_RESET
+ );
+
+ //
+ // zero depth counter for disconnected requests
+ //
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)
+ {
+ max_targets = SYM_MAX_TARGETS;
+ }
+ else
+ {
+ max_targets = SYM_NARROW_MAX_TARGETS;
+ }
+
+ for ( i = 0; i < max_targets; i++ )
+ DeviceExtension->DisconnectedCount[i] = 0;
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_CONNECTED;
+
+#ifdef FOR_95
+ // set up flags for the SCAM code to work from
+ // only do SCAM if Single Ended
+ // if this is the scam run from our init code, do it straight away
+ // without the delay call of the OS
+ //
+ if ( !(READ_SIOP_UCHAR(STEST2) & STEST2_DIFF_MODE) )
+ {
+ if (DeviceExtension->initial_run)
+ {
+ scam_scan(DeviceExtension);
+ }
+ else
+ {
+ DeviceExtension->current_state=TRUE;
+ DeviceExtension->scam_completed=FALSE;
+ DebugPrint((0, "Sym8xx: Begin TimerCall... \n"));
+
+ ScsiPortNotification(RequestTimerCall,
+ DeviceExtension,
+ scam_scan,
+ 1000);
+
+ DebugPrint((0, "Sym8xx: Exiting BusResetPostProcess... \n"));
+ }
+ }
+ else
+ {
+ if ( !(DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED))
+ {
+ DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED;
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL
+ );
+ }
+
+ ScsiPortStallExecution( POST_RESET_STALL_TIME );
+ DeviceExtension->scam_completed=TRUE;
+ }
+
+#else
+ if ( !(DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED))
+ {
+ DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED;
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL
+ );
+ }
+
+ ScsiPortStallExecution( POST_RESET_STALL_TIME );
+ DeviceExtension->scam_completed=TRUE;
+#endif
+
+ return;
+
+} // BusResetPostProcess
+
+
+VOID
+clear_CA_Condition(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ This routine clears the Contingent Allegience blocking array.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR target, lun;
+
+ for (target = 0; target < SYM_MAX_TARGETS; target++)
+ {
+ for (lun = 0; lun < SCSI_MAXIMUM_LOGICAL_UNITS; lun++)
+ DeviceExtension->CA_Condition[target][lun] = 0;
+ }
+}
+
+VOID
+ComputeSCSIScriptVectors(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine computes 53C8xx script physical addresses, and fills in
+ device extension fields used by scripts.
+
+Arguments:
+
+ PHW_DEVICE_EXTENSION DeviceExtension
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG SegmentLength; // receives length of physical memory segment
+
+ PHW_NONCACHED_EXTENSION NonCachedExtPtr =
+ DeviceExtension->NonCachedExtension;
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+ PULONG ScriptArrayPtr;
+
+ // Added for SCRIPT patching.
+
+ PULONG dataInPatches = &DeviceExtension->dataInPatches[0];
+ PULONG dataOutPatches = &DeviceExtension->dataOutPatches[0];
+ ULONG patchInOffset;
+ ULONG patchOutOffset;
+ USHORT i;
+
+ //
+ // make local copy of scripts in device extension. Total copy size
+ // is # of instructions * (8 bytes / instruction).
+ //
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM)
+ {
+ ScriptArrayPtr = DeviceExtension->ScriptRamVirt;
+ }
+ else
+ {
+ ScriptArrayPtr=(PULONG) DeviceExtension->NonCachedExtension->ScsiScripts;
+ }
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM)
+ {
+ ScsiPortWriteRegisterBufferUchar((PUCHAR)ScriptArrayPtr,
+ (PUCHAR)SCRIPT,
+ INSTRUCTIONS * sizeof (SCRIPTINS));
+ }
+ else
+ {
+ ScsiPortMoveMemory( ScriptArrayPtr,
+ SCRIPT,
+ INSTRUCTIONS * sizeof(SCRIPTINS)
+ );
+ }
+
+ //
+ // the following code computes physical addresses of script entry points.
+ // note that the "Ent_..." constants are generated by the scripts
+ // compiler, and are byte indices into the script instruction array.
+ // we divide these constants by 4 to correctly index into the array,
+ // since each array element consists of a longword.
+ //
+
+ //
+ // compute command script start physical address
+ //
+ if ( !(DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM) )
+ {
+ DeviceExtension->CommandScriptPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_CommandScriptStart / 4],
+ &SegmentLength
+ ));
+
+
+ //
+ // compute data in script physical address
+ //
+
+ DeviceExtension->DataInStartPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_DataIn01 / 4],
+ &SegmentLength
+ ));
+
+ //
+ // compute data out script physical address
+ //
+
+ DeviceExtension->DataOutStartPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_DataOut01 / 4],
+ &SegmentLength
+ ));
+
+ //
+ // compute restart after reselection script phys address
+ //
+
+ DeviceExtension->RestartScriptPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_RestartScript / 4],
+ &SegmentLength
+ ));
+
+ //
+ // compute continue negotiation script phys address
+ //
+
+ DeviceExtension->ContNegScriptPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_ContNegScript / 4],
+ &SegmentLength
+ ));
+
+ //
+ // compute script send abort script phys address
+ //
+
+ DeviceExtension->AbortScriptPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_AbortDevice / 4],
+ &SegmentLength
+ ));
+
+ //
+ // compute script send bus device reset script phys address
+ //
+
+ DeviceExtension->ResetDevScriptPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_ResetDevice / 4],
+ &SegmentLength
+ ));
+
+ //
+ // compute reject message script phys address
+ //
+
+ DeviceExtension->RejectScriptPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_RejectMessage / 4],
+ &SegmentLength
+ ));
+
+ //
+ // compute wait for reselect script phys address
+ //
+
+ DeviceExtension->WaitReselectScriptPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_ReselectScript / 4],
+ &SegmentLength
+ ));
+
+ //
+ // compute wait for queue tag phys address
+ //
+
+ DeviceExtension->QueueTagPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_QueueTagMessage / 4],
+ &SegmentLength
+ ));
+
+ //
+ // Compute the IDE (Initiatior Detected Error)/MPE (Message Parity Error)
+ // message script routine phys address
+ //
+
+ DeviceExtension->SendIDEScriptPhys =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &ScriptArrayPtr[ Ent_SendErrorMessage / 4],
+ &SegmentLength
+ ));
+
+ }
+
+ else
+ {
+
+ DeviceExtension->CommandScriptPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_CommandScriptStart] - ScriptArrayPtr );
+
+ DeviceExtension->DataInStartPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_DataIn01] - ScriptArrayPtr );
+
+ DeviceExtension->DataOutStartPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_DataOut01] - ScriptArrayPtr );
+
+ DeviceExtension->RestartScriptPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_RestartScript] - ScriptArrayPtr );
+
+ DeviceExtension->ContNegScriptPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_ContNegScript] - ScriptArrayPtr );
+
+ DeviceExtension->AbortScriptPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_AbortDevice] - ScriptArrayPtr );
+
+ DeviceExtension->ResetDevScriptPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_ResetDevice] - ScriptArrayPtr );
+
+ DeviceExtension->RejectScriptPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_RejectMessage] - ScriptArrayPtr );
+
+ DeviceExtension->WaitReselectScriptPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_ReselectScript] - ScriptArrayPtr );
+
+ DeviceExtension->QueueTagPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_QueueTagMessage] - ScriptArrayPtr );
+
+ DeviceExtension->SendIDEScriptPhys =
+ DeviceExtension->ScriptRamPhys +
+ ( &ScriptArrayPtr[Ent_SendErrorMessage] - ScriptArrayPtr );
+ }
+
+
+ //
+ // Compute the patch address for the Data-In routine. Note that this
+ // is a virtual address.
+ //
+
+ DeviceExtension->DataInJumpVirt =
+ (PVOID) &ScriptArrayPtr[ Ent_DataInJump / 4];
+
+ //
+ // Compute the patch address for the Data-Out routine. Note that this
+ // is a virtual address.
+ //
+
+ DeviceExtension->DataOutJumpVirt =
+ (PVOID) &ScriptArrayPtr[ Ent_DataOutJump / 4];
+
+ //
+ // Set up first Data-In offset patch value.
+ //
+
+ patchInOffset = Ent_DataIn18 - Ent_DataInJump - SCRIPT_INS_SIZE;
+
+ //
+ // Set up first Data-Out offset patch value.
+ //
+
+ patchOutOffset = Ent_DataOut18 - Ent_DataOutJump - SCRIPT_INS_SIZE;
+
+ //
+ // Fill in offset table for Data In and Data Out patches. Note that
+ // the offset for a list of 7 segments will be in table entry 7. Entry
+ // zero will be unused.
+ //
+
+ for ( i = MAX_SG_ELEMENTS; i > 0; i-- )
+ {
+ dataInPatches[i] = patchInOffset;
+ dataOutPatches[i] = patchOutOffset;
+ patchInOffset += 8;
+ patchOutOffset += 8;
+ }
+
+ //
+ // Flag the zero element to aid in debugging.
+ //
+
+ dataInPatches[0] = 0xFACEBEAD;
+ dataOutPatches[0] = 0xFACEBEAD;
+
+ //
+ // fill in script structures required for table indirect script mode
+ // (see 53C8xx data manual fo details)
+ //
+
+ ScriptDataPtr->MsgOutCount = 0; // no message out bytes
+ ScriptDataPtr->StatusDataCount = 1; // STATUS buf is 1 byte
+ ScriptDataPtr->OneByteMsgCount = 1; // 1 byte messages
+ ScriptDataPtr->TwoByteMsgCount = 2; // 2 byte messages
+ ScriptDataPtr->RejectMsgCount = 1; // Reject msg is 1 byte
+ ScriptDataPtr->ParityMsgCount = 1; // Parity msg is 1 byte
+ ScriptDataPtr->AbortMsgCount = 1; // Abort msg is 1 byte
+ ScriptDataPtr->BDRMsgCount = 1; // BDR msg is 1 byte
+
+ //
+ // Initialize reject message buffer
+ //
+
+ NonCachedExtPtr->RejectMsgData = SCSIMESS_MESSAGE_REJECT;
+
+ //
+ // Initialize parity message buffer
+ //
+
+ NonCachedExtPtr->ParityMsgData = SCSIMESS_INIT_DETECTED_ERROR;
+
+ //
+ // Initialize abort message buffer
+ //
+
+ NonCachedExtPtr->AbortMsgData = SCSIMESS_ABORT;
+
+ //
+ // Initialize bus device reset message buffer
+ //
+
+ NonCachedExtPtr->BDRMsgData = SCSIMESS_BUS_DEVICE_RESET;
+
+ //
+ // the following code initializes physical pointers to the data bytes
+ // and buffers filled in above
+ //
+
+ //
+ // set up MESSAGE OUT buffer pointer
+ //
+
+ ScriptDataPtr->MsgOutBuf =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) NonCachedExtPtr->MsgOutBuf,
+ &SegmentLength
+ ));
+
+ //
+ // set up one byte message ptr
+ //
+
+ ScriptDataPtr->OneByteMsgBuff =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) NonCachedExtPtr->MsgInBuf,
+ &SegmentLength
+ ));
+
+ //
+ // set up two byte message ptr
+ //
+
+ ScriptDataPtr->TwoByteMsgBuff = ScriptDataPtr->OneByteMsgBuff;
+
+ //
+ // set up status buffer ptr
+ //
+
+ ScriptDataPtr->StatusDataBuff =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &NonCachedExtPtr->StatusData,
+ &SegmentLength
+ ));
+
+ //
+ // set up reject message ptr
+ //
+
+ ScriptDataPtr->RejectMsgBuff =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &NonCachedExtPtr->RejectMsgData,
+ &SegmentLength
+ ));
+
+ //
+ // set up Initiator Detected Error (IDE) message ptr
+ //
+
+ ScriptDataPtr->ParityMsgBuff =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &NonCachedExtPtr->ParityMsgData,
+ &SegmentLength
+ ));
+
+ //
+ // set up ABORT message ptr
+ //
+
+ ScriptDataPtr->AbortMsgBuff =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &NonCachedExtPtr->AbortMsgData,
+ &SegmentLength
+ ));
+
+ //
+ // set up BUS DEVICE RESET message ptr
+ //
+
+ ScriptDataPtr->BDRMsgBuff =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &NonCachedExtPtr->BDRMsgData,
+ &SegmentLength
+ ));
+
+ //
+ // compute physical address of script data buffer start point
+ //
+
+ DeviceExtension->DSAAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) &NonCachedExtPtr->ScriptData,
+ &SegmentLength
+ ));
+
+} // ComputeSCSIScriptVectors
+
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+/******************************************************************************
+
+Routine Description:
+
+ Initial entry point for Symbios 53C8xx miniport driver.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status indicating whether adapter(s) were found and initialized.
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG pciStatus810;
+ ULONG pciStatus810A;
+ ULONG pciStatus815;
+ ULONG pciStatus820;
+ ULONG pciStatus825;
+ ULONG pciStatus825A;
+ ULONG pciStatus860;
+ ULONG pciStatus875;
+ ULONG retValue1;
+ ULONG retValue2;
+ ULONG retValue3;
+ ULONG retValue4;
+ ULONG i;
+ UCHAR vendorId[4] = {'1', '0', '0', '0'};
+ UCHAR deviceId[4] = {'0', '0', '0', '0'};
+
+ HWInfo hwInfo;
+
+ DebugPrint((1, "\nSymbios 53c8XX SCSI Miniport Driver.\n\n"));
+
+ //
+ // Initialize the hardware initialization data structure.
+ //
+
+ for ( i = 0; i < sizeof( HW_INITIALIZATION_DATA); i++)
+ {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hardware initialization structure.
+ //
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Identify required miniport entry point routines.
+ //
+
+ hwInitializationData.HwInitialize = Sym8xxHWInitialize;
+ hwInitializationData.HwStartIo = Sym8xxStartIo;
+ hwInitializationData.HwInterrupt = Sym8xxISR;
+ hwInitializationData.HwFindAdapter = Sym8xxFindAdapter;
+ hwInitializationData.HwResetBus = Sym8xxReset;
+ hwInitializationData.HwAdapterState = Sym8xxAdapterState;
+
+ //
+ // Specifiy adapter specific information.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+ hwInitializationData.NumberOfAccessRanges = 3;
+ hwInitializationData.AdapterInterfaceType = PCIBus;
+ hwInitializationData.VendorId = &vendorId;
+ hwInitializationData.VendorIdLength = 4;
+ hwInitializationData.DeviceId = &deviceId;
+ hwInitializationData.DeviceIdLength = 4;
+
+ //
+ // Set required extension sizes.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.SrbExtensionSize = sizeof(SRB_EXTENSION);
+ hwInitializationData.SpecificLuExtensionSize =
+ sizeof(SPECIFIC_LOGICAL_UNIT_EXTENSION);
+
+ //
+ // Initialize the driver configuration information.
+ //
+
+ hwInfo.hbaCount = 0;
+ hwInfo.hbaCapability = 0;
+
+ //
+ // Check for the SymC810.
+ //
+
+ deviceId[3] = '1';
+ hwInfo.hbaDeviceID = 0x01;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_810_FAMILY;
+
+ pciStatus810 = ScsiPortInitialize( DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &hwInfo);
+
+ //
+ // Check for the SymC820.
+ //
+
+ deviceId[3] = '2';
+ hwInfo.hbaDeviceID = 0x02;
+ hwInfo.hbaCapability = 0;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_WIDE;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_DIFFERENTIAL;
+
+ pciStatus820 = ScsiPortInitialize( DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &hwInfo);
+
+ //
+ // Check for the SymC825.
+ //
+
+ deviceId[3] = '3';
+ hwInfo.hbaDeviceID = 0x03;
+ hwInfo.hbaCapability = 0;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_WIDE;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_DIFFERENTIAL;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_825_FAMILY;
+ // testing purposes only ->
+ // hwInfo.hbaCapability |= HBA_CAPABILITY_FAST20;
+
+ pciStatus825 = ScsiPortInitialize( DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &hwInfo);
+
+ //
+ // Check for the SYMC815.
+ //
+
+ deviceId[3] = '4';
+ hwInfo.hbaDeviceID = 0x04;
+ hwInfo.hbaCapability = 0;
+
+ pciStatus815 = ScsiPortInitialize( DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &hwInfo);
+
+ //
+ // Check for the SYMC810A.
+ //
+
+ deviceId[3] = '5';
+ hwInfo.hbaDeviceID = 0x05;
+ hwInfo.hbaCapability = 0;
+
+ pciStatus810A = ScsiPortInitialize( DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &hwInfo);
+
+ //
+ // Check for the SYMC860.
+ //
+
+ deviceId[3] = '6';
+ hwInfo.hbaDeviceID = 0x06;
+ hwInfo.hbaCapability = 0;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_FAST20;
+
+ pciStatus860 = ScsiPortInitialize( DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &hwInfo);
+
+ //
+ // Check for the SYMC825A.
+ //
+
+ deviceId[3] = 'E';
+ hwInfo.hbaDeviceID = 0x0E;
+ hwInfo.hbaCapability = 0;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_WIDE;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_DIFFERENTIAL;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_875_LARGE_FIFO;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_SYNC_16;
+
+#ifndef FOR_95
+ hwInfo.hbaCapability |= HBA_CAPABILITY_SCRIPT_RAM;
+#endif
+
+
+ pciStatus825A = ScsiPortInitialize( DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &hwInfo);
+ //
+ // Check for the SYMC875,
+ //
+
+#ifdef FOR_95
+ deviceId[3] = 'F';
+#else
+ deviceId[3] = 'f';
+#endif
+
+ hwInfo.hbaDeviceID = 0x0F;
+ hwInfo.hbaCapability = 0;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_WIDE;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_DIFFERENTIAL;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_SYNC_16;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_FAST20;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_875_LARGE_FIFO;
+ hwInfo.hbaCapability |= HBA_CAPABILITY_875_FAMILY;
+
+#ifndef FOR_95
+ hwInfo.hbaCapability |= HBA_CAPABILITY_SCRIPT_RAM;
+#endif
+
+ pciStatus875 = ScsiPortInitialize( DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &hwInfo);
+
+
+ //
+ // Return the smaller status.
+ //
+ retValue1 = (pciStatus810 < pciStatus820 ? pciStatus810 : pciStatus820);
+ retValue2 = (pciStatus825 < pciStatus815 ? pciStatus825 : pciStatus815);
+ retValue3 = (pciStatus810A < pciStatus860 ? pciStatus810A : pciStatus860);
+ retValue4 = (pciStatus825A < pciStatus875 ? pciStatus825A : pciStatus875);
+
+ retValue1 = (retValue1 < retValue2 ? retValue1 : retValue2);
+ retValue2 = (retValue3 < retValue4 ? retValue3 : retValue4);
+
+ return(retValue1 < retValue2 ? retValue1 : retValue2);
+
+} // end DriverEntry()
+
+
+VOID
+InitializeSIOP(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This function initializes the Symbios SCSI adapter chip. Presently, we do
+ not reset the SIOP, although this may be necessary in the future. Resetting
+ the SIOP will clear all of the chip registers, making it impossible to
+ execute BIOS calls for disk access (SETUP makes BIOS calls after loading
+ the driver).
+
+Arguments:
+
+ DeviceExtension - Pointer to the specific device extension for this SCSI
+ bus.
+
+Return Value:
+
+ NONE
+
+--*/
+
+{
+ UCHAR HbaId = 0;
+ UCHAR max_targets;
+ UCHAR scntl3Value = 0;
+ USHORT i;
+ BOOLEAN needChipReset = FALSE;
+
+ //
+ // Clear (not flush) the DMA FIFO in case something left over.
+ //
+
+ WRITE_SIOP_UCHAR( CTEST3, 0x04 );
+
+ //
+ // Wait for the DMA FIFO to clear.
+ //
+
+ for ( i = 0; i < MAX_CLEAR_FIFO_LOOP; i++ )
+ {
+ ScsiPortStallExecution( CLEAR_FIFO_STALL_TIME );
+
+ //
+ // Check if the clear bit reset itself.
+ //
+
+ if (!(READ_SIOP_UCHAR( CTEST3 ) & 0x04))
+ break;
+ }
+
+ //
+ // If the DMA FIFO did not clear, we will have to reset the chip.
+ //
+
+ if ( !(READ_SIOP_UCHAR( DSTAT ) & 0x80) )
+ {
+ needChipReset = TRUE;
+
+ DebugPrint((3, "Sym8xx(%2x): DMA FIFO not cleared... Need chip reset \n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+ }
+
+ //
+ // Clear (not flush) the SCSI FIFO in case something left over.
+ //
+
+ WRITE_SIOP_UCHAR( STEST3, 0x02 );
+
+ //
+ // Wait for the SCSI FIFO to clear.
+ //
+
+ for ( i = 0; i < MAX_CLEAR_FIFO_LOOP; i++ )
+ {
+ ScsiPortStallExecution( CLEAR_FIFO_STALL_TIME );
+
+ //
+ // Check if the clear bit reset itself.
+ //
+
+ if ( !(READ_SIOP_UCHAR( STEST3 ) & 0x02) )
+ break;
+ }
+
+ //
+ // If the SCSI FIFO did not clear, we will have to reset the chip.
+ //
+
+ if ( READ_SIOP_UCHAR( STEST3 ) & 0x02 )
+ {
+ needChipReset = TRUE;
+
+ DebugPrint((3,
+ "Sym8xx(%2x): SCSI FIFO not cleared... Need chip reset \n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+ }
+
+ if ( needChipReset )
+ {
+ DebugPrint((3, "Sym8xx(%2x): Resetting chip now... \n",
+ DeviceExtension->SIOPRegisterBase ));
+
+#ifdef _MIPS_
+
+ //
+ // Preserve GPCNTL contents for SNI PCI boxes
+ // which set bit 7 to 1 to get internal bus
+ // master signal on GPIO1 to drive a LED
+ //
+
+ DeviceExtension->preserved_reg = READ_SIOP_UCHAR(GPCNTL);
+#endif
+ WRITE_SIOP_UCHAR( ISTAT, 0x40 );
+
+ for ( i = 0; i < MAX_CLEAR_FIFO_LOOP; i++ )
+ {
+ ScsiPortStallExecution( POST_RESET_STALL_TIME );
+
+ //
+ // Clear the chip reset.
+ //
+
+ WRITE_SIOP_UCHAR( ISTAT, 0 );
+
+ if ( !(READ_SIOP_UCHAR( ISTAT ) & 0x40) )
+ break;
+ }
+
+#ifdef _MIPS_
+
+ //
+ // Restore GPCNTL contents for SNI PCI boxes
+ // which set bit 7 to 1 to get internal bus
+ // master signal on GPIO1 to drive a LED
+ //
+
+ WRITE_SIOP_UCHAR(GPCNTL,DeviceExtension->preserved_reg);
+#endif
+
+ }
+
+ else // Abort any running script in order to change clock settings.
+ {
+ AbortCurrentScript (DeviceExtension);
+ }
+
+ //
+ // Insure that Flush DMA FIFO, Clear DMA FIFO, and Fetch Pin Mode
+ // bits are all cleared.
+ //
+
+ WRITE_SIOP_UCHAR( CTEST3, 0 );
+
+ //
+ // set DMA burst length:
+ // 8 - transfer burst for all chips except 825A and 875
+ // Set to 64 if we're using the large fifo and scripts ram on the
+ // 825A and 875 part. Do not set up the prefetch unit since it buys
+ // us nothing in speed and can create a problem using 64 as the burst
+ // length.
+ // Set DMA control values:
+ // do not enable the Totem Pole driver - violates PCI spec
+ // Flush and enable the script prefetch for devices (except as noted above)
+ // (units that do not have pre-fetch will ignore this.)
+ //
+
+ if (!(DeviceExtension->hbaCapability & HBA_CAPABILITY_875_LARGE_FIFO) )
+ {
+ WRITE_SIOP_UCHAR( DMODE, DMODE_BURST_1 );
+//
+// Do not enable pre-fetch until chips are fixed...
+//
+// WRITE_SIOP_UCHAR( DCNTL, 0x60 );
+ WRITE_SIOP_UCHAR( DCNTL, 0x00 );
+ }
+ else
+ {
+ WRITE_SIOP_UCHAR( DMODE, DMODE_BURST_0 );
+ WRITE_SIOP_UCHAR(CTEST5, (UCHAR)(READ_SIOP_UCHAR(CTEST5) |
+ (CTEST5_USE_LARGE_FIFO + CTEST5_BURST)));
+ WRITE_SIOP_UCHAR( DCNTL, 0x00 );
+ }
+
+ //
+ // set SCSI Control Register 0 bits
+ // Full arbitration, selection, or reselection
+ // Enable SCSI parity checking and raising ATN on bad parity
+ //
+
+ WRITE_SIOP_UCHAR( SCNTL0, SCNTL0_ARB_MODE_1 + SCNTL0_ARB_MODE_0 +
+ SCNTL0_ENA_PARITY_CHK + SCNTL0_ASSERT_ATN_PAR );
+
+ if ( (DeviceExtension->hbaCapability & HBA_CAPABILITY_875_FAMILY) &&
+ (READ_SIOP_UCHAR(CTEST3) & 0xF0) > 0x10 )
+ {
+ // 875 rev. E or greater part with clock doubler
+ scntl3Value = set_875_multipler (DeviceExtension);
+ }
+
+ //
+ // Still need to set up the clock stuff if we did not already do it in the
+ // clock multipler code above.
+ //
+ if (!scntl3Value)
+ {
+ scntl3Value = set_8xx_clock (DeviceExtension);
+ }
+
+ DeviceExtension->NonCachedExtension->ScriptData.SelectDataSCNTL3 =
+ scntl3Value;
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)
+ max_targets = SYM_MAX_TARGETS;
+ else
+ max_targets = SYM_NARROW_MAX_TARGETS;
+
+ for ( i = 0; i < max_targets; i++ )
+ {
+ DeviceExtension->WideParms[i] = scntl3Value;
+ DeviceExtension->SyncParms[i] = ASYNCHRONOUS_MODE_PARAMS;
+ }
+
+ //
+ // set SCSI bus SCSI ID
+ // Enable response to reselections
+ //
+
+ WRITE_SIOP_UCHAR( SCID, (UCHAR)(DeviceExtension->SIOPBusID + 0x40 ));
+
+ //
+ // set reselection ID
+ //
+
+ if ( DeviceExtension->SIOPBusID < 0x08 )
+ {
+ WRITE_SIOP_UCHAR( RESPID0, (UCHAR) (1 << DeviceExtension->SIOPBusID ));
+ }
+
+ else
+ {
+ HbaId = DeviceExtension->SIOPBusID - 8;
+ WRITE_SIOP_UCHAR( RESPID1, (UCHAR) (1 << HbaId ));
+ }
+
+ //
+ // Enable appropriate SCSI interrupts
+ //
+
+ WRITE_SIOP_UCHAR( SIEN0, SIEN0_PHASE_MISMATCH
+ + SIEN0_SCSI_GROSS_ERROR
+ + SIEN0_UNEXPECTED_DISCON
+ + SIEN0_RST_RECEIVED
+ + SIEN0_PARITY_ERROR
+ );
+
+ //
+ // enable appropriate DMA interrupts
+ //
+
+ WRITE_SIOP_UCHAR( DIEN, DIEN_ENA_ABRT_INT
+ + DIEN_BUS_FAULT
+ + DIEN_ENABLE_INT_RCVD
+ + DIEN_ENABLE_ILL_INST
+ );
+
+ //
+ // Enable additional SCSI interrupts
+ // Selection or relection time-out interrupt
+ //
+
+ WRITE_SIOP_UCHAR( SIEN1, 0x04 );
+
+ //
+ // Set the SCSI timer values
+ // Handshake-to-handshake timer disabled
+ // Selection time out set to 204.8 ms
+ //
+
+ WRITE_SIOP_UCHAR( STIME0, 0x0c );
+
+ //
+ // Enable TolerANT
+ //
+
+ WRITE_SIOP_UCHAR( STEST3, 0x80 );
+
+ //
+ // Enable differential mode
+ //
+
+#ifdef _MIPS_
+ // Preserve GPCNTL contents for SNI PCI boxes
+ // which set bit 7 to 1 to get internal bus
+ // master signal on GPIO1 to drive a LED
+ WRITE_SIOP_UCHAR(GPCNTL,(UCHAR)(READ_SIOP_UCHAR(GPCNTL) | GPCNTL_GPIO3));
+#else
+ WRITE_SIOP_UCHAR(GPCNTL,GPCNTL_GPIO3);
+#endif
+
+ if ( !(READ_SIOP_UCHAR(GPREG) & GPCNTL_GPIO3) &&
+ (DeviceExtension->hbaCapability & HBA_CAPABILITY_DIFFERENTIAL) )
+ {
+ WRITE_SIOP_UCHAR(STEST2,STEST2_DIFF_MODE);
+ }
+
+
+ //
+ // turn GPIO 0 into an output by clearing its bit in the control reg
+ // to enable LED use
+ //
+
+ WRITE_SIOP_UCHAR(GPCNTL,(UCHAR)(READ_SIOP_UCHAR(GPCNTL) & 0xFE) );
+
+ //
+ // initially have the LED off
+ //
+
+ WRITE_SIOP_UCHAR(GPREG, (UCHAR)(READ_SIOP_UCHAR(GPREG) | 0x01) );
+
+
+} // InitializeSIOP
+
+
+#if defined (_X86_)
+
+BOOLEAN
+IsCompaqSystem(
+ IN PVOID DeviceExtension,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
+ )
+/*
+
+Routine Description:
+
+ This routine locates a Compaq system so the differential support
+ may be disabled.
+
+Arguments:
+
+ DeviceExtension - Supplies the device Extension for the SCSI bus adapter.
+ ConfigInfo - port configuration structure.
+
+Return Value:
+
+ TRUE if 'compaq' string is found in system BIOS space
+
+--*/
+
+{
+ BOOLEAN isCompaq = FALSE;
+ CHAR signatureBuffer[6];
+ CHAR compaqString[6] = { 'c', 'o', 'm', 'p', 'a', 'q' };
+ PVOID signatureAddress;
+ ULONG index;
+ CHAR tmp;
+
+ //
+ // Get a mapped system address to the physical address of the ROM signature
+ // for Compaq systems.
+ //
+
+ signatureAddress = ScsiPortGetDeviceBase( DeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ 0,
+ ScsiPortConvertUlongToPhysicalAddress( 0x000FFFEAL ),
+ 6, // strlen("COMPAQ")
+ FALSE ); // not in I/O space
+
+ if (signatureAddress)
+ {
+
+ //
+ // Read 6 bytes from the mapped address.
+ //
+
+ ScsiPortReadRegisterBufferUchar( (PUCHAR)signatureAddress,
+ (PUCHAR)(&signatureBuffer[0]),
+ 6 );
+ //
+ // lower case string from memory
+ //
+
+ for (index = 0; index < 6; index++)
+ {
+
+ tmp = signatureBuffer[index];
+ if (tmp >= 'A' && tmp <= 'Z')
+ {
+ tmp = tmp + ('a' - 'A');
+ signatureBuffer[index] = tmp;
+ }
+ }
+
+ //
+ // Compare the bytes to "compaq".
+ //
+
+ for (index = 0; index < 6; index++)
+ {
+ if (signatureBuffer[index] != compaqString[index])
+ {
+ break;
+ }
+ }
+
+ if (index == 6)
+ {
+ isCompaq = TRUE;
+
+ }
+ }
+
+ //
+ // Free the device base address.
+ //
+
+ ScsiPortFreeDeviceBase( DeviceExtension, signatureAddress );
+
+ return isCompaq;
+} // end IsCompaqSystem()
+
+#endif
+
+VOID
+ISR_Service_Next(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR ISRDisposition
+ )
+/******************************************************************************
+
+Routine Description:
+
+Arguments:
+
+ DeviceExtension - Supplies the device Extension for the SCSI bus adapter.
+
+Return Value:
+
+
+--*/
+
+{
+ BOOLEAN discIo;
+ USHORT i;
+ UCHAR max_targets;
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+
+
+ DebugPrint((3, "Sym8xx: Entering ISR_Service_Next... \n"));
+
+ switch (ISRDisposition)
+ {
+ case ISR_START_NEXT_REQUEST:
+
+ //
+ // try to start next request.
+ //
+
+ if ( DeviceExtension->NextSrbToProcess != NULL)
+ {
+
+ //
+ // Now check to see if this request is for a SCSI I/O request...
+ //
+
+ if (DeviceExtension->NextSrbToProcess->Function ==
+ SRB_FUNCTION_EXECUTE_SCSI)
+ {
+
+
+ DebugPrint((3, "StartSCSIRequest [1]... \n"));
+
+ StartSCSIRequest(DeviceExtension->NextSrbToProcess, DeviceExtension);
+ }
+
+ else if (DeviceExtension->NextSrbToProcess->Function ==
+ SRB_FUNCTION_RESET_DEVICE )
+ {
+ ResetPeripheral( DeviceExtension, DeviceExtension->NextSrbToProcess);
+ }
+
+ //else
+ //{
+ // What else should be checked for????
+ //}
+
+
+ }
+
+ else
+ {
+
+ //
+ // no pending request, so start WAIT RESELECT script to wait
+ // for a reselection, and ask for a new request if we have not
+ // already asked.
+ //
+
+ discIo = FALSE;
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)
+ max_targets = SYM_MAX_TARGETS;
+ else
+ max_targets = SYM_NARROW_MAX_TARGETS;
+
+ for ( i = 0; i < max_targets; i++ )
+ {
+ if ( DeviceExtension->DisconnectedCount[i] > 0 )
+ {
+ discIo = TRUE;
+ break;
+ }
+ }
+
+ if ( ( !( DeviceExtension->DeviceFlags & DFLAGS_SCRIPT_RUNNING))
+ && ( discIo ) )
+ {
+ StartSIOP( DeviceExtension,
+ DeviceExtension->WaitReselectScriptPhys);
+ } // if
+
+ if ( !( DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED))
+ {
+ DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED;
+
+ if (DeviceExtension->DeviceFlags & DFLAGS_TAGGED_SELECT)
+ {
+ DebugPrint((3, "PortNotification [2]... \n"));
+ ScsiPortNotification( NextLuRequest,
+ DeviceExtension,
+ DeviceExtension->BusNumber,
+ DeviceExtension->TargetId,
+ DeviceExtension->LUN
+ );
+
+ }
+ else
+ {
+ DebugPrint((3, "PortNotification [3]... \n"));
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL
+ );
+ }
+
+ } // if
+
+ } // else
+
+ break;
+
+
+ case ISR_RESTART_SCRIPT:
+
+ //
+ // set up synchronous parameters and restart the script.
+ //
+
+ Srb=DeviceExtension->ActiveRequest;
+
+ ScriptDataPtr->SelectDataSCNTL3 =
+ DeviceExtension->WideParms[Srb->TargetId];
+ ScriptDataPtr->SelectDataSXFER =
+ DeviceExtension->SyncParms[Srb->TargetId];
+
+ WRITE_SIOP_UCHAR (SCNTL3, DeviceExtension->WideParms[Srb->TargetId] );
+ WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] );
+
+ StartSIOP( DeviceExtension, DeviceExtension->RestartScriptPhys);
+ break;
+
+
+ case ISR_CONT_NEG_SCRIPT:
+
+ //
+ // set up synchronous parameters and restart the script.
+ //
+
+ Srb=DeviceExtension->ActiveRequest;
+
+ ScriptDataPtr->SelectDataSCNTL3 =
+ DeviceExtension->WideParms[Srb->TargetId];
+ ScriptDataPtr->SelectDataSXFER =
+ DeviceExtension->SyncParms[Srb->TargetId];
+
+ WRITE_SIOP_UCHAR (SCNTL3, DeviceExtension->WideParms[Srb->TargetId] );
+ WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] );
+
+ StartSIOP( DeviceExtension, DeviceExtension->ContNegScriptPhys);
+ break;
+
+
+ case ISR_EXIT:
+ default:
+ break;
+
+ } // switch ISR_DISPOSITION
+
+ DebugPrint((3, "Sym8xx: Exiting ISR_Service_Next... \n"));
+
+ return;
+} //isr_service_next
+
+
+BOOLEAN
+Sym8xxAdapterState(
+ IN PVOID Context,
+ IN PVOID ConfigContext,
+ IN BOOLEAN SaveState
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This function saves the SIOP registers on driver init and restores
+ them when Windows 95 shuts down. Nothing is done for Windows NT.
+
+Arguments:
+
+ Context - Supplies a pointer to the device extension.
+
+ ConfigContext - miniport configuration data structure
+
+ SaveState - save/restore indicator flag (TRUE = Save, FALSE = Restore)
+
+Return Value:
+
+ Returns status of save/restore operation.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = Context;
+
+#ifdef FOR_95
+ if ( SaveState )
+ {
+ //
+ // Save SIOP registers as they were in DOS mode
+ //
+
+ save_reg( DeviceExtension, &(DeviceExtension->AdapStateStore) );
+ }
+ else
+ {
+ //
+ // Return all devices to asynchronous transfer mode
+ // by resetting the SCSI bus.
+ //
+
+ WRITE_SIOP_UCHAR( SCNTL1, SCNTL1_RESET_SCSI_BUS );
+
+ //
+ // Delay the minimum assertion time for a SCSI bus reset to make sure
+ // a valid reset signal is sent.
+ //
+
+ ScsiPortStallExecution( RESET_STALL_TIME);
+
+ //
+ // set the bus reset line low to end the bus reset event
+ //
+
+ WRITE_SIOP_UCHAR(SCNTL1, 0);
+
+ DebugPrint((1, "Sym8xx(%2x): Restore State\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ //
+ // Wait 250 milliseconds before returning (Reset to Selection Time)
+ //
+
+ for (i=0; i<250; i++)
+ {
+ ScsiPortStallExecution(999);
+ }
+
+ //
+ // Restore SIOP registers to state they were in DOS mode
+ //
+
+ restore_reg( DeviceExtension, &(DeviceExtension->AdapStateStore) );
+ }
+#endif
+
+ return TRUE;
+}
+
+
+ULONG
+Sym8xxFindAdapter(
+ IN PVOID Context,
+ IN PVOID InitContext,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This function fills in the configuration information structure
+
+Arguments:
+
+ Context - Supplies a pointer to the device extension.
+
+ InitContext - Supplies adapter initialization structure.
+
+ BusInformation - Unused.
+
+ ArgumentString - Unused.
+
+ ConfigInfo - Pointer to the configuration information structure to be
+ filled in.
+
+ Again - Returns back a request to call this function again.
+
+Return Value:
+
+ Returns status based upon results of adapter parameter acquisition.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = Context;
+ ULONG Status;
+ PACCESS_RANGE AccessRange, SAccessRange;
+ ULONG do_fast20 = 0;
+ ULONG whatslot, whatid;
+ UCHAR excludechip = 0;
+
+ //
+ // Get information from previous calls.
+ //
+
+ PHWInfo hwInfo = (PHWInfo)InitContext;
+
+ //
+ // Get access range.
+ //
+
+#ifdef FOR_95
+ DeviceExtension->initial_run = 1; // so scam code runs without delays
+#endif
+
+#ifdef PORT_IO
+ //
+ // Look through addresses taken from our PCI config space til
+ // we find on that is for port I/O. Else set range length to
+ // 0 to reject this device.
+ //
+ AccessRange = &((*(ConfigInfo->AccessRanges))[0]);
+ if (AccessRange->RangeInMemory == TRUE)
+ AccessRange = &((*(ConfigInfo->AccessRanges))[1]);
+ if (AccessRange->RangeInMemory == TRUE)
+ AccessRange->RangeLength = 0;
+#else
+ //
+ // Look through addresses taken from our PCI config space til
+ // we find on that is for memory mapped I/O. Else set range
+ // length to 0 to reject this device.
+ //
+ AccessRange = &((*(ConfigInfo->AccessRanges))[1]);
+ if (AccessRange->RangeInMemory != TRUE)
+ AccessRange = &((*(ConfigInfo->AccessRanges))[0]);
+ if (AccessRange->RangeInMemory != TRUE)
+ AccessRange->RangeLength = 0;
+#endif
+
+ if (AccessRange->RangeLength != 0)
+ {
+
+ DeviceExtension->SIOPRegisterBase =
+ (PSIOP_REGISTER_BASE)ScsiPortGetDeviceBase(DeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ AccessRange->RangeStart,
+ AccessRange->RangeLength,
+ (BOOLEAN)!AccessRange->RangeInMemory);
+
+ // always default to not doing FAST20.
+
+ DeviceExtension->hbaCapability = 0;
+
+ if (ArgumentString != NULL)
+ {
+ if (ProcessParseArgumentString(ArgumentString,"Ex_Slot",&whatslot))
+ {
+ if ( ((whatslot & 0x0F) == (ULONG)ConfigInfo->SlotNumber) &&
+ (((whatslot & 0xF0) >> 4) == ConfigInfo->SystemIoBusNumber) )
+ excludechip = 1;
+ }
+
+ if (ProcessParseArgumentString(ArgumentString,"Ex_ChipID",&whatid))
+ {
+ if (whatid == hwInfo->hbaDeviceID)
+ excludechip = 1;
+ }
+
+ if (excludechip)
+ {
+ //
+ // We'll need to free up the address base for this chip/slot
+ //
+ ScsiPortFreeDeviceBase (DeviceExtension,
+ DeviceExtension->SIOPRegisterBase);
+ *Again = TRUE;
+ return (SP_RETURN_NOT_FOUND);
+ }
+
+ if (ProcessParseArgumentString(ArgumentString,"Fast20_Support",
+ &do_fast20))
+ {
+ if (do_fast20)
+ DeviceExtension->hbaCapability = HBA_CAPABILITY_REGISTRY_FAST20;
+ }
+ }
+
+ // detect if this board has the NVRAM on board and
+ // if it is programmed with user supplied data.
+
+ if (NvmDetect(DeviceExtension) == SUCCESS)
+ {
+ if (RetrieveNvmData(DeviceExtension) != SUCCESS)
+ InvalidateNvmData(DeviceExtension);
+ }
+
+ else
+ {
+ InvalidateNvmData(DeviceExtension);
+ }
+
+ //
+ // Set SCSI ID obtained from NVRAM (or defaulted to 7)
+ //
+
+ DeviceExtension->SIOPBusID = (UCHAR)DeviceExtension->UsersHBAId;
+
+ //
+ // Set remainder of configuration
+ //
+
+ //
+ // Set the bus number for this controller. Since Symbios controllers
+ // currently only support one SCSI bus each, this value is zero.
+ //
+
+ DeviceExtension->BusNumber = 0;
+
+ //
+ // Set the SCSI bus number. This value is incremented for each
+ // SCSI bus found in the system.
+ //
+
+ DeviceExtension->ScsiBusNumber = hwInfo->hbaCount++;
+
+ DeviceExtension->hbaCapability |= hwInfo->hbaCapability;
+
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_825_FAMILY)
+ {
+ if ( (READ_SIOP_UCHAR(MACNTL) & 0xF0) >= 0x60 )
+ // 825A part
+ {
+ DeviceExtension->hbaCapability |= HBA_CAPABILITY_SYNC_16;
+ DeviceExtension->hbaCapability |= HBA_CAPABILITY_875_LARGE_FIFO;
+
+#ifndef FOR_95
+ DeviceExtension->hbaCapability |= HBA_CAPABILITY_SCRIPT_RAM;
+#endif
+ }
+ }
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20)
+ {
+ DeviceExtension->ClockSpeed = 80;
+ }
+
+ else
+ {
+ DeviceExtension->ClockSpeed = 40;
+ }
+
+ ConfigInfo->MaximumTransferLength = MAX_XFER_LENGTH;
+ ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_ELEMENTS - 1;
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)
+ {
+ ConfigInfo->MaximumNumberOfTargets = SYM_MAX_TARGETS;
+ }
+
+ else
+ {
+ ConfigInfo->MaximumNumberOfTargets = SYM_NARROW_MAX_TARGETS;
+ }
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+
+ ConfigInfo->AdapterScansDown = FALSE;
+ ConfigInfo->TaggedQueuing = TRUE;
+ ConfigInfo->Dma32BitAddresses = TRUE;
+
+ ConfigInfo->InitiatorBusId[0] = DeviceExtension->SIOPBusID;
+
+ DeviceExtension->ScriptRamPhys = (ULONG)NULL;
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM)
+ {
+ SAccessRange = &((*(ConfigInfo->AccessRanges))[2]);
+ if (ScsiPortConvertPhysicalAddressToUlong(SAccessRange->RangeStart))
+ {
+ // just map the Script Ram area here so NT knows about the space,
+ // save the needed address into ScriptRamPhys.
+
+ DeviceExtension->ScriptRamVirt =
+ (PULONG)ScsiPortGetDeviceBase(DeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ SAccessRange->RangeStart,
+ SAccessRange->RangeLength,
+ (BOOLEAN)!SAccessRange->RangeInMemory);
+ DeviceExtension->ScriptRamPhys = SAccessRange->RangeStart.LowPart;
+ }
+
+ if (!DeviceExtension->ScriptRamPhys)
+ {
+ DeviceExtension->hbaCapability &= ~HBA_CAPABILITY_SCRIPT_RAM;
+ }
+ }
+
+ DeviceExtension->NonCachedExtension =
+ ScsiPortGetUncachedExtension(
+ DeviceExtension,
+ ConfigInfo,
+ sizeof(HW_NONCACHED_EXTENSION)
+ );
+
+ if (DeviceExtension->NonCachedExtension == NULL)
+ {
+ Status = SP_RETURN_ERROR;
+ }
+
+ else
+ {
+ Status = SP_RETURN_FOUND;
+
+ DebugPrint((1, "Symbios 53c8xx(%1x) IO Base=%x Irq=%x HBA Id=%x \n",
+ DeviceExtension->ScsiBusNumber,
+ DeviceExtension->SIOPRegisterBase,
+ ConfigInfo->BusInterruptLevel,
+ ConfigInfo->InitiatorBusId[0]
+ ));
+
+ DebugPrint((3,
+ "Sym8xx(%2x) Sym8xxFindAdapter: DeviceExtension at 0x%x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension
+ ));
+
+ DebugPrint((3, "Sym8xx(%2x) Sym8xxFindAdapter: SCSI SCRIPTS at 0x%x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->NonCachedExtension->ScsiScripts
+ ));
+ }
+
+ //
+ // Disable differential support if this is a compaq.
+ //
+
+#if defined(_X86_)
+ if (IsCompaqSystem( DeviceExtension, ConfigInfo ))
+ {
+ DeviceExtension->hbaCapability &= ~HBA_CAPABILITY_DIFFERENTIAL;
+ }
+
+#endif
+
+ //
+ // Prepare the LU Flags for work.
+ //
+
+ SetupLuFlags( DeviceExtension, 0 );
+
+ //
+ // Tell system to look for more adapters.
+ //
+
+ *Again = TRUE;
+
+ }
+
+ else
+ {
+ //
+ // Access Range == 0 ...
+ //
+
+ //
+ // Tell system to stop search for adapters.
+ //
+
+ Status = SP_RETURN_NOT_FOUND;
+ *Again = FALSE;
+ }
+
+ return(Status);
+
+} // Sym8xxFindAdapter
+
+
+BOOLEAN
+Sym8xxHWInitialize(
+ IN PVOID Context
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This function initializes the Symbios 53C8xx SCSI Scripts, and then
+ initializes the SIOP.
+
+Arguments:
+
+ Context - Pointer to the device extension for this SCSI bus.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = Context;
+
+ //
+ // Initialize SCSI script buffers and pointers and the Symbios 53C8xx
+ // SCSI I/O processor for the current hardware implementation.
+ //
+
+ ComputeSCSIScriptVectors(DeviceExtension);
+ InitializeSIOP(DeviceExtension);
+
+ //
+ // For WinNT: Deleting this reset, going to do asynch neg. on all I/O's
+ // till OS says to do Synch.
+ //
+#ifdef FOR_95
+ ResetSCSIBus( DeviceExtension);
+#else
+ //
+ // scam_completed flag needs to be set to true for NT to allow I/O's thru
+ DeviceExtension->scam_completed=TRUE;
+#endif
+
+ clear_CA_Condition(DeviceExtension);
+
+ return(TRUE);
+
+} // Sym8xxHWInitialize
+
+
+BOOLEAN
+Sym8xxISR(
+ PVOID Context
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This is the interrupt service routine for the Symbios 53C8xx SCSI chip.
+ This routine calls one of two interrupt routines, depending upon whether
+ the DMA or SCSI core of the SIOP interrupted. Both routines return a
+ disposition code indicating what action to take next.
+
+Arguments:
+
+ Context - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ TRUE - Indicates that an interrupt was pending on adapter.
+
+ FALSE - Indicates the interrupt was not ours.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = Context;
+ UCHAR IntStatus;
+ UCHAR ScsiStatus = 0;
+ UCHAR DmaStatus = 0;
+ UCHAR ScsiStatus1 = 0;
+ UCHAR ISRDisposition;
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+
+
+ if (!((IntStatus = READ_SIOP_UCHAR(ISTAT)) &
+ (ISTAT_SCSI_INT | ISTAT_DMA_INT)))
+ {
+
+ //
+ // Reject this interrupt. This could be the loader polling or a
+ // shared interrupt.
+ //
+
+ DebugPrint((2,
+ "Sym8xx(%2x) Sym8xxISR: Unexpected interrupt. Dev. Ext. = %x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension
+ ));
+
+ return(FALSE);
+ }
+
+ // CHC - 53c810 pass 1 chip bug workaround.
+ //
+ // We need to make sure the ISTAT_SIGP bit is cleared since
+ // this bit could be still set when we attempted to abort
+ // a scsi script and got a reselection instead. Reading
+ // CTEST2 clears this bit.
+ //
+
+ if (IntStatus & ISTAT_SIGP)
+ {
+ READ_SIOP_UCHAR(CTEST2);
+ }
+
+ //
+ // Indicate that the scripts have stopped and determine
+ // the type of interrupt received.
+ //
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_SCRIPT_RUNNING;
+
+ //
+ // Check if a DMA interrupt occurred.
+ //
+
+ if ( IntStatus & ISTAT_DMA_INT)
+ {
+ //
+ // DMA Interrupt occurred, get the DMA status.
+ //
+
+ DmaStatus = READ_SIOP_UCHAR(DSTAT);
+
+ //
+ // Call routine to process the appropriate DMA interrupt.
+ //
+
+ ISRDisposition = ProcessDMAInterrupt( DeviceExtension, DmaStatus);
+
+ //
+ // Check if a SCSI interrupt occurred.
+ //
+ }
+
+ else if ( IntStatus & ISTAT_SCSI_INT )
+ {
+ //
+ // SCSI interrupt occurred, get the SCSI interrupt status.
+ //
+
+ ScsiStatus = READ_SIOP_UCHAR(SIST0);
+
+ //
+ // Call routine to process the appropriate SCSI interrupt.
+ //
+
+ //
+ // Check for Selection/Reselection timeout.
+ //
+
+ if ( (ScsiStatus1 = READ_SIOP_UCHAR(SIST1)) & SIST1_SEL_RESEL_TIMEOUT )
+ {
+ ISRDisposition = ProcessSelectionTimeout( DeviceExtension);
+ }
+
+ else
+ {
+ ISRDisposition = ProcessSCSIInterrupt( DeviceExtension, ScsiStatus);
+ }
+
+ }
+
+ //
+ // Neither DMA interrupt or SCSI interrupt. Must be an error.
+ //
+
+ else
+ {
+ DebugPrint((2,
+ "Sym8xx(%2x) Sym8xxISR: Unexpected int. - neither DIP or SIP set\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ return FALSE;
+ }
+
+ DebugPrint((2,
+ "Sym8xx(%2x) Sym8xxISR: ISTAT=%x, DSTAT=%x, SIST0=%x, SIST1=%x \n",
+ DeviceExtension->SIOPRegisterBase,
+ IntStatus, DmaStatus, ScsiStatus, ScsiStatus1
+ ));
+
+ ISR_Service_Next(DeviceExtension,ISRDisposition);
+
+ return(TRUE);
+
+} // Sym8xxISR
+
+
+BOOLEAN
+Sym8xxReset(
+ IN PVOID Context,
+ IN ULONG PathId
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This externally called routine resets the SIOP and the SCSI bus.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+ PathId - Indicates adapter to reset.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = Context;
+ ULONG Limit = 0;
+ PSCSI_REQUEST_BLOCK srb;
+ UCHAR IntStatus;
+
+ //
+ // Check to see if an interrupt is pending on the card.
+ //
+
+ if (((IntStatus = READ_SIOP_UCHAR(ISTAT)) &
+ (ISTAT_SCSI_INT | ISTAT_DMA_INT)))
+ {
+ DebugPrint((1,
+ "Sym8xxReset: Interrupt pending on chip. ISTAT %x.\n",
+ IntStatus));
+ //
+ // Interrupt is there. Assume that the chip is disabled, but still
+ // assigned resources (Omniplex).
+ //
+
+ srb = DeviceExtension->ActiveRequest;
+
+ //
+ // Set flag to ensure that the rest are caught in startIo
+ //
+
+ DeviceExtension->DeviceFlags |= DFLAGS_IRQ_NOT_CONNECTED;
+
+ //
+ // Log this.
+ //
+
+ ScsiPortLogError(Context,
+ srb,
+ 0,
+ 0,
+ 0,
+ SP_IRQ_NOT_RESPONDING,
+ (1 << 8) | IntStatus);
+
+ //
+ // Fall through and execute rest of reset code, to ensure that
+ // the scripts and chip are coherent.
+ //
+ }
+
+
+ DebugPrint((1, "Sym8xx(%2x): O/S requested SCSI bus reset\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ if (DeviceExtension->DeviceFlags & DFLAGS_SCRIPT_RUNNING)
+ {
+ WRITE_SIOP_UCHAR(ISTAT, ISTAT_SIGP);
+
+ IntStatus = READ_SIOP_UCHAR(ISTAT);
+
+ while (!(IntStatus & ISTAT_DMA_INT))
+ {
+ IntStatus = READ_SIOP_UCHAR(ISTAT);
+
+ if (IntStatus & ISTAT_SCSI_INT)
+ {
+ READ_SIOP_UCHAR(SIST0);
+ }
+
+ ScsiPortStallExecution(10);
+
+ if (Limit++ > 1000 * 10)
+ {
+ break;
+ }
+ }
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_SCRIPT_RUNNING;
+
+ //
+ // Check to see if a reselection occurred or the abort was successful.
+ //
+
+ if (IntStatus & ISTAT_SIGP)
+ {
+ READ_SIOP_UCHAR(CTEST2);
+ }
+
+ else
+ {
+ READ_SIOP_UCHAR(DSTAT);
+ }
+
+ } // if scripts running
+
+ //
+ // reset the SIOP.
+ //
+
+ InitializeSIOP( DeviceExtension);
+
+ //
+ // reset the SCSI bus.
+ //
+
+ ResetSCSIBus( DeviceExtension);
+
+ return (TRUE);
+
+} // Sym8xxReset
+
+
+BOOLEAN
+Sym8xxStartIo(
+ IN PVOID Context,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine receives requests from the port driver.
+
+Arguments:
+
+ Context - pointer to the device extension for the adapter.
+
+ Srb - pointer to the request to be started.
+
+Return Value:
+
+ TRUE - the request was accepted.
+
+ FALSE - the request must be submitted later.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION DeviceExtension = Context;
+ UCHAR pathId = Srb->PathId;
+
+ if (!(DeviceExtension->scam_completed))
+ {
+ DebugPrint((3,"Entered Sym8xxStartIO before SCAM finished... \n"));
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+ DeviceExtension->DeviceFlags &= ~DFLAGS_WORK_REQUESTED;
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ return(FALSE);
+ }
+
+
+ switch (Srb->Function)
+ {
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ if (Srb->Cdb[0] == SCSIOP_INQUIRY)
+ {
+ if (DeviceExtension->DeviceFlags & DFLAGS_IRQ_NOT_CONNECTED)
+ {
+ Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ return(TRUE);
+ }
+ }
+
+ //
+ // Indicate a request for work is not pending.
+ //
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_WORK_REQUESTED;
+
+ StartSCSIRequest( Srb, DeviceExtension );
+
+ return(TRUE);
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+ case SRB_FUNCTION_TERMINATE_IO:
+
+ if ( DeviceExtension->ActiveRequest == Srb->NextSrb)
+ {
+ //
+ // Indicate a request for work is not pending.
+ //
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_WORK_REQUESTED;
+
+ //
+ // abort the script that is processing the request
+ //
+
+ AbortCurrentScript( DeviceExtension);
+
+ //
+ // temporarily disable unexpected disconnect interrupt, as
+ // an unexpected disconnect interrupt could occur after we
+ // send the abort command, but before we receive the script
+ // interrupt indicating the request was aborted.
+ //
+
+ WRITE_SIOP_UCHAR( SIEN0, (UCHAR) ( READ_SIOP_UCHAR(SIEN0) &
+ (UCHAR) ~SIEN0_UNEXPECTED_DISCON));
+
+ //
+ // abort the request - we will be interrupted later regardless
+ // of whether abort succeeds or fails.
+ //
+
+ StartSIOP( DeviceExtension, DeviceExtension->AbortScriptPhys);
+
+ return( TRUE);
+ } // if
+
+ //
+ // the request we were asked to abort is not currently in process,
+ // so fail the abort request and ask for a new one.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ return(TRUE);
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ DebugPrint((2, "Sym8xx(%2x) Sym8xxStartIO: ResetDevice received.\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ //
+ // Indicate a request for work is not pending.
+ //
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_WORK_REQUESTED;
+
+ //
+ // reset the SCSI device.
+ //
+
+ ResetPeripheral( DeviceExtension,Srb );
+
+ return(TRUE);
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ DebugPrint((2, "Sym8xx(%2x) Sym8xxStartIO: ResetBus received.\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ //
+ // reset the SCSI bus.
+ //
+
+ ResetSCSIBus( DeviceExtension );
+
+ return(TRUE);
+
+
+ default:
+
+ DebugPrint((1,
+ "Sym8xx(%2x) Sym8xxStartIO: Unknown function code received.\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ //
+ // Unknown function code in the request. Complete the request with
+ // an error and ask for the next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ return(TRUE);
+
+ } // switch
+
+} // Sym8xxStartIO
+
+
+UCHAR
+ProcessAbortOccurred(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when scripts sucessfully sent an Abort message
+ to a device.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension;
+
+ DebugPrint((1, "Sym8xx(%2x) Abort message occurred \n",
+ DeviceExtension->SIOPRegisterBase));
+
+ //
+ // indicate that the abort was successful
+ //
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ DeviceExtension->ActiveRequest = NULL;
+
+ if ( !(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) )
+ {
+
+ LuExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+
+ LuExtension->UntaggedRequest = NULL;
+
+ }
+
+ //
+ // call back the request.
+ //
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ //
+ // enable UNEXPECTED DISCONNECT interrupt in case we disabled it.
+ //
+
+ WRITE_SIOP_UCHAR( SIEN0, (UCHAR) ( READ_SIOP_UCHAR(SIEN0)
+ | (UCHAR) SIEN0_UNEXPECTED_DISCON) );
+
+ //
+ // tell ISR to start next request
+ //
+
+ return( ISR_START_NEXT_REQUEST );
+
+} // ProcessAbortOccurred
+
+
+UCHAR
+ProcessBusResetReceived(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine processes SCSI bus resets detected by the SIOP.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // tell port driver that a bus reset has occurred
+ //
+
+ ScsiPortNotification( ResetDetected,
+ DeviceExtension,
+ NULL
+ );
+
+ //
+ // if the bus reset was internal, we will not try to start a new
+ // request, since the routine that issued the reset would have already
+ // done this.
+ //
+
+ if ( DeviceExtension->DeviceFlags & DFLAGS_BUS_RESET)
+ {
+ //
+ // clear the flag indicating internal bus reset.
+ //
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_BUS_RESET;
+
+ //
+ // tell ISR to continue without doing anything.
+ //
+
+ return( ISR_EXIT);
+ }
+
+ else
+ {
+ //
+ // the bus reset was externally generated, so abort any started or
+ // pending requests and try to start a new one.
+ //
+
+ BusResetPostProcess( DeviceExtension);
+
+ return( ISR_START_NEXT_REQUEST);
+ }
+
+} // ProcessBusResetReceived
+
+
+UCHAR
+ProcessCommandComplete(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine handles normal SCSI request completion. Routine first checks
+ SCSI status returned from device, and if some permutation of GOOD sets
+ error flag in SRB. Routine then does port notification of request
+ completion.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension;
+
+ DebugPrint((3, "Sym8xx(%2x) Sym8xxCommand: Completing request for Path=%2x Id=%2x Lun=%2x\n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId,
+ Srb->Lun ));
+
+ //
+ // if a synchronous negotiation is pending, the target was nice enough
+ // to not acknowledge our SDTR message. go to asynchronous.
+ //
+
+ if ( DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND)
+ {
+ ProcessSynchNotSupported( DeviceExtension);
+ }
+
+ if ((DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND) ||
+ (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_NARROW_NEGOT_PEND))
+ {
+ ProcessWideNotSupported( DeviceExtension, Srb->TargetId);
+ }
+
+ //
+ // set status data from script buffer.
+ //
+
+ Srb->ScsiStatus = DeviceExtension->NonCachedExtension->StatusData;
+
+ //
+ // check for bad status.
+ //
+
+ if ( Srb->ScsiStatus != SCSISTAT_GOOD &&
+ Srb->ScsiStatus != SCSISTAT_CONDITION_MET &&
+ Srb->ScsiStatus != SCSISTAT_INTERMEDIATE &&
+ Srb->ScsiStatus != SCSISTAT_INTERMEDIATE_COND_MET )
+ {
+ // check to see if Contingient Condition now exists
+ if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION)
+ {
+ DeviceExtension->CA_Condition[Srb->TargetId][Srb->Lun] = 1;
+ }
+
+ if ( (Srb->ScsiStatus == SCSISTAT_BUSY) ||
+ (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) )
+ {
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+ }
+
+ else
+ {
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ }
+
+ DebugPrint((1,
+ "Sym8xx(%2x): Request failed for Path=%2x Id=%2x Lun=%2x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId,
+ Srb->Lun
+ ));
+ DebugPrint((1, " ScsiStatus: 0x%x SrbStatus: 0x%x\n SrbFlags: 0x%x",
+ Srb->ScsiStatus,
+ Srb->SrbStatus,
+ Srb->SrbFlags
+ ));
+
+ //
+ // Make sure the next command is not for the current LUN.
+ //
+
+ if ( DeviceExtension->NextSrbToProcess != NULL &&
+ DeviceExtension->NextSrbToProcess->PathId == Srb->PathId &&
+ DeviceExtension->NextSrbToProcess->TargetId == Srb->TargetId &&
+ DeviceExtension->NextSrbToProcess->Lun == Srb->Lun)
+ {
+ DebugPrint((1, "Sym8xx(%2x): Failing request with busy status due to check condition\n",
+ DeviceExtension->SIOPRegisterBase));
+
+ DeviceExtension->NextSrbToProcess->SrbStatus = SRB_STATUS_ABORTED;
+
+ DeviceExtension->NextSrbToProcess->ScsiStatus = SCSISTAT_BUSY;
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ DeviceExtension->NextSrbToProcess
+ );
+
+ DeviceExtension->NextSrbToProcess = NULL;
+
+ if ( !( DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED))
+ {
+ DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED;
+
+ ScsiPortNotification(NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ }
+ }
+ }
+
+ else
+ {
+ // Status is good...
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ // Check for data underrun.
+
+ if ( SRB_EXT(Srb)->DataTransferred != 0)
+ {
+ Srb->DataTransferLength = Srb->DataTransferLength -
+ SRB_EXT(Srb)->SavedDataLength + SRB_EXT(Srb)->DataTransferred;
+
+ if (Srb->DataTransferLength == 0)
+ {
+ Srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ }
+
+ else
+ {
+ Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+ }
+ }
+
+ // indicate no request is active.
+ DeviceExtension->ActiveRequest = NULL;
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) )
+ {
+ LuExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+
+ LuExtension->UntaggedRequest = NULL;
+ }
+
+ // indicate request completed to port driver.
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ // tell ISR to try to start a new request
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessCommandComplete
+
+
+UCHAR
+ProcessDeviceResetFailed(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when scripts try to reset a wayward device, but
+ cannot.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+
+ DebugPrint((1, "Sym8xx(%2x) Bus Device Reset or Abort failed \n",
+ DeviceExtension->SIOPRegisterBase));
+
+ //
+ // since the device would not get off the bus, we must blow him (and every-
+ // body else) away.
+ //
+
+ //
+ // reset SIOP
+ //
+
+ InitializeSIOP( DeviceExtension );
+
+ //
+ // reset SCSI bus
+ //
+
+ ResetSCSIBus( DeviceExtension );
+
+ return( ISR_START_NEXT_REQUEST );
+
+} // ProcessDeviceResetFailed
+
+
+UCHAR
+ProcessDeviceResetOccurred(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when scripts sucessfully sent a Bus Device
+ Reset message to a device.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UCHAR lun;
+
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension;
+
+ DebugPrint((1, "Sym8xx(%2x) Bus Device Reset occurred \n",
+ DeviceExtension->SIOPRegisterBase));
+
+ if ( Srb->Function == SRB_FUNCTION_RESET_DEVICE )
+ {
+ //
+ // indicate that the reset was successful
+ //
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ else
+ {
+ //
+ // indicate the device was wayward.
+ //
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ Srb->ScsiStatus = SCSISTAT_COMMAND_TERMINATED;
+ }
+
+ // reset the Contingent Allegience blocker for this Target
+ for ( lun = 0; lun < SCSI_MAXIMUM_LOGICAL_UNITS; lun++ )
+ DeviceExtension->CA_Condition[Srb->TargetId][lun] = 0;
+
+ DeviceExtension->ActiveRequest = NULL;
+
+ if ( !(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) )
+ {
+ LuExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+
+ LuExtension->UntaggedRequest = NULL;
+ }
+
+ //
+ // call back the request.
+ //
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ //
+ // enable UNEXPECTED DISCONNECT interrupt in case we disabled it.
+ //
+
+ WRITE_SIOP_UCHAR( SIEN0, (UCHAR) ( READ_SIOP_UCHAR(SIEN0) |
+ (UCHAR) SIEN0_UNEXPECTED_DISCON) );
+
+ //
+ // Remove all the disconnected I/Os for this target.
+ //
+
+ DeviceExtension->DisconnectedCount[Srb->TargetId] = 0;
+
+ if ( DeviceExtension->DeviceFlags & DFLAGS_TAGGED_SELECT )
+ {
+ ScsiPortNotification( NextLuRequest,
+ DeviceExtension,
+ DeviceExtension->BusNumber,
+ DeviceExtension->TargetId,
+ DeviceExtension->LUN
+ );
+ }
+
+ else
+ {
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL
+ );
+ }
+
+ return( ISR_EXIT );
+
+} // ProcessDeviceResetOccurred
+
+
+UCHAR
+ProcessDisconnect(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine handles a normal device disconnect. Note that this routine
+ is not called in the case of a command completion, so we expect a
+ reselection after the completion of this call.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+
+ //
+ // indicate that no request is active.
+ //
+
+ DebugPrint((3, "Sym8xx(%2x) Sym8xxDMAInterrupt: Disconnect \n",
+ DeviceExtension->SIOPRegisterBase));
+
+ //
+ // increment depth counter for disconnected requests
+ //
+
+ DeviceExtension->DisconnectedCount[Srb->TargetId]++;
+
+ //
+ // indicate no work is pending, and tell ISR to start next request.
+ //
+
+ DeviceExtension->ActiveRequest = NULL;
+
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessDisconnect
+
+
+UCHAR
+ProcessDMAInterrupt(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR DmaStatus
+ )
+/******************************************************************************
+
+Routine Description:
+
+ The routine processes interrupts from the DMA core of the 53C8xx SIOP.
+
+Arguments:
+
+ Context - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ ULONG i;
+ UCHAR ScriptIntOpcode;
+ PSCSI_REQUEST_BLOCK Srb;
+
+ Srb = DeviceExtension->ActiveRequest;
+
+ if ( DmaStatus & DSTAT_SCRPTINT)
+ {
+ //
+ // Check for residual data in the C8xx DMA FIFO and
+ // flush it as neccessary.
+ //
+
+ if (!(DmaStatus & 0x80))
+ {
+ WRITE_SIOP_UCHAR( CTEST3, CTEST3_FLUSH_FIFO);
+
+ for (i=0; i < 1000; i++)
+ {
+ if (READ_SIOP_UCHAR(DSTAT) & 0x80)
+ {
+ break;
+ }
+
+ ScsiPortStallExecution(5);
+ }
+
+ if (i >= 1000)
+ {
+ //
+ // Give up and reset the chip.
+ //
+
+ InitializeSIOP( DeviceExtension);
+ ResetSCSIBus( DeviceExtension);
+ return( ISR_START_NEXT_REQUEST);
+ }
+
+ WRITE_SIOP_UCHAR( CTEST3, 0);
+ }
+
+ //
+ // read the register that contains the script interrupt opcode.
+ // if the RESELECT bit is set in the opcode, process the reselect.
+ //
+
+ if (( ScriptIntOpcode = READ_SIOP_UCHAR( DSPS[0])) & DSPS_RESELOP)
+ {
+ //
+ // CHC - 53c810 pass 1 chip bug workaround.
+ //
+ // We need to make sure the ISTAT_SIGP bit is cleared since
+ // this bit could be still set when we attempted to abort
+ // a scsi script and got a reselection instead. Reading
+ // CTEST2 clears this bit.
+ //
+
+ READ_SIOP_UCHAR( CTEST2);
+
+ //
+ // A reselection occurred.
+ // The reselection id is in the low byte of the SSID register.
+ //
+
+ ScriptIntOpcode = READ_SIOP_UCHAR( SSID ) & 0x0F;
+
+ //
+ // call routine to process reselection. return disposition code
+ // to the ISR.
+ //
+
+ return ( ProcessReselection( DeviceExtension, ScriptIntOpcode) );
+ }
+
+ //
+ // the script interrupt opcode was not a reselection, so process it.
+ //
+ //
+ // CHC - 53c810 pass 1 chip bug workaround.
+ //
+ // To get around the parity error on the PCI bus, we will handle
+ // the aborting of scsi scripts here.
+ //
+
+ if ( ScriptIntOpcode == SCRIPT_INT_SCRIPT_ABORTED)
+ {
+ //
+ // Just make sure we've cleared the DSTAT register
+ //
+
+ READ_SIOP_UCHAR( DSTAT);
+
+ return( ISR_START_NEXT_REQUEST);
+ }
+
+ //
+ // The following DMA interrupts should only occur when we have an
+ // active SRB. To be safe, we check for one. If there is not an
+ // active SRB, the hardware has interrupted inappropriately,
+ // so reset everything.
+ //
+
+ if ( DeviceExtension->ActiveRequest == NULL &&
+ ScriptIntOpcode != SCRIPT_INT_TAG_RECEIVED)
+ {
+ DebugPrint((1, "Sym8xx(%2x) ProcessDMAInterrupt unknown request\n",
+ DeviceExtension->SIOPRegisterBase));
+ DebugPrint((1, " ActiveRequest: %lx DmaStatus: %x\n",
+ DeviceExtension->ActiveRequest, DmaStatus));
+ DebugPrint((1, " DSPS[0]: %x\n",
+ ScriptIntOpcode));
+
+ InitializeSIOP( DeviceExtension);
+ ResetSCSIBus( DeviceExtension);
+ return( ISR_START_NEXT_REQUEST);
+ }
+
+ DebugPrint((3, "Sym8xx(%2x) ProcessDMAInterrupt ...ScriptIntOpcode=%x\n",
+ DeviceExtension->SIOPRegisterBase, ScriptIntOpcode
+ ));
+
+ switch (ScriptIntOpcode)
+ {
+ //
+ // call appropriate routine to process script interrupt.
+ // todo - decide whether to move critical path routines up
+ // from subroutines to reduce overhead.
+ //
+
+ case SCRIPT_INT_COMMAND_COMPLETE:
+
+ //
+ // process COMMAND COMPLETE script interrupt. return
+ // disposition code to ISR.
+ //
+
+ return( ProcessCommandComplete( DeviceExtension));
+
+ case SCRIPT_INT_SAVE_DATA_PTRS:
+ case SCRIPT_INT_SAVE_WITH_DISCONNECT:
+
+ //
+ // most of the time, a SAVE DATA POINTERS is followed
+ // by a DISCONNECT message. We make the determination
+ // in scripts, and if this is the case we save ourselves
+ // an interrupt by processing both at once.
+ //
+
+ ProcessSaveDataPointers( DeviceExtension);
+
+ //
+ // if not SAVE WITH DISCONNECT just return.
+ //
+
+ if (ScriptIntOpcode == SCRIPT_INT_SAVE_DATA_PTRS)
+ {
+ return ( ISR_RESTART_SCRIPT);
+ }
+
+ //
+ // fall through to process disconnect.
+ //
+
+ case SCRIPT_INT_DISCONNECT:
+
+ //
+ // process SCRIPT_INT_DISCONNECT script interrupt. return
+ // disposition code to ISR.
+ //
+
+ return( ProcessDisconnect( DeviceExtension));
+
+ case SCRIPT_INT_RESTORE_POINTERS:
+
+ //
+ // process SCRIPT_INT_RESTORE_POINTERS script interrupt.
+ // return disposition code to ISR.
+ //
+
+ return( ProcessRestorePointers( DeviceExtension));
+
+ case SCRIPT_INT_DEV_RESET_OCCURRED:
+
+ //
+ // process SCRIPT_INT_DEV_RESET_OCCURRED script interrupt. return
+ // disposition code to ISR.
+ //
+
+ return( ProcessDeviceResetOccurred( DeviceExtension));
+
+ case SCRIPT_INT_DEV_RESET_FAILED:
+ case SCRIPT_INT_ABORT_FAILED:
+
+ //
+ // process SCRIPT_INT_DEV_RESET_FAILED script interrupt. return
+ // disposition code to ISR.
+ //
+
+ return( ProcessDeviceResetFailed( DeviceExtension));
+
+ case SCRIPT_INT_IDE_MSG_SENT:
+
+ //
+ // process SCRIPT_INT_IDE_MSG_SENT script interrupt. return
+ // disposition code to ISR.
+ //
+
+ return( ProcessErrorMsgSent( ));
+
+ case SCRIPT_INT_SYNC_NOT_SUPP:
+
+ //
+ // process SCRIPT_INT_SYNC_NOT_SUPP script interrupt. return
+ // disposition code to ISR.
+ //
+
+ return ( ProcessSynchNotSupported( DeviceExtension));
+
+ case SCRIPT_INT_SYNC_NEGOT_COMP:
+
+ //
+ // process SCRIPT_INT_SYNC_NEGOT_COMP script interrupt.
+ // return disposition code to ISR.
+ //
+
+ return( ProcessSynchNegotComplete( DeviceExtension));
+
+ case SCRIPT_INT_WIDE_NOT_SUPP:
+
+ //
+ // process SCRIPT_INT_WIDE_NOT_SUPP script interrupt. return
+ // disposition code to ISR.
+ //
+
+ return ( ProcessWideNotSupported( DeviceExtension, Srb->TargetId));
+
+ case SCRIPT_INT_WIDE_NEGOT_COMP:
+
+ //
+ // process SCRIPT_INT_WIDE_NEGOT_COMP script interrupt.
+ // return disposition code to ISR.
+ //
+
+ return( ProcessWideNegotComplete( DeviceExtension));
+
+ case SCRIPT_INT_INVALID_RESELECT:
+ case SCRIPT_INT_INVALID_TAG_MESSAGE:
+
+ //
+ // process SCRIPT_INT_INVALID_RESELECT script interrupt.
+ // return disposition code to ISR.
+ //
+
+ return( ProcessInvalidReselect( DeviceExtension) );
+
+ case SCRIPT_INT_REJECT_MSG_RECEIVED:
+
+ //
+ // process SCRIPT_INT_REJECT_MSG_RECEIVED script interrupt.
+ // return disposition code to ISR.
+ //
+
+ return( ProcessRejectReceived( DeviceExtension));
+
+ case SCRIPT_INT_TAG_RECEIVED:
+
+ //
+ // Process the queue tag message.
+ //
+
+ return( ProcessQueueTagReceived( DeviceExtension));
+
+ case SCRIPT_INT_ABORT_OCCURRED:
+
+ //
+ // The device was successfully aborted.
+ //
+
+ return( ProcessAbortOccurred( DeviceExtension ) );
+
+ default:
+
+ //
+ // something went really wrong.
+ // perform drastic error recovery.
+ //
+
+ InitializeSIOP( DeviceExtension);
+ ResetSCSIBus( DeviceExtension);
+ return( ISR_START_NEXT_REQUEST);
+
+ } // switch ( SCRIPT_INT_OPCODE)
+
+ } // if
+
+ //
+ // if we arrive here a DMA error of some type has occurred.
+ //
+
+ if ( DmaStatus & DSTAT_ILLEGAL_INSTRUCTION)
+ {
+ return( ProcessIllegalInstruction( DeviceExtension));
+ }
+
+ //
+ // all other cases indicate that things are really screwed up, since
+ // we mask off all other types of DMA interrupts. perform drastic error
+ // recovery.
+ //
+
+ InitializeSIOP( DeviceExtension);
+ ResetSCSIBus( DeviceExtension);
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessDMAInterrupt
+
+
+UCHAR
+ProcessErrorMsgSent(
+ VOID
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when scripts sucessfully sent an IDE or MPE
+ message to a device.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Target devices should either:
+ //
+ // a) return CHECK CONDITION status after receiving an IDE message, or
+ //
+ // b) resend the entire message in the case of an MPE message.
+ //
+ // Therefore, we simply restart the script state machine.
+ //
+
+ //
+ // tell ISR to restart the script
+ //
+
+ return( ISR_RESTART_SCRIPT);
+
+} // ProcessErrorMsgSent
+
+
+
+UCHAR
+ProcessGrossError(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine processes gross scsi errors. See 53C8xx data manual for
+ a description of gross errors.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DebugPrint((3, "Sym8xx(%2x) SCSI Gross Error occurred \n",
+ DeviceExtension->SIOPRegisterBase));
+
+ //
+ // A gross error implies the hardware or SCSI device is in an unknown
+ // state. We reset the chip and SCSI bus in hopes that the problem will
+ // not recur.
+ //
+
+ //
+ // reset SIOP
+ //
+
+ InitializeSIOP( DeviceExtension);
+
+ //
+ // reset SCSI bus
+ //
+
+ ResetSCSIBus( DeviceExtension);
+
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessGrossError
+
+
+UCHAR
+ProcessIllegalInstruction(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when illegal script instruction is fetched by
+ the 53C8xx.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG ScriptPhysAddr;
+
+ DebugPrint((1,
+ "Sym8xx(%2x) Sym8xxDMAInterrupt: Illegal script instruction \n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ //
+ // if a WAIT DISCONNECT has generated an ILLEGAL INSTRUCTION interrupt,
+ // meaning that we have been reselected before the WAIT DISCONNECT could
+ // be fetched and processed, we must determine why the device
+ // disconnected. We do this by fetching the next script instruction,
+ // which should be an INT instruction, and processing it.
+ //
+
+ if ( READ_SIOP_UCHAR( DCMD) == DCMD_WAIT_DISCONNECT)
+ {
+ DebugPrint((1,
+ "Sym8xx(%2x) Sym8xxDMAInterrupt: Illegal WAIT DISCONNECT \n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ //
+ // get the physical address of the next script instruction.
+ //
+
+ ScriptPhysAddr = READ_SIOP_ULONG(DSP);
+
+ //
+ // start the script instruction.
+ //
+
+ StartSIOP( DeviceExtension, ScriptPhysAddr);
+
+ return( ISR_EXIT);
+ }
+
+ //
+ // if we reach here, either scripts have been corrupted in memory or the
+ // hardware is hosed. since we can't do anything about the former case,
+ // we will assume the latter and reset everything.
+ //
+
+ //
+ // reset SIOP
+ //
+
+ InitializeSIOP( DeviceExtension);
+
+ //
+ // reset SCSI bus
+ //
+
+ ResetSCSIBus( DeviceExtension);
+
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessIllegalInstruction
+
+
+UCHAR
+ProcessInvalidReselect(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when a device reselects that did not disconnect.
+ Since something is really broken at this point, we just reset everything
+ we can, and hope for the best.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DebugPrint((1, "Sym8xx(%2x) Sym8xxDMAInterrupt: Invalid Reselect \n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ //
+ // reset SIOP
+ //
+
+ InitializeSIOP( DeviceExtension);
+
+ //
+ // reset SCSI bus
+ //
+
+ ResetSCSIBus( DeviceExtension);
+
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessInvalidReselect
+
+
+UCHAR
+ProcessParityError(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine processes parity errors detected on the SCSI bus by the
+ host adapter.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // we must determine if we are in message in phase, or some other phase,
+ // since we must send a different message for each case.
+ //
+
+ DebugPrint((1, "Sym8xx(%2x) ProcessParityError: Parity error detected \n",
+ DeviceExtension->SIOPRegisterBase));
+
+ //
+ // check if SCSI bus message line is high. if so, send MESSAGE PARITY
+ // message, and if not, send INITIATOR DETECTED ERROR message.
+ //
+
+ if ( READ_SIOP_UCHAR(SBCL) & SBCL_MSG)
+ {
+ DeviceExtension->NonCachedExtension->ParityMsgData =
+ SCSIMESS_MESS_PARITY_ERROR;
+ }
+
+ else
+ {
+ DeviceExtension->NonCachedExtension->ParityMsgData =
+ SCSIMESS_INIT_DETECTED_ERROR;
+ }
+
+ //
+ // Start script to send the appropriate message to device.
+ //
+
+ StartSIOP( DeviceExtension, DeviceExtension->SendIDEScriptPhys);
+
+ return( ISR_EXIT);
+
+} // ProcessParityError
+
+
+UCHAR
+ProcessPhaseMismatch(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when a phase mismatch occurs during a data
+ transfer. This normally occurs when a device wishes to disconnect
+ mid-transfer to move to a new cylinder, etc.
+
+ The routine determines how much data the 53C8xx has transferred
+ and how much remains in the chip, and updates pointers accordingly.
+
+ The # of scatter/gather move instructions successfully completed before
+ the phase mismatch occurred is returned in the SCRATCH0 register. A
+ value of FF in this register indicates the mismatch did not occur in
+ DATA phase. This happens with some drives that get confused during
+ synchronous negotiation.
+
+ If the mismatch occurred in a DATA phase, we set a flag to indicate that
+ a mismatch has occurred. When the device issues a SAVE DATA POINTER
+ message, we use the value calculated by this routine to determine the
+ new pointer value.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ ISR_RESTART_SCRIPT to continue normally
+ ISR_START_NEXT_REQUEST if error
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+ ULONG BytesRemaining = 0;
+ ULONG DataTransferred = 0;
+ UCHAR ScsiStatus;
+ UCHAR ScsiStatus2;
+ UCHAR ScriptMoveIndex;
+ USHORT FIFOCount;
+ USHORT DMAFifoByteCount = 0;
+ UCHAR ArrayIndexStart;
+ UCHAR ArrayIndexEnd;
+ ULONG ScriptPhysAddr;
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+ UCHAR i;
+ SCRIPTSG SampleBuffer;
+ PVOID VirtualBufferPointer;
+ ULONG RemainingDataCount;
+ ULONG ElementLength;
+ UCHAR MovedData = 0;
+ UCHAR SCNTL2Reg;
+ UCHAR DataValue;
+ ULONG BufferUlongAddress;
+
+ //
+ // if this phase mismatch occurred during a data phase, the value
+ // returned in the scratch0 register will not be FF.
+ //
+
+ DebugPrint((3, "Sym8xx(%2x) ProcessPhaseMismatch: Mismatch Occurred \n",
+ DeviceExtension->SIOPRegisterBase));
+
+ //
+ // get physical address of script instruction upon which we changed
+ // phases. Note that the DSP register points to the instruction following
+ // the one we want, so we must back up one instruction.
+ //
+
+ ScriptPhysAddr = READ_SIOP_ULONG(DSP);
+
+ ScriptPhysAddr -= SCRIPT_INS_SIZE;
+
+ //
+ // Calculate the index into the script move array upon which we changed
+ // phases: subtract the physical address of the first script move
+ // from the address calculated above, and divide by 8 to convert into
+ // an index (8 bytes per move instruction).
+ //
+
+ if (ScriptPhysAddr <= (DeviceExtension->DataOutStartPhys +
+ sizeof(SCRIPTINS)))
+ {
+ ScriptMoveIndex = (UCHAR) (( DeviceExtension->DataOutStartPhys -
+ ScriptPhysAddr) >> 3);
+
+ Srb->SrbFlags &= ~SRB_FLAGS_DATA_IN;
+ }
+
+ else
+ {
+ ScriptMoveIndex = (UCHAR) (( DeviceExtension->DataInStartPhys -
+ ScriptPhysAddr) >> 3);
+
+ Srb->SrbFlags &= ~SRB_FLAGS_DATA_OUT;
+ }
+
+ if ( ScriptMoveIndex < MAX_PHYS_BREAK_COUNT)
+ {
+ DebugPrint((3,
+ "Sym8xx(%2x) ProcessPhaseMismatch: Moves processed = %x\n",
+ DeviceExtension->SIOPRegisterBase,
+ ScriptMoveIndex
+ ));
+
+ //
+ // get 24 bit BYTES REMAINING counter for this S/G entry from SIOP.
+ //
+
+ for ( i = 0; i < 3; i++)
+ {
+ ((PUCHAR) (&BytesRemaining))[i] = READ_SIOP_UCHAR( DBC[i]);
+ }
+
+ //
+ // if the request was a write, we must determine how much data
+ // remains in the SIOP FIFO's.
+ //
+
+ if ( Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
+ {
+ // 875s' large FIFO / normal 64 byte FIFO
+ // get the low 10 / 7 bits of the DMA FIFO, and subtract the low
+ // 10 / 7 bytes of the # of bytes remaining, and clear the hi bit of
+ // the resultant byte.
+ //
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_875_LARGE_FIFO)
+ {
+ DMAFifoByteCount = (USHORT)READ_SIOP_UCHAR(DFIFO);
+ DMAFifoByteCount |= (USHORT)((READ_SIOP_UCHAR(CTEST5)&0x03)<<8);
+ FIFOCount = DMAFifoByteCount - (USHORT)(BytesRemaining & 0x3FF);
+ FIFOCount &= 0x3FF;
+ }
+
+ else
+ {
+ FIFOCount = (( READ_SIOP_UCHAR( DFIFO)
+ & (UCHAR) DFIFO_LOW_SEVEN)
+ - (UCHAR) ( BytesRemaining & 0x07f))
+ & (UCHAR) DFIFO_LOW_SEVEN;
+ }
+
+ //
+ // if the SCSI output data register contains a byte, increment
+ // the FIFO count.
+ //
+ // Possible chip bug reported by CHC (DEC) Under heavy scsi traffic,
+ // the SSTAT1_ORF bit will get lit for some reason when the transfer
+ // is asynchronous. This bit should *only* be checked
+ // during synchronous transfers.
+ //
+
+ if (((ScsiStatus = READ_SIOP_UCHAR(SSTAT0)) & (UCHAR) SSTAT1_ORF) &&
+ !(DeviceExtension->LuFlags[Srb->TargetId] &
+ LUFLAGS_SYNC_NEGOT_FAILED))
+ {
+ FIFOCount += 1;
+ }
+
+ if (((ScsiStatus2 = READ_SIOP_UCHAR(SSTAT2)) & (UCHAR) SSTAT2_ORF) &&
+ !(DeviceExtension->LuFlags[Srb->TargetId] &
+ LUFLAGS_SYNC_NEGOT_FAILED))
+ {
+ FIFOCount += 1;
+ }
+
+ //
+ // if the SCSI output data latch contains a byte, increment
+ // the FIFO count.
+ //
+
+ if ( ScsiStatus & SSTAT1_OLF)
+ {
+ FIFOCount += 1;
+ }
+
+ if ( ScsiStatus2 & (UCHAR) SSTAT2_OLF)
+ {
+ FIFOCount += 1;
+ }
+
+ //
+ // add the FIFO count to the bytes remaining.
+ //
+
+ BytesRemaining += (ULONG) FIFOCount;
+
+ //
+ // clear the DMA and SCSI FIFO's
+ //
+
+ WRITE_SIOP_UCHAR( CTEST3, CTEST3_CLEAR_FIFO);
+
+ // insure the WSS bit is off so the low order byte stored in the chip
+ // will be forgotten about. (chmov script instruction) stored in
+ // SODL register so the fifo count has already been taken care of
+
+ if ( (SCNTL2Reg = READ_SIOP_UCHAR(SCNTL2)) & SCNTL2_WSS)
+ {
+ WRITE_SIOP_UCHAR(SCNTL2, (UCHAR)(SCNTL2Reg & ~SCNTL2_WSS));
+ }
+
+ } // if for data out checks
+
+ else // data in section
+ {
+ // if the WSR bit is on, the chip is retaining a byte in the swide
+ // register which we need to manually put into its RAM space. This
+ // byte will always be at the start of a scatter\gather section so
+ // we only need to scan the virtual buffers break points for the
+ // location to stick the byte. (wide transfer - odd byte scatter/
+ // gather lists possibility.
+
+ if ( (SCNTL2Reg = READ_SIOP_UCHAR(SCNTL2)) & SCNTL2_WSR)
+ {
+ DataValue = READ_SIOP_UCHAR(SWIDE);
+ WRITE_SIOP_UCHAR(SCNTL2, (UCHAR)(SCNTL2Reg & ~SCNTL2_WSR));
+ BytesRemaining--;
+ BufferUlongAddress =
+ ScriptDataPtr->SGBufferArray[ScriptMoveIndex + 1].SGBufferPtr;
+ VirtualBufferPointer = Srb->DataBuffer;
+ RemainingDataCount = Srb->DataTransferLength;
+ do
+ {
+ SampleBuffer.SGBufferPtr =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(
+ DeviceExtension,
+ Srb,
+ VirtualBufferPointer,
+ &ElementLength));
+ if ( BufferUlongAddress == SampleBuffer.SGBufferPtr )
+ {
+ *(PUCHAR)VirtualBufferPointer = DataValue;
+ MovedData = 1;
+ RemainingDataCount = 0;
+ }
+
+ else
+ {
+ if ( ElementLength > RemainingDataCount )
+ {
+ ElementLength = RemainingDataCount;
+ }
+
+ (ULONG)VirtualBufferPointer += ElementLength;
+ RemainingDataCount -= ElementLength;
+ }
+ } while ( RemainingDataCount );
+
+ if ( !MovedData )
+ {
+ // if we're here, pointers have gotten messed up, just reset
+ InitializeSIOP(DeviceExtension);
+ ResetSCSIBus(DeviceExtension);
+ return(ISR_START_NEXT_REQUEST);
+ }
+ }
+ }
+
+ //
+ // loop through all the moves that were processed to get the total
+ // byte count moved before the SAVE DATA PTRS.
+ //
+
+ ArrayIndexStart = MAX_SG_ELEMENTS - SRB_EXT(Srb)->PhysBreakCount;
+ ArrayIndexEnd = ArrayIndexStart + SRB_EXT(Srb)->PhysBreakCount -
+ ScriptMoveIndex - 1;
+
+ for ( i = ArrayIndexStart; i <= ArrayIndexEnd; i++)
+ {
+ DataTransferred += ScriptDataPtr->SGBufferArray[i].SGByteCount;
+ }
+
+ //
+ // subtract the bytes remaining on the last move processed from the
+ // total bytes transferred, and store this value.
+ //
+
+ SRB_EXT(Srb)->DataTransferred = DataTransferred - BytesRemaining;
+ }
+
+
+ else
+ {
+ //
+ // the phase mismatch did not occur during a data phase.
+ // this will happen in cases such as a phase change during an
+ // extended message. flush the FIFO's and exit.
+ //
+
+ WRITE_SIOP_UCHAR( CTEST3, CTEST3_CLEAR_FIFO);
+ }
+
+ //
+ // tell ISR to restart script state machine
+ //
+
+ return(ISR_RESTART_SCRIPT);
+
+} // ProcessPhaseMismatch
+
+
+BOOLEAN
+ProcessParseArgumentString(
+ IN PCHAR String,
+ IN PCHAR WantedString,
+ OUT PULONG ValueFound
+ )
+
+/******************************************************************************
+
+Routine Description:
+
+ This routine will parse the string for a match on the wanted string, then
+ calculate the value for the wnated string and return it to the caller.
+
+Arguments:
+
+ String - The ASCII string to parse.
+ WantedString - The keyword for the value desired.
+ ValueFound - address where the value found is placed
+
+Return Values:
+
+ TRUE if WantedString found, FALSE if not
+ ValueFound converted from ASCII to binary.
+
+--*/
+
+{
+ PCHAR cptr;
+ PCHAR kptr;
+ ULONG stringLength = 0;
+ ULONG WantedStringLength = 0;
+ ULONG index;
+
+ //
+ // Calculate the string length and lower case all characters.
+ //
+ cptr = String;
+ while (*cptr)
+ {
+ if (*cptr >= 'A' && *cptr <= 'Z')
+ {
+ *cptr = *cptr + ('a' - 'A');
+ }
+
+ cptr++;
+ stringLength++;
+ }
+
+ //
+ // Calculate the wanted strings length and lower case all characters.
+ //
+ cptr = WantedString;
+ while (*cptr)
+ {
+ if (*cptr >= 'A' && *cptr <= 'Z')
+ {
+ *cptr = *cptr + ('a' - 'A');
+ }
+
+ cptr++;
+ WantedStringLength++;
+ }
+
+ if (WantedStringLength > stringLength)
+ {
+ // Can't possibly have a match.
+ return FALSE;
+ }
+
+ //
+ // Now setup and start the compare.
+ //
+ cptr = String;
+
+ContinueSearch:
+ //
+ // The input string may start with white space. Skip it.
+ //
+ while (*cptr == ' ' || *cptr == '\t')
+ {
+ cptr++;
+ }
+
+ if (*cptr == '\0')
+ {
+ // end of string.
+ return FALSE;
+ }
+
+ kptr = WantedString;
+ while (*cptr++ == *kptr++)
+ {
+ if (*(cptr - 1) == '\0')
+ // end of string
+ return FALSE;
+ }
+
+ if (*(kptr - 1) == '\0')
+ {
+ // May have a match backup and check for blank or equals.
+ cptr--;
+ while (*cptr == ' ' || *cptr == '\t')
+ {
+ cptr++;
+ }
+
+ // Found a match. Make sure there is an equals.
+ if (*cptr != '=')
+ {
+ // Not a match so move to the next semicolon.
+ while (*cptr)
+ {
+ if (*cptr++ == ';')
+ goto ContinueSearch;
+ }
+ return FALSE;
+ }
+
+ // Skip the equals sign.
+ cptr++;
+
+ // Skip white space.
+ while ((*cptr == ' ') || (*cptr == '\t'))
+ cptr++;
+
+ if (*cptr == '\0')
+ // Early end of string, return not found
+ return FALSE;
+
+ if (*cptr == ';')
+ {
+ // This isn't it either.
+ cptr++;
+ goto ContinueSearch;
+ }
+
+ *ValueFound = 0;
+ if ((*cptr == '0') && (*(cptr + 1) == 'x'))
+ {
+ // Value is in Hex. Skip the "0x"
+ cptr += 2;
+ for (index = 0; *(cptr + index); index++)
+ {
+ if (*(cptr + index) == ' ' || *(cptr + index) == '\t' ||
+ *(cptr + index) == ';')
+ {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9'))
+ {
+ *ValueFound = (16 * (*ValueFound)) + (*(cptr + index) - '0');
+ }
+
+ else
+ {
+ if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f'))
+ {
+ *ValueFound = (16 * (*ValueFound)) + (*(cptr + index) - 'a' + 10);
+ }
+ else
+ {
+ // Syntax error, return not found.
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ else
+ {
+ // Value is in Decimal.
+ for (index = 0; *(cptr + index); index++)
+ {
+ if (*(cptr + index) == ' ' || *(cptr + index) == '\t' ||
+ *(cptr + index) == ';')
+ {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9'))
+ {
+ *ValueFound = (10 * (*ValueFound)) + (*(cptr + index) - '0');
+ }
+
+ else
+ {
+ // Syntax error return not found.
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+ }
+
+ else
+ {
+ // Not a match check for ';' to continue search.
+ while (*cptr)
+ {
+ if (*cptr++ == ';')
+ goto ContinueSearch;
+ }
+ }
+
+ return FALSE;
+
+} // ProcessParseArgumentString
+
+
+UCHAR
+ProcessQueueTagReceived(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when the target sends a queue tag messaged as
+ part of reselected.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ Returns the action to be taken after the interrupt.
+
+--*/
+
+{
+ UCHAR Tag;
+ DebugPrint((2, "Sym8xx(%2x) Queue tag messaged received \n",
+ DeviceExtension->SIOPRegisterBase));
+
+ //
+ // Clear the connection flag.
+ //
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_CONNECTED;
+
+ //
+ // Get the tag from the message buffer;
+ //
+
+ Tag = DeviceExtension->NonCachedExtension->MsgInBuf[0];
+
+ //
+ // Get the active SRB.
+ //
+
+ DeviceExtension->ActiveRequest = ScsiPortGetSrb( DeviceExtension,
+ 0,
+ DeviceExtension->TargetId,
+ DeviceExtension->LUN,
+ Tag
+ );
+
+ //
+ // See if this is a tagged request.
+ //
+
+ if (DeviceExtension->ActiveRequest == NULL)
+ {
+ DebugPrint((1,
+ "Sym8xx(%2x): Invalid Tag, Path=%2x Id= %2x, Tag = %2x\n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ DeviceExtension->TargetId,
+ Tag));
+
+ //
+ // either we were SELECTED, or something is really hosed.
+ // perform drastic error recovery.
+ //
+
+ InitializeSIOP( DeviceExtension);
+ ResetSCSIBus( DeviceExtension);
+ return( ISR_START_NEXT_REQUEST);
+ }
+
+ //
+ // if there is data to transfer set up scatter/gather.
+ //
+
+ if (DeviceExtension->ActiveRequest->SrbFlags &
+ SRB_FLAGS_UNSPECIFIED_DIRECTION )
+ {
+ ScatterGatherScriptSetup( DeviceExtension,
+ DeviceExtension->ActiveRequest->SrbExtension
+ );
+ }
+
+ return( ISR_RESTART_SCRIPT);
+
+} // ProcessQueueTagReceived
+
+
+UCHAR
+ProcessRejectReceived(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine is called when a device rejects a message sent in scripts.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK Srb;
+
+ DebugPrint((1,
+ "Sym8xx(%2x) ProcessDMAInterrupt: Message reject received \n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ Srb = DeviceExtension->ActiveRequest;
+
+ if ((DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND) ||
+ (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_NARROW_NEGOT_PEND))
+ {
+ return( ProcessWideNotSupported( DeviceExtension, Srb->TargetId));
+ }
+
+ if ((DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND) ||
+ (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_ASYNC_NEGOT_PEND))
+ {
+ return( ProcessSynchNotSupported( DeviceExtension));
+ }
+
+ //
+ // the rejected message
+ //
+
+ return( ISR_RESTART_SCRIPT);
+
+} // ProcessRejectReceived
+
+
+UCHAR
+ProcessReselection(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR TargetID
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine handles a normal device reselection.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension;
+ UCHAR LUN;
+
+ //
+ // check if there is an active request. if so, we preempted someone
+ // who was trying to start a new request.
+ //
+
+ if ( DeviceExtension->ActiveRequest != NULL)
+ {
+ //
+ // put this guy back on holding queue.
+ //
+
+ DeviceExtension->NextSrbToProcess = DeviceExtension->ActiveRequest;
+
+ //
+ // indicate no active request
+ //
+
+ DeviceExtension->ActiveRequest = NULL;
+
+ DebugPrint((3, "Sym8xx(%2x) Preemptive reselection, Path=%2x Id=%2x\n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ TargetID
+ ));
+ }
+
+ DebugPrint((3, "Sym8xx(%2x) Reselection by Path=%2x Id=%2x \n ",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ TargetID
+ ));
+
+ //
+ // retrieve LUN from MESSAGE IN buffer
+ //
+
+ LUN = (UCHAR) ( DeviceExtension->NonCachedExtension->MsgInBuf[0] &
+ SCSIMESS_IDENTIFY_LUN_MASK);
+
+ DeviceExtension->TargetId = TargetID;
+ DeviceExtension->LUN = LUN;
+
+ //
+ // get logical unit extension for this ID/LUN.
+ //
+
+ LuExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ DeviceExtension->BusNumber,
+ TargetID,
+ LUN
+ );
+ //
+ // Confirm that this is a valid logical unit.
+ //
+
+ if (LuExtension == NULL)
+ {
+ DebugPrint((1, "Sym8xx(%2x): Invalid reselection, Path=%2x Id=%2x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ TargetID
+ ));
+ TargetID = READ_SIOP_UCHAR(SSID);
+
+ //
+ // Temporary workaround for chip anomoly
+ //
+ // TODO: Find out why this occurs, if it still occurs.
+ //
+
+ if (TargetID & 0x80)
+ {
+ TargetID &= 0x07;
+ LuExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ DeviceExtension->BusNumber,
+ TargetID,
+ LUN
+ );
+ }
+
+ else
+ {
+ DebugPrint((1, "Sym8xx(%2x): Still invalid, Path=%2x Id=%2x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ TargetID
+ ));
+ }
+
+ //
+ // either we were SELECTED, or something is really hosed.
+ // perform drastic error recovery.
+ //
+
+ DebugPrint((0,"Reselection Error[1] \n"));
+ InitializeSIOP( DeviceExtension);
+ ResetSCSIBus( DeviceExtension);
+ return( ISR_START_NEXT_REQUEST);
+
+ } // if
+
+ //
+ // decrement depth counter for disconnected requests
+ //
+
+ if ( DeviceExtension->DisconnectedCount[TargetID] != 0 )
+ {
+ DeviceExtension->DisconnectedCount[TargetID]-- ;
+ }
+
+ //
+ // See if this is a tagged request.
+ //
+
+ DeviceExtension->ActiveRequest = LuExtension->UntaggedRequest;
+
+ if (DeviceExtension->ActiveRequest == NULL)
+ {
+ //
+ // Set the connection flag, etc..
+ //
+
+ DeviceExtension->DeviceFlags |= DFLAGS_CONNECTED;
+ DeviceExtension->DeviceFlags |= DFLAGS_TAGGED_SELECT;
+
+ //
+ // This request must be tagged, process the tagged message.
+ //
+
+ StartSIOP( DeviceExtension, DeviceExtension->QueueTagPhys);
+ return( ISR_EXIT);
+ }
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_TAGGED_SELECT;
+
+ //
+ // If there is data to transfer set up scatter/gather.
+ //
+
+ if (DeviceExtension->ActiveRequest->SrbFlags &
+ SRB_FLAGS_UNSPECIFIED_DIRECTION)
+ {
+ ScatterGatherScriptSetup( DeviceExtension,
+ DeviceExtension->ActiveRequest->SrbExtension
+ );
+ }
+
+ //
+ // tell ISR to restart script state machine
+ //
+
+ return( ISR_RESTART_SCRIPT);
+
+} // ProcessReselection
+
+
+UCHAR
+ProcessRestorePointers(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine restores the data pointers if they exist.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // If there is data to transfer set up scatter/gather.
+ //
+
+ if ( DeviceExtension->ActiveRequest->SrbFlags &
+ SRB_FLAGS_UNSPECIFIED_DIRECTION)
+ {
+ ScatterGatherScriptSetup( DeviceExtension,
+ DeviceExtension->ActiveRequest->SrbExtension
+ );
+ }
+
+ //
+ // tell ISR to restart script state machine
+ //
+
+ return( ISR_RESTART_SCRIPT);
+
+} // ProcessRestorePointers
+
+
+UCHAR
+ProcessSaveDataPointers(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine determines how much data was transferred before the SAVE
+ DATA PTRS message was received, and updates pointers accordingly.
+
+ The # of scatter/gather move instructions successfully completed before
+ the SAVE DATA PTRS occurred is returned in the SCRATCH0 register. A
+ value of FF in this register indicates that no data was transferred.
+ If a phase mismatch occurred before we arrived here, a flag was set to
+ a mismatch has occurred. When the device issues a SAVE DATA POINTER
+ indicate the mismatch, and the value of scratch0 was saved at that time.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSRB_EXTENSION SrbExtension = DeviceExtension->ActiveRequest->SrbExtension;
+
+ //
+ // compute the new pointers.
+ //
+
+ SrbExtension->SavedDataPointer += SrbExtension->DataTransferred;
+ SrbExtension->SavedDataLength -= SrbExtension->DataTransferred;
+
+ //
+ // tell the ISR to restart the script and complete the request.
+ //
+
+ return( ISR_RESTART_SCRIPT);
+
+} // ProcessSaveDataPointers
+
+
+UCHAR
+ProcessSCSIInterrupt(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR ScsiStatus
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine processes interrupts from the SCSI core of the 53C8xx SIOP.
+
+Arguments:
+
+ Context - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ //
+ // todo - decide whether to move critical path SCSI interrupt processing
+ // up from subroutines to reduce overhead.
+ //
+
+ //
+ // if a SCSI bus reset is detected, call routine to process, and return
+ // disposition code to ISR.
+ //
+
+ if ( ScsiStatus & SSTAT0_RESET)
+ {
+ return( ProcessBusResetReceived( DeviceExtension));
+ }
+
+ //
+ // The following SCSI interrupts should only occur when we have an
+ // active SRB. To be safe, we check for one. If there is not an
+ // active SRB, the hardware has interrupted inappropriately,
+ // so reset everything.
+ //
+
+ if (DeviceExtension->ActiveRequest == NULL)
+ {
+ DebugPrint((1, "Sym8xx(%2x) ProcessSCSIInterrupt unknown request\n",
+ DeviceExtension->SIOPRegisterBase));
+ DebugPrint((1, " ActiveRequest: %lx ScsiStatus: %x\n",
+ DeviceExtension->ActiveRequest, ScsiStatus));
+
+ InitializeSIOP( DeviceExtension);
+ ResetSCSIBus( DeviceExtension);
+ return( ISR_START_NEXT_REQUEST);
+ }
+
+ //
+ // if a SCSI phase mismatch occurred call routine to process, and return
+ // disposition code to ISR.
+ //
+
+ if ( ScsiStatus & SSTAT0_PHASE_MISMATCH)
+ {
+ return( ProcessPhaseMismatch( DeviceExtension));
+ }
+
+ //
+ // if a SCSI gross error occurred call routine to process, and return
+ // disposition code to ISR.
+ //
+
+ if ( ScsiStatus & SSTAT0_GROSS_ERROR)
+ {
+ return( ProcessGrossError( DeviceExtension));
+ }
+
+ //
+ // if an unexpected disconnect occurred call routine to process, and
+ // return disposition code to ISR.
+ //
+
+ if ( ScsiStatus & SSTAT0_UNEXPECTED_DISCONNECT)
+ {
+ return( ProcessUnexpectedDisconnect( DeviceExtension));
+ }
+
+ //
+ // if a parity error was detected call routine to process, and return
+ // disposition code to ISR.
+ //
+
+ if ( ScsiStatus & SSTAT0_PARITY_ERROR)
+ {
+ return( ProcessParityError( DeviceExtension));
+ }
+
+ //
+ // if none of the above, the hardware is in an unknown state. Perform
+ // drastic error recovery.
+ //
+
+ InitializeSIOP( DeviceExtension);
+ ResetSCSIBus( DeviceExtension);
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessSCSIInterrupt
+
+
+UCHAR
+ProcessSelectionTimeout(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine processes selection timeouts.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension;
+
+ //
+ // the 53C8xx SIOP generates an UNEXPECTED DISCONNECT interrupt along
+ // with SELECTION TIMEOUT. We read the SCSI STATUS register to throw
+ // it away. This is safe since no additional SCSI interrupt should have
+ // been generated at this time.
+ //
+
+ READ_SIOP_UCHAR( SIST0);
+
+ //
+ // get the logical unit extension and SRB for the request that timed out.
+ //
+
+ Srb = DeviceExtension->ActiveRequest;
+
+ if (!Srb)
+ {
+ return ISR_EXIT;
+ }
+
+ DebugPrint((1,
+ "Sym8xx(%2x) SelectionTimeout: Timeout for Path=%2x Id=%2x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+
+ //
+ // indicate this request is no longer active.
+ //
+
+ DeviceExtension->ActiveRequest = NULL;
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) )
+ {
+ LuExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+
+ LuExtension->UntaggedRequest = NULL;
+ }
+
+ //
+ // indicate selection timeout occurred and notify superiors.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ //
+ // tell ISR to start new request.
+ //
+
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessSelectionTimeout
+
+
+UCHAR
+ProcessSynchNegotComplete(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine handles successful synchronous negotiation. The routine
+ first retrieves the synchronous period and offset from the message in
+ buffer, then massages the parameters into a form the SIOP can use.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UCHAR RecvdSynchPeriod;
+ UCHAR RecvdSynchOffset;
+ UCHAR SynchIndex = 0;
+ UCHAR Scntl3Value;
+ UCHAR EffectiveClockSpeed;
+ UCHAR MaxOffset, MinPeriod;
+ UCHAR SynchPeriod;
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+
+ if (!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND) &&
+ !(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_ASYNC_NEGOT_PEND))
+ {
+ DebugPrint((1,
+ "Sym8xx(%2x) ProcessSynchNegotComplete: Rejecting SDTR message.\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ //
+ // If we are not doing negotation then reject this request.
+ //
+
+ DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS;
+ ScriptDataPtr->SelectDataSXFER=DeviceExtension->SyncParms[Srb->TargetId];
+ WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] );
+
+ StartSIOP( DeviceExtension, DeviceExtension->RejectScriptPhys);
+
+ //
+ // We're here if the target device has tried to negotiate sync with
+ // us when we don't support the target initiating the negotiation.
+ // Now, make sure we do not think that this device is still in SYNCH.
+ // transfer mode from some earlier successful negotiation. We'll i
+ // redo it all on the next command with US as the initiator.
+ //
+
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_DONE;
+
+ return( ISR_EXIT);
+ }
+
+ //
+ // If we were trying Asynch negotiations, cleanup is a lot less
+ //
+
+ if ( DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_ASYNC_NEGOT_PEND )
+ {
+
+ //
+ // indicate we are no longer expecting a negotiation reply
+ //
+
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_ASYNC_NEGOT_PEND +
+ LUFLAGS_SYNC_NEGOT_PEND);
+
+ //
+ // pick up offset from Script message buffer
+ //
+
+ RecvdSynchOffset = DeviceExtension->NonCachedExtension->MsgInBuf[1];
+
+ if (RecvdSynchOffset != 0)
+ {
+ DebugPrint((0, "Sym8xx(%2x) Rejecting SDTR message. Asynch failed\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_FAILED;
+
+ DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS;
+ WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] );
+
+ //
+ // value out of range, reject this request.
+ //
+
+ StartSIOP( DeviceExtension, DeviceExtension->RejectScriptPhys);
+
+ return( ISR_EXIT);
+ }
+
+ //
+ // indicate asynch params are valid, and restart the script.
+ //
+
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_ASYNC_NEGOT_DONE;
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_DONE;
+ }
+
+ else // Finish up synchronous negotiations.
+ {
+ //
+ // indicate we are no longer expecting a negotiation reply
+ //
+
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_ASYNC_NEGOT_PEND +
+ LUFLAGS_SYNC_NEGOT_PEND);
+
+ //
+ // Clear the failed negot. flag. If needed, it will be set on failure.
+ // if we have done sync. values, now need to check sstat1_orf
+
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_FAILED;
+
+ //
+ // pick up synch period and offset from Script message buffer
+ //
+
+ RecvdSynchPeriod = DeviceExtension->NonCachedExtension->MsgInBuf[0];
+ RecvdSynchOffset = DeviceExtension->NonCachedExtension->MsgInBuf[1];
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SYNC_16)
+ {
+ MaxOffset = MAX_875_SYNCH_OFFSET;
+ }
+
+ else
+ {
+ MaxOffset = MAX_SYNCH_OFFSET;
+ }
+
+ if (RecvdSynchOffset == 0)
+ {
+ MinPeriod = 0;
+ }
+
+ else
+ {
+ if ((DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20) &&
+ (DeviceExtension->hbaCapability & HBA_CAPABILITY_REGISTRY_FAST20))
+ {
+ MinPeriod = 0x0C;
+ }
+
+ else
+ {
+ MinPeriod = 0x19;
+ }
+ }
+
+ DebugPrint((1,
+ "Sym8xx(%2x) SynchronousNegotiation Received - Path=%2x Id=%2x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+
+ DebugPrint((1, " Period: %x Offset: %x\n",
+ RecvdSynchPeriod,
+ RecvdSynchOffset
+ ));
+
+ if ( RecvdSynchOffset == 0 )
+ {
+ DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS;
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_FAILED;
+
+ DebugPrint((1, "Sym8xx(%1x) Synchronous Disabled - Target: %x\n",
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+ }
+
+ else
+ {
+ //
+ // Check for a FAST SCSI request. If the request is faster than 200ns
+ // then it is fast.
+ //
+
+ EffectiveClockSpeed = DeviceExtension->ClockSpeed;
+ Scntl3Value = (DeviceExtension->WideParms[Srb->TargetId] & 0x0F);
+
+ if (EffectiveClockSpeed == 80)
+ {
+ // check to see if device wants to do FAST 20
+ //
+
+ if (RecvdSynchPeriod == 0x0C)
+ {
+ Scntl3Value = (UCHAR)(Scntl3Value | 0x90);
+ WRITE_SIOP_UCHAR(SCNTL3, Scntl3Value);
+ DeviceExtension->NonCachedExtension->ScriptData.SelectDataSCNTL3 =
+ Scntl3Value;
+ DeviceExtension->WideParms[Srb->TargetId] = Scntl3Value;
+ DeviceExtension->SyncParms[Srb->TargetId] = RecvdSynchOffset;
+ }
+
+ else // set up to check regular SCSI Sync
+ {
+ // divide 80Mhz clock by 2 so we can still use old conversion rtn
+ Scntl3Value = (UCHAR)(Scntl3Value | 0x30);
+ WRITE_SIOP_UCHAR(SCNTL3, Scntl3Value);
+ DeviceExtension->NonCachedExtension->ScriptData.SelectDataSCNTL3 =
+ Scntl3Value;
+ DeviceExtension->WideParms[Srb->TargetId] = Scntl3Value;
+ EffectiveClockSpeed = 40;
+ }
+ }
+
+ if (EffectiveClockSpeed == 40)
+ {
+ if (DeviceExtension->ClockSpeed == 40)
+ {
+ Scntl3Value = (UCHAR)(Scntl3Value | 0x10);
+ WRITE_SIOP_UCHAR(SCNTL3, Scntl3Value);
+ DeviceExtension->NonCachedExtension->ScriptData.SelectDataSCNTL3 =
+ Scntl3Value;
+ DeviceExtension->WideParms[Srb->TargetId] = Scntl3Value;
+ } // if
+
+ for (SynchIndex = 0;SynchIndex < MAX_SYNCH_TABLE_ENTRY; SynchIndex++)
+ {
+ SynchPeriod = ((1000 / EffectiveClockSpeed) * (4 + SynchIndex)) / 4;
+ if (RecvdSynchPeriod <= SynchPeriod)
+ {
+ DeviceExtension->SyncParms[Srb->TargetId] =
+ (UCHAR) (SynchIndex << 0x05) | RecvdSynchOffset;
+ break;
+ }
+ } // for
+ } // if
+ } // else
+
+ // check for valid values, reject target if not OK
+ if ( (SynchIndex >= MAX_SYNCH_TABLE_ENTRY) ||
+ (RecvdSynchOffset > MaxOffset) ||
+ (RecvdSynchPeriod < MinPeriod) ||
+ ( (RecvdSynchPeriod > 0x0C) &&
+ (RecvdSynchPeriod < 0x19) &&
+ (RecvdSynchOffset != 0) ) )
+ {
+ DebugPrint((0, "Sym8xx(%2x) Rejecting SDTR message. Rate too slow\n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_FAILED;
+ DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS;
+ WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] );
+
+ //
+ // values were out of our range, reject this request.
+ //
+
+ StartSIOP( DeviceExtension, DeviceExtension->RejectScriptPhys);
+
+ return( ISR_EXIT);
+
+ } // if
+
+ //
+ // indicate synch params are valid, and restart the script.
+ //
+
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_DONE;
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_ASYNC_NEGOT_DONE;
+
+ } // else
+
+ //
+ // tell ISR to restart script state machine
+ //
+ //
+
+ return( ISR_RESTART_SCRIPT);
+
+} // ProcessSynchNegotComplete
+
+
+UCHAR
+ProcessSynchNotSupported(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine handles unsuccessful synchronous negotiation. The routine
+ sets the synchronous parameters to asynchronous, and sets the appropriate
+ flag.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+
+ DebugPrint((1,
+ "Sym8xx(%2x) Synchronous negotiation failed, Path=%2x Id=%2x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ *((PUCHAR) &(DeviceExtension->ActiveRequest)->TargetId)
+ ));
+
+ //
+ // indicate drive is low technology.
+ //
+ if (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND)
+ {
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_DONE +
+ LUFLAGS_SYNC_NEGOT_FAILED;
+ }
+ else
+ {
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_ASYNC_NEGOT_DONE +
+ LUFLAGS_SYNC_NEGOT_FAILED;
+ }
+
+ //
+ // indicate we are no longer expecting a negotiation reply
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_SYNC_NEGOT_PEND +
+ LUFLAGS_ASYNC_NEGOT_PEND);
+
+ //
+ // set up for asynchronous xfer.
+ //
+ DeviceExtension->SyncParms[Srb->TargetId] = ASYNCHRONOUS_MODE_PARAMS;
+
+ //
+ // tell ISR to restart script state machine
+ //
+
+ return( ISR_RESTART_SCRIPT);
+
+} // ProcessSynchNotSupported
+
+
+UCHAR
+ProcessWideNegotComplete(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine handles successful wide negotiation. The routine
+ first retrieves the wide width from the message in
+ buffer, then massages the parameters into a form the SIOP can use.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UCHAR RecvdWideWidth;
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+ PHW_NONCACHED_EXTENSION NonCachedExt = DeviceExtension->NonCachedExtension;
+ ULONG MessageCount=0;
+
+ if (!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND)&&
+ !(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_NARROW_NEGOT_PEND))
+ {
+ DebugPrint((1,
+ "Sym8xx(%1x) ProcessWideNegotComplete: Rejecting SDTR message.\n",
+ DeviceExtension->ScsiBusNumber
+ ));
+
+ //
+ // If we are not doing negotation then reject this request.
+ //
+
+ StartSIOP( DeviceExtension, DeviceExtension->RejectScriptPhys);
+
+ //
+ // We're here if the target device has tried to negotiate wide with
+ // us when we don't support the target initiating the negotiation.
+ // Now, make sure we do not think that this device is still in WIDE
+ // transfer mode from some earlier successful negotiation. We'll i
+ // redo it all on the next command with US as the initiator.
+ //
+
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_WIDE_NEGOT_DONE +
+ LUFLAGS_NARROW_NEGOT_DONE);
+
+ return( ISR_EXIT);
+ } // if
+
+ if (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND)
+ {
+ //
+ // indicate we are no longer expecting a negotiation reply
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_WIDE_NEGOT_PEND +
+ LUFLAGS_NARROW_NEGOT_PEND);
+
+ //
+ // Assume that wide neg. reset any synch/asynch settings
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_SYNC_NEGOT_DONE +
+ LUFLAGS_ASYNC_NEGOT_DONE);
+
+ //
+ // pick up wide width from Script message buffer
+ //
+ RecvdWideWidth = DeviceExtension->NonCachedExtension->MsgInBuf[0];
+
+ DebugPrint((1, "Sym8xx(%1x) WideNegotiation Received - Target: %x\n",
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+
+ if (RecvdWideWidth == 0)
+ {
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_FAILED;
+ DeviceExtension->WideParms[Srb->TargetId] &= ~ENABLE_WIDE;
+ DebugPrint((1, "Sym8xx(%1x) Wide Disabled - Target: %x\n",
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+ }
+
+ else
+ {
+ DeviceExtension->WideParms[Srb->TargetId] |= ENABLE_WIDE;
+ DebugPrint((1, "Sym8xx(%1x) WideNegotiation Agreed - Target: %x\n",
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+ }
+
+ //
+ // indicate wide params are valid, and restart the script.
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_NARROW_NEGOT_DONE;
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_DONE;
+ }
+
+ else
+ {
+ //
+ // indicate we are no longer expecting a negotiation reply
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_NARROW_NEGOT_PEND +
+ LUFLAGS_WIDE_NEGOT_PEND);
+
+ //
+ // Assume that narrow neg. reset any synch/asynch settings
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~(LUFLAGS_SYNC_NEGOT_DONE +
+ LUFLAGS_ASYNC_NEGOT_DONE);
+
+ //
+ // pick up wide width from Script message buffer
+ //
+ RecvdWideWidth = DeviceExtension->NonCachedExtension->MsgInBuf[0];
+
+ DebugPrint((1, "Sym8xx(%1x) NarrowNegotiation Received - Target: %x\n",
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+
+ if (RecvdWideWidth != 0)
+ {
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_FAILED;
+ DeviceExtension->WideParms[Srb->TargetId] &= ~ENABLE_WIDE;
+ DebugPrint((1, "Sym8xx(%1x) Wide Disabled - Target: %x\n",
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+ }
+
+ else
+ {
+ DeviceExtension->WideParms[Srb->TargetId] &= ~ENABLE_WIDE;
+ DebugPrint((1, "Sym8xx(%1x) NarrowNegotiation Agreed - Target: %x\n",
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId
+ ));
+ }
+
+ //
+ // indicate wide params are valid, and restart the script.
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_WIDE_NEGOT_DONE;
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_NARROW_NEGOT_DONE;
+ }
+
+ //
+ // check on synch/asynch negotiations
+ //
+ if ((!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_DONE)
+ && !( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER ))
+ || (!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_ASYNC_NEGOT_DONE)
+ && ( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER )) )
+ {
+ //
+ // fill in the parameters for SDTR extended message
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_EXTENDED_MESSAGE;
+ NonCachedExt->MsgOutBuf[MessageCount++] = 3; // 3 message bytes
+ NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_SYNCHRONOUS_DATA_REQ;
+
+ if (!( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER))
+ {
+ //
+ // Clear any synchronous negotiations
+ //
+ DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS;
+
+ //
+ // indicate sync negotiation is not done
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_PEND;
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_ASYNC_NEGOT_PEND;
+
+ //
+ // Initialize sync period to maximum supported
+ //
+ // Period = ((1000 / (ClockSpeed / 1)) * (4 + xferp)) / 4
+ // where xferp = 0
+ // modified for FAST20 devices, set msg byte to 0x0C since divide
+ // of 1000 by 80 equals 12.5
+ //
+ if ((DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20) &&
+ (DeviceExtension->hbaCapability & HBA_CAPABILITY_REGISTRY_FAST20))
+ {
+ NonCachedExt->MsgOutBuf[MessageCount++] = 12;
+ }
+
+ else
+ {
+ NonCachedExt->MsgOutBuf[MessageCount++] = 25;
+ }
+
+ //
+ // Initialize sync offset to maximum
+ //
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SYNC_16)
+ {
+ NonCachedExt->MsgOutBuf[MessageCount++] = MAX_875_SYNCH_OFFSET;
+ }
+
+ else
+ {
+ NonCachedExt->MsgOutBuf[MessageCount++] = MAX_SYNCH_OFFSET;
+ }
+
+ DebugPrint((1,
+ "Sym8xx(%2x): SynchronousNegotiation Requested - Target: %x\n",
+ DeviceExtension->SIOPRegisterBase,
+ (DeviceExtension->ActiveRequest)->TargetId
+ ));
+
+ DebugPrint((1, " Period: %x Offset: %x\n",
+ NonCachedExt->MsgOutBuf[MessageCount-2],
+ MAX_SYNCH_OFFSET
+ ));
+ }
+
+ else
+ {
+ //
+ // Clear any synchronous negotiations
+ //
+ DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS;
+
+ //
+ // indicate async negotiation is not done
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_ASYNC_NEGOT_PEND;
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_PEND;
+
+ //
+ // Initialize sync period to 0
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = 0;
+
+ //
+ // Initialize sync offset to 0
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = 0;
+
+ DebugPrint((1,
+ "Sym8xx(%2x): AsynchronousNegotiation Requested - Target: %x\n",
+ DeviceExtension->SIOPRegisterBase,
+ (DeviceExtension->ActiveRequest)->TargetId
+ ));
+
+ DebugPrint((1, " Period: %x Offset: %x\n",
+ NonCachedExt->MsgOutBuf[MessageCount-2],
+ MAX_SYNCH_OFFSET
+ ));
+ }
+
+ ScriptDataPtr->SelectDataSCNTL3 =
+ DeviceExtension->WideParms[Srb->TargetId];
+ ScriptDataPtr->SelectDataSXFER =
+ DeviceExtension->SyncParms[Srb->TargetId];
+ WRITE_SIOP_UCHAR (SCNTL3, DeviceExtension->WideParms[Srb->TargetId] );
+ WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] );
+
+ ScriptDataPtr->MsgOutCount = 5;
+
+ return (ISR_CONT_NEG_SCRIPT);
+
+ } // if
+
+ return (ISR_RESTART_SCRIPT);
+
+} // ProcessWideNegotComplete
+
+
+UCHAR
+ProcessWideNotSupported(
+ PHW_DEVICE_EXTENSION DeviceExtension,
+ UCHAR DestId
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine handles unsuccessful wide negotiation. The routine
+ sets the wide parameters to narrow, and sets the appropriate
+ flag.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+ PHW_NONCACHED_EXTENSION NonCachedExt = DeviceExtension->NonCachedExtension;
+
+ DebugPrint((1,
+ "Sym8xx(%1x) WideNotSupp: Wide negotiation failed, ID = %2x\n",
+ DeviceExtension->ScsiBusNumber, DestId));
+
+ //
+ // indicate drive is low technology.
+ //
+ if (DeviceExtension->LuFlags[DestId] & LUFLAGS_WIDE_NEGOT_PEND)
+ {
+ DeviceExtension->LuFlags[DestId] |= LUFLAGS_WIDE_NEGOT_DONE +
+ LUFLAGS_WIDE_NEGOT_FAILED;
+ }
+ else
+ {
+ DeviceExtension->LuFlags[DestId] |= LUFLAGS_NARROW_NEGOT_DONE +
+ LUFLAGS_WIDE_NEGOT_FAILED;
+ }
+
+ //
+ // indicate we are no longer expecting a negotiation reply
+ //
+ DeviceExtension->LuFlags[DestId] &= ~(LUFLAGS_WIDE_NEGOT_PEND +
+ LUFLAGS_NARROW_NEGOT_PEND);
+
+ //
+ // set up for narrow xfer.
+ //
+ DeviceExtension->WideParms[DestId] &= ~ENABLE_WIDE;
+
+ //
+ // check on asynch negotiations
+ //
+ if (!(DeviceExtension->LuFlags[DestId] & LUFLAGS_ASYNC_NEGOT_DONE))
+ {
+ //
+ // fill in the parameters for SDTR extended message
+ //
+ NonCachedExt->MsgOutBuf[0] = SCSIMESS_EXTENDED_MESSAGE;
+ NonCachedExt->MsgOutBuf[1] = 3; // 3 message bytes
+ NonCachedExt->MsgOutBuf[2] = SCSIMESS_SYNCHRONOUS_DATA_REQ;
+
+ //
+ // Clear any synchronous negotiations
+ //
+ DeviceExtension->SyncParms[DestId]=ASYNCHRONOUS_MODE_PARAMS;
+
+ //
+ // indicate async negotiation is not done
+ //
+ DeviceExtension->LuFlags[DestId] |= LUFLAGS_ASYNC_NEGOT_PEND;
+ DeviceExtension->LuFlags[DestId] &= ~LUFLAGS_SYNC_NEGOT_PEND;
+
+ //
+ // Initialize sync period to 0
+ //
+ NonCachedExt->MsgOutBuf[3] = 0;
+
+ //
+ // Initialize sync offset to 0
+ //
+ NonCachedExt->MsgOutBuf[4] = 0;
+
+ DebugPrint((1,
+ "Sym8xx(%2x): AsynchronousNegotiation Requested - Target: %x\n",
+ DeviceExtension->SIOPRegisterBase, DestId));
+
+ DebugPrint((1, " Period: %x Offset: %x\n",
+ NonCachedExt->MsgOutBuf[3],
+ MAX_SYNCH_OFFSET
+ ));
+
+ ScriptDataPtr->MsgOutCount = 5;
+
+ return (ISR_CONT_NEG_SCRIPT);
+
+ } // if
+
+ return (ISR_RESTART_SCRIPT);
+
+} // ProcessWideNotSupported
+
+
+UCHAR
+ProcessUnexpectedDisconnect(
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine processes unexpected disconnects. An unexpected disconnect
+ is defined as a disconnect occurring before a disconnect message is
+ received.
+
+Arguments:
+
+ DeviceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension;
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+
+ /*
+ * if wide negotiation is pending on this device, mark the
+ * device as NOT wide capable.
+ */
+
+ if ((DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND) ||
+ (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_NARROW_NEGOT_PEND))
+ {
+ (void) ProcessWideNotSupported(DeviceExtension, Srb->TargetId);
+ }
+
+ /*
+ * Ditto for sync...
+ */
+
+ if ( DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_SYNC_NEGOT_PEND )
+ {
+ (void) ProcessSynchNotSupported(DeviceExtension);
+ }
+
+ //
+ // indicate unexpected disconnect occurred.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+
+ //
+ // indicate this request is no longer active.
+ //
+
+ DeviceExtension->ActiveRequest = NULL;
+
+ //
+ // This delay added due to issues found with older Quantum drives which
+ // went BUS FREE after a MSG Reject. Seems on faster machines (>100Mhz)
+ // we would hit them again too quickly and they would mess up. This delay
+ // seems to have corrected the problem.
+ //
+
+ ScsiPortStallExecution( 999 );
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) )
+ {
+ LuExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+
+ LuExtension->UntaggedRequest = NULL;
+ }
+
+ //
+ // call back the request.
+ //
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ //
+ // tell ISR to start next request
+ //
+
+ return( ISR_START_NEXT_REQUEST);
+
+} // ProcessUnexpectedDisconnected
+
+
+VOID
+ResetPeripheral(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/******************************************************************************
+
+Routine Description:
+
+ This routine resets a specified SCSI peripheral.
+
+ Note that since the 53C8xx generates a bus reset interrupt when we reset
+ the bus, we set a flag indicating we have reset the bus so the reset
+ postprocess routine will not be called twice.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+ //
+ // store away SRB.
+ //
+
+ DeviceExtension->NextSrbToProcess = Srb;
+
+ //
+ // If we have an active request, just return. Since we saved away the
+ // SRB we just received, it will be started later.
+ //
+
+ if ( DeviceExtension->ActiveRequest != NULL )
+ {
+ return;
+ }
+
+ //
+ // CHC - 53c810 pass 1 chip bug workaround.
+ //
+ // To get around the parity error on the PCI bus, we will set
+ // the bit to abort the script here but let the ISR routine do
+ // the actual processing. As long as we don't poll the ISTAT
+ // register while script is running, we should be ok.
+ //
+
+ if ( DeviceExtension->DeviceFlags & DFLAGS_SCRIPT_RUNNING )
+ {
+ WRITE_SIOP_UCHAR( ISTAT, ISTAT_SIGP );
+ return;
+ }
+
+ //
+ // Make this request active.
+ //
+
+ DeviceExtension->ActiveRequest = Srb;
+ DeviceExtension->TargetId = Srb->TargetId;
+
+ //
+ // indicate no pending request.
+ //
+
+ DeviceExtension->NextSrbToProcess = NULL;
+
+ //
+ // set up target ID in select script buffer.
+ //
+
+ ScriptDataPtr->SelectDataID = Srb->TargetId;
+
+ //
+ // clear the tagged command queueing flag
+ //
+
+ DeviceExtension->DeviceFlags &= ~DFLAGS_TAGGED_SELECT;
+
+ //
+ // indicate message length
+ //
+
+ ScriptDataPtr->MsgOutCount = 1;
+
+ //
+ // Attempt to start the request.
+ //
+
+ StartSIOP( DeviceExtension, DeviceExtension->ResetDevScriptPhys );
+
+} // ResetPeripheral
+
+
+VOID
+ResetSCSIBus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/******************************************************************************
+
+Routine Description:
+
+ This routine resets the SCSI bus and calls the bus reset postprocess
+ routine.
+
+ Note that since the 53C8xx generates a bus reset interrupt when we reset
+ the bus, we set a flag indicating we have reset the bus so the reset
+ postprocess routine will not be called twice.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK Srb = DeviceExtension->ActiveRequest;
+ ULONG tmpflg = 0x00;
+
+ DebugPrint((1, "Sym8xx(%2x) ResetSCSIBus\n",
+ DeviceExtension->SIOPRegisterBase));
+
+ //
+ // set the bus reset line high
+ //
+
+ WRITE_SIOP_UCHAR (SCNTL1, (UCHAR) ( READ_SIOP_UCHAR(SCNTL1) |
+ (UCHAR) SCNTL1_RESET_SCSI_BUS));
+
+ //
+ // Delay the minimum assertion time for a SCSI bus reset to make sure a
+ // valid reset signal is sent.
+ //
+
+ ScsiPortStallExecution( RESET_STALL_TIME);
+
+ //
+ // set the bus reset line low to end the bus reset event
+ //
+
+ WRITE_SIOP_UCHAR(SCNTL1, (UCHAR) ( READ_SIOP_UCHAR(SCNTL1) &
+ (UCHAR) ~SCNTL1_RESET_SCSI_BUS));
+
+ //
+ // if wide negotiation is pending on this device, mark the
+ // device as NOT wide capable.
+ //
+
+ //
+ // make sure we have an active request and were not just called
+ // directly by the OS to reset the bus
+ //
+
+ if (Srb)
+ {
+ if (DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_PEND)
+ {
+ tmpflg = LUFLAGS_WIDE_NEGOT_PEND;
+ }
+ }
+
+ //
+ // abort any pending or started requests.
+ //
+
+ BusResetPostProcess(DeviceExtension);
+
+ //
+ // indicate that we reset the bus locally.
+ //
+
+ DeviceExtension->DeviceFlags |= DFLAGS_BUS_RESET;
+
+ if (tmpflg)
+ {
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_PEND;
+ ProcessWideNotSupported (DeviceExtension, Srb->TargetId);
+ }
+
+} // ResetSCSIBus
+
+VOID
+ScatterGatherScriptSetup(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSRB_EXTENSION SrbExtension
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine copies physical break pointers and transfer lengths to the
+ appropriate locations in the SCSI script data buffer and sets the SCRATCH0
+ register to the # of S/G elements to process.
+
+Arguments:
+
+ DeviceExtension - Supplies the device Extension for the SCSI bus adapter.
+
+ SrbExtension - Supplies the SRB Extension for the request to be setup
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ ULONG ElementLength;
+ PVOID VirtualBufferPointer;
+ UCHAR PhysBreakCount = 0;
+ ULONG RemainingDataCount;
+ SCRIPTSG MoveBuffer[ MAX_SG_ELEMENTS];
+
+ //
+ // Added for script patching.
+ //
+
+ PULONG dataInPatches = &DeviceExtension->dataInPatches[0];
+ PULONG dataOutPatches = &DeviceExtension->dataOutPatches[0];
+
+ PULONG patchInArea;
+ PULONG patchOutArea;
+
+ //
+ // set pointer to offset into xfer buffer
+ //
+
+ VirtualBufferPointer = (PVOID) SrbExtension->SavedDataPointer;
+
+ //
+ // get length of data remaining to xfer
+ //
+
+ RemainingDataCount = SrbExtension->SavedDataLength;
+
+ do
+ {
+ MoveBuffer[ PhysBreakCount].SGBufferPtr =
+ ScsiPortConvertPhysicalAddressToUlong (
+ ScsiPortGetPhysicalAddress ( DeviceExtension,
+ DeviceExtension->ActiveRequest,
+ VirtualBufferPointer,
+ &ElementLength
+ ));
+
+ if ( ElementLength > RemainingDataCount)
+ {
+ ElementLength = RemainingDataCount;
+ }
+
+ MoveBuffer[ PhysBreakCount++].SGByteCount = ElementLength;
+
+ (ULONG) VirtualBufferPointer += ElementLength;
+ RemainingDataCount -= ElementLength;
+
+ } while ( RemainingDataCount != 0);
+
+ //
+ // Indicate that we have not yet transfered any data.
+ //
+
+ SrbExtension->DataTransferred = 0L;
+
+ ScsiPortMoveMemory(
+ DeviceExtension->NonCachedExtension->ScriptData.SGBufferArray +
+ (MAX_SG_ELEMENTS - PhysBreakCount),
+ MoveBuffer,
+ PhysBreakCount * SCRIPT_INS_SIZE
+ );
+
+ WRITE_SIOP_UCHAR( SCRATCH[0], PhysBreakCount);
+
+ SrbExtension->PhysBreakCount = PhysBreakCount;
+
+ DebugPrint((3,
+ "Sym8xx(%2x) Sym8xxScatterGather: Phys breaks = %2x, total size = %8x \n",
+ DeviceExtension->SIOPRegisterBase,
+ PhysBreakCount,
+ *((PULONG) &SrbExtension->SavedDataLength)
+ ));
+
+ //
+ // Set up pointers to the patch area, which is 4 bytes (1 long word)
+ // past the jump instructions for data in and data out.
+ //
+
+ patchInArea = (PULONG)DeviceExtension->DataInJumpVirt;
+ patchInArea += 1;
+
+ patchOutArea = (PULONG)DeviceExtension->DataOutJumpVirt;
+ patchOutArea += 1;
+
+ //
+ // Move the pre-determined jump amount into these patch areas.
+ //
+
+ if (!(DeviceExtension->hbaCapability & HBA_CAPABILITY_SCRIPT_RAM))
+ {
+ //
+ // Script in system memory, patch it.
+ //
+
+ (ULONG)*patchInArea = dataInPatches[ PhysBreakCount ];
+ (ULONG)*patchOutArea = dataOutPatches[ PhysBreakCount ];
+ }
+ else
+ {
+ //
+ // Script in onboard RAM, patch it.
+ //
+
+ ScsiPortWriteRegisterUlong(patchInArea, dataInPatches[PhysBreakCount]);
+ ScsiPortWriteRegisterUlong(patchOutArea, dataOutPatches[PhysBreakCount]);
+ }
+
+} // ScatterGatherScriptSetup
+
+
+VOID
+SetupLuFlags(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR ResetFlag
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine clears the LU flags which hold information such as whether
+ a peripheral device supports synchronous.
+
+Arguments:
+
+ PHW_DEVICE_EXTENSION DeviceExtension
+ ResetFlag Specifies a bus reset has just been done
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension;
+
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR max_targets;
+
+ //
+ // Indicate that no negotiations have been done, and there are no
+ // outstanding tagged requests.
+ //
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)
+ {
+ max_targets = SYM_MAX_TARGETS;
+ }
+ else
+ {
+ max_targets = SYM_NARROW_MAX_TARGETS;
+ }
+
+ for (TargetId = 0; TargetId < max_targets; TargetId++)
+ {
+ DeviceExtension->LuFlags[TargetId] &= ~LUFLAGS_SYNC_NEGOT_DONE;
+ DeviceExtension->LuFlags[TargetId] &= ~LUFLAGS_WIDE_NEGOT_DONE;
+
+ if (!(ResetFlag))
+ {
+ DeviceExtension->LuFlags[TargetId] &= ~LUFLAGS_ASYNC_NEGOT_DONE;
+ DeviceExtension->LuFlags[TargetId] &= ~LUFLAGS_NARROW_NEGOT_DONE;
+ }
+ else
+ {
+ DeviceExtension->LuFlags[TargetId] |= LUFLAGS_ASYNC_NEGOT_DONE;
+ DeviceExtension->LuFlags[TargetId] |= LUFLAGS_NARROW_NEGOT_DONE;
+ if (DeviceExtension->LuFlags[TargetId] & LUFLAGS_WIDE_NEGOT_FAILED)
+ {
+ DeviceExtension->LuFlags[TargetId] |= LUFLAGS_WIDE_NEGOT_DONE;
+ }
+ }
+
+ // set failed bit as a check to see when we actually get to go sync.
+ // needed as a check so we only look at sstat1_orf when we are sync
+ DeviceExtension->LuFlags[TargetId] |= LUFLAGS_SYNC_NEGOT_FAILED;
+
+ for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
+ {
+ LuExtension = ScsiPortGetLogicalUnit(
+ DeviceExtension,
+ DeviceExtension->BusNumber,
+ TargetId,
+ Lun
+ );
+
+ if (LuExtension != NULL)
+ {
+ LuExtension->UntaggedRequest = NULL;
+ }
+ } // for
+ } // for
+
+} // SetupLuFlags
+
+
+VOID
+StartSCSIRequest(
+ PSCSI_REQUEST_BLOCK Srb,
+ PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/******************************************************************************
+
+Routine Description:
+
+ This procedure starts a request if possible, and also
+ determines if synchronous negotiation is necessary.
+
+Arguments:
+
+ Srb - Pointer to the request to be started.
+
+ DeviceExtension - Pointer to the device extension for this adapter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG VirtualBufferLength;
+ PHW_NONCACHED_EXTENSION NonCachedExt = DeviceExtension->NonCachedExtension;
+ PSRB_EXTENSION SrbExtension = Srb->SrbExtension;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension;
+ PSCRIPTDATASTRUCT ScriptDataPtr =
+ &DeviceExtension->NonCachedExtension->ScriptData;
+ ULONG MessageCount;
+
+ //
+ // store away SRB.
+ //
+
+ DeviceExtension->NextSrbToProcess = Srb;
+
+ //
+ // If we have an active request, just return. Since we saved away the
+ // SRB we just received, it will be started later.
+ //
+
+ if (DeviceExtension->ActiveRequest != NULL)
+ {
+ return;
+ }
+
+ //
+ // CHC - 53c810 pass 1 chip bug workaround.
+ //
+ // To get around the parity error on the PCI bus, we will set
+ // the bit to abort the script here but let the ISR routine do
+ // the actual processing. As long as we don't poll the ISTAT
+ // register while script is running, we should be ok.
+ //
+
+ if (DeviceExtension->DeviceFlags & DFLAGS_SCRIPT_RUNNING)
+ {
+ WRITE_SIOP_UCHAR(ISTAT, ISTAT_SIGP);
+ return;
+ }
+
+ //
+ // Make this request active.
+ //
+
+ DeviceExtension->ActiveRequest = Srb;
+ DeviceExtension->TargetId = Srb->TargetId;
+ DeviceExtension->LUN = Srb->Lun;
+
+ //
+ // Initialize the data pointer and transfer length for this request.
+ //
+
+ SrbExtension->SavedDataPointer = (ULONG) Srb->DataBuffer;
+ SrbExtension->SavedDataLength = Srb->DataTransferLength;
+ SrbExtension->DataTransferred = 0L;
+
+ //
+ // indicate no pending request.
+ //
+
+ DeviceExtension->NextSrbToProcess = NULL;
+
+ //
+ // If there is data to transfer set up scatter/gather.
+ //
+
+ if ( Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
+ {
+ ScatterGatherScriptSetup( DeviceExtension,
+ DeviceExtension->ActiveRequest->SrbExtension
+ );
+ }
+
+ //
+ // set CDB length and physical address in buffer.
+ //
+
+ ScriptDataPtr->CDBDataCount = (ULONG) Srb->CdbLength;
+ ScsiPortMoveMemory(Srb->SrbExtension, Srb->Cdb, Srb->CdbLength);
+ ScriptDataPtr->CDBDataBuff =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress( DeviceExtension,
+ NULL,
+ (PVOID) Srb->SrbExtension,
+ &VirtualBufferLength
+ ));
+
+ //
+ // Set up the identify message. If disconnect is disabled reset DSCPRV.
+ //
+
+ DeviceExtension->NonCachedExtension->MsgOutBuf[0] =
+ (UCHAR) SCSIMESS_IDENTIFY_WITH_DISCON + Srb->Lun;
+
+ if ( Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
+ {
+ DeviceExtension->NonCachedExtension->MsgOutBuf[0] &=
+ ~SCSIMESS_IDENTIFY_DISC_PRIV_MASK;
+ }
+
+ //
+ // indicate length of identify message.
+ //
+
+ MessageCount = 1;
+
+ //
+ // set up target ID in select script buffer.
+ //
+
+ ScriptDataPtr->SelectDataID = Srb->TargetId;
+
+ DebugPrint((3, "Sym8xx(%2x) StartSCSIRequest: Starting request for Path=%2x Id=%2x Lun=%2x \n",
+ DeviceExtension->SIOPRegisterBase,
+ DeviceExtension->ScsiBusNumber,
+ Srb->TargetId,
+ Srb->Lun ));
+
+
+ if (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE)
+ {
+ // before passing on this tagged cmd, make sure there is no
+ // Contingent Allegence Condition pending for this ITL nexus,
+ // if there is abort this SRB and have the class driver retry it
+ // after the CA condition is cleared.
+
+ if (DeviceExtension->CA_Condition[Srb->TargetId][Srb->Lun])
+ {
+ DeviceExtension->ActiveRequest = NULL;
+ Srb->SrbStatus = SCSISTAT_CHECK_CONDITION;
+
+ Srb->ScsiStatus = SCSISTAT_BUSY;
+
+ ScsiPortNotification( RequestComplete,
+ DeviceExtension,
+ Srb);
+
+ if ( !(DeviceExtension->DeviceFlags & DFLAGS_WORK_REQUESTED))
+ {
+ DeviceExtension->DeviceFlags |= DFLAGS_WORK_REQUESTED;
+
+ ScsiPortNotification( NextRequest,
+ DeviceExtension,
+ NULL
+ );
+ }
+
+ return;
+ }
+
+ //
+ // The queue tag message is two bytes the first is the queue action
+ // and the second is the queue tag.
+ //
+ NonCachedExt->MsgOutBuf[1] = Srb->QueueAction;
+ NonCachedExt->MsgOutBuf[2] = Srb->QueueTag;
+ MessageCount = 3;
+
+ //
+ // Set Tagged select command.
+ //
+ DeviceExtension->DeviceFlags |= DFLAGS_TAGGED_SELECT;
+
+ DebugPrint((3, "Sym8xx(%2x) Tagged I/O request \n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+ } // if
+
+ else
+ {
+ // blindly clear the Contingent Allegience blocker on non-tagged cmds
+ DeviceExtension->CA_Condition[Srb->TargetId][Srb->Lun] = 0;
+
+ // Clear Tagged select command.
+ //
+ DeviceExtension->DeviceFlags &= ~DFLAGS_TAGGED_SELECT;
+ LuExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+
+ LuExtension->UntaggedRequest = Srb;
+
+ DebugPrint((3, "Sym8xx(%2x) Untagged I/O request \n",
+ DeviceExtension->SIOPRegisterBase
+ ));
+ } // else
+
+ DebugPrint((3, " CDB = %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x \n",
+ Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3],
+ Srb->Cdb[4], Srb->Cdb[5], Srb->Cdb[6], Srb->Cdb[7],
+ Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11]
+ ));
+
+ //*************************************************************************
+ //
+ // Decide if wide negotiations are needed (either 8 or 16 bit)
+ //
+ //*************************************************************************
+
+ //
+ // OK, the following mess does this:
+ // 1st half of if - checks to see if wide neg. NOT already done AND the OS
+ // is NOT restricting SYNCH transfers AND the chip is
+ // capable of wide transfers.(will do wide negotiations)
+ //
+ // 2nd half of if (after the ||) - checks to see if narrow neg. NOT
+ // already done AND the OS IS restricting SYNCH transfers
+ // and the chip is capable of wide transfers. (will do
+ // narrow negotiations)
+
+ if ((!(DeviceExtension->LuFlags[Srb->TargetId] & LUFLAGS_WIDE_NEGOT_DONE)&&
+ !( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) &&
+ (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)) || // OR...
+
+ (!(DeviceExtension->LuFlags[Srb->TargetId]&LUFLAGS_NARROW_NEGOT_DONE)&&
+ (Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) &&
+ (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)))
+ {
+
+ //
+ // fill in the parameters for SDTR extended message
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_EXTENDED_MESSAGE;
+ NonCachedExt->MsgOutBuf[MessageCount++] = 2; // 2 message bytes
+ NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_WIDE_DATA_REQUEST;
+
+ if (!( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER))
+ {
+ // Will be doing WIDE negotiations...
+ //
+ //
+ // Clear any synchronous negotiations
+ //
+ DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS;
+ ScriptDataPtr->SelectDataSXFER =
+ DeviceExtension->SyncParms[Srb->TargetId];
+
+ WRITE_SIOP_UCHAR (SXFER,DeviceExtension->SyncParms[Srb->TargetId]);
+ DeviceExtension->WideParms[Srb->TargetId] |= ENABLE_WIDE;
+
+ //
+ // indicate wide negotiation is not done
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_WIDE_NEGOT_DONE;
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_WIDE_NEGOT_PEND;
+
+ //
+ // Initialize transfer wide width to maximum supported
+ // Width = 16 bits
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = 1;
+
+ DebugPrint((1, "Sym8xx(%2x): WideNegotiation Requested - Target: %x\n",
+ DeviceExtension->SIOPRegisterBase,
+ Srb->TargetId
+ ));
+ }
+
+ else
+ {
+ // Will be doing NARROW negotiations...
+ //
+ DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS;
+ ScriptDataPtr->SelectDataSXFER =
+ DeviceExtension->SyncParms[Srb->TargetId];
+
+ WRITE_SIOP_UCHAR (SXFER,DeviceExtension->SyncParms[Srb->TargetId]);
+ DeviceExtension->WideParms[Srb->TargetId] &= ~ENABLE_WIDE;
+
+ //
+ // indicate narrow negotiation is not done
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_NARROW_NEGOT_DONE;
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_NARROW_NEGOT_PEND;
+
+ //
+ // Set for asynchronous negotiations
+ //
+ DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS;
+ ScriptDataPtr->SelectDataSXFER =
+ DeviceExtension->SyncParms[Srb->TargetId];
+ WRITE_SIOP_UCHAR (SXFER,DeviceExtension->SyncParms[Srb->TargetId]);
+
+ //
+ // Initialize transfer width to minimum supported
+ // Width = 8 bits
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = 0;
+
+ DebugPrint((1, "Sym8xx(%2x): Narrow Neg. Requested - Target: %x\n",
+ DeviceExtension->SIOPRegisterBase,
+ Srb->TargetId
+ ));
+ }
+
+ } // if
+
+ // check on sync negotiations
+
+ else if (!(DeviceExtension->LuFlags[Srb->TargetId] &
+ LUFLAGS_SYNC_NEGOT_DONE) &&
+ (!( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER )))
+ {
+ //
+ // Clear any synchronous negotiations
+ //
+ DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS;
+
+ //
+ // indicate sync negotiation is not done
+ //
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_SYNC_NEGOT_DONE;
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_SYNC_NEGOT_PEND;
+
+ //
+ // fill in the parameters for SDTR extended message
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_EXTENDED_MESSAGE;
+ NonCachedExt->MsgOutBuf[MessageCount++] = 3; // 3 message bytes
+ NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_SYNCHRONOUS_DATA_REQ;
+
+ //
+ // Initialize sync period to maximum supported
+ //
+ // Period = ((1000 / (ClockSpeed / 1)) * (4 + xferp)) / 4
+ // where xferp = 0
+ // modified for FAST20 devices, set msg byte to 0x0C since divide
+ // of 1000 by 80 equals 12.5
+ //
+ if ((DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20) &&
+ (DeviceExtension->hbaCapability & HBA_CAPABILITY_REGISTRY_FAST20))
+ {
+ NonCachedExt->MsgOutBuf[MessageCount++] = 12;
+ }
+ else
+ {
+ NonCachedExt->MsgOutBuf[MessageCount++] = 25;
+ }
+
+ //
+ // Initialize sync offset to maximum
+ //
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_SYNC_16)
+ {
+ NonCachedExt->MsgOutBuf[MessageCount++] = MAX_875_SYNCH_OFFSET;
+ }
+ else
+ {
+ NonCachedExt->MsgOutBuf[MessageCount++] = MAX_SYNCH_OFFSET;
+ }
+
+ DebugPrint((1,
+ "Sym8xx(%2x): SynchronousNegotiation Requested - Target: %x\n",
+ DeviceExtension->SIOPRegisterBase,
+ (DeviceExtension->ActiveRequest)->TargetId
+ ));
+
+ DebugPrint((1, " Period: %x Offset: %x\n",
+ NonCachedExt->MsgOutBuf[MessageCount-2],
+ MAX_SYNCH_OFFSET
+ ));
+
+ } // else if
+
+ //
+ // Let's just force async negotiation if need be to make sure device is
+ // in a known state.
+ //
+
+ else if (!(DeviceExtension->LuFlags[Srb->TargetId] &
+ LUFLAGS_ASYNC_NEGOT_DONE) &&
+ (( Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER )))
+ {
+ //
+ // Set the knowns...
+ //
+ DeviceExtension->SyncParms[Srb->TargetId]=ASYNCHRONOUS_MODE_PARAMS;
+ DeviceExtension->LuFlags[Srb->TargetId] &= ~LUFLAGS_ASYNC_NEGOT_DONE;
+ DeviceExtension->LuFlags[Srb->TargetId] |= LUFLAGS_ASYNC_NEGOT_PEND;
+
+ //
+ // fill in the parameters for SDTR extended message
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_EXTENDED_MESSAGE;
+ NonCachedExt->MsgOutBuf[MessageCount++] = 3; // 3 message bytes
+ NonCachedExt->MsgOutBuf[MessageCount++] = SCSIMESS_SYNCHRONOUS_DATA_REQ;
+
+ //
+ // sync period to 0
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = 0;
+
+ //
+ // Initialize sync offset to 0
+ //
+ NonCachedExt->MsgOutBuf[MessageCount++] = 0;
+
+ DebugPrint((1,
+ "Sym8xx(%2x): AsynchronousNegotiation Requested - Target: %x\n",
+ DeviceExtension->SIOPRegisterBase,
+ (DeviceExtension->ActiveRequest)->TargetId
+ ));
+
+ } // else if
+
+ ScriptDataPtr->SelectDataSCNTL3 = DeviceExtension->WideParms[Srb->TargetId];
+ ScriptDataPtr->SelectDataSXFER = DeviceExtension->SyncParms[Srb->TargetId];
+ WRITE_SIOP_UCHAR (SCNTL3, DeviceExtension->WideParms[Srb->TargetId] );
+ WRITE_SIOP_UCHAR (SXFER, DeviceExtension->SyncParms[Srb->TargetId] );
+
+ //
+ // indicate message length
+ //
+ ScriptDataPtr->MsgOutCount = MessageCount;
+
+ //
+ // Attempt to start the request.
+ //
+ StartSIOP( DeviceExtension, DeviceExtension->CommandScriptPhys);
+
+} // StartSCSIRequest
+
+
+VOID
+StartSIOP(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG ScriptPhysAddr
+ )
+/******************************************************************************
+
+Routine Description:
+
+ This routine indicates that scripts are running and starts the script
+ instruction whose physical address is passed to it.
+
+Arguments:
+
+ DeviceExtension - Supplies the device Extension for the SCSI bus adapter.
+ ScriptPhysAddr - Supplies the address of the script routine to start.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // indicate scripts are running
+ //
+ DeviceExtension->DeviceFlags |= DFLAGS_SCRIPT_RUNNING;
+
+ //
+ // write script buffer start address to DSA register.
+ //
+ WRITE_SIOP_ULONG( DSA, DeviceExtension->DSAAddress);
+
+ //
+ // write script instruction start address to DSP register.
+ //
+ WRITE_SIOP_ULONG( DSP, ScriptPhysAddr);
+
+} // StartSIOP
+
+
+// start of NVRAM useage code
+// NVRAM_CODE
+/* BOOLEAN NvmDetect( PHW_DEVICE_EXTENSION DeviceExtension )
+ *
+ * Input:
+ *
+ * PHW_DEVICE_EXTENSION DeviceExtension - This contains the I/O port
+ * address of the adapter to test.
+ *
+ * Output:
+ *
+ * NONE
+ *
+ * Returns:
+ *
+ * BOOLEAN - SUCCESS if NVM was detected
+ * FAILURE if NVM was not detected
+ *
+ * Purpose:
+ *
+ * This routine is used to test the adapter to see if NVM is installed on
+ * the GPIO pins of the 8xx chip.
+ */
+
+
+BOOLEAN NvmDetect( PHW_DEVICE_EXTENSION DeviceExtension )
+{
+ UINT flag;
+ UINT retries;
+
+ /* Turn the data line into an output and the clock line into an output,
+ * then send a stop signal to the I2C chip to reset it to a known state.
+ */
+
+ WRITE_SIOP_UCHAR( GPCNTL,
+ (UCHAR)(READ_SIOP_UCHAR(GPCNTL) & (~(DATA_MASK | CLOCK_MASK ))) );
+ NvmSendStop(DeviceExtension); /* Reset the I2C chip */
+
+ /* Attempt to issue a read for retries number of times. If the ACK is not
+ * received, then return that the I2C chip is not present or not
+ * functional.
+ */
+
+ flag = 1;
+ retries = 100;
+
+ do
+ {
+ NvmSendStart(DeviceExtension);
+ /* Send a dummy write 1010 | A2 A1 A0 | Write */
+ } while (--retries &&
+ (NvmSendData(DeviceExtension, 0xA0 | 0x00 | 0x00) != 0x00) );
+
+ if (retries != 0)
+ {
+ flag = NvmSendData( DeviceExtension, 0x00 ); /* Address zero */
+ NvmSendStart(DeviceExtension);
+ /* 1010 | A2 A1 A0 | Read */
+ flag += NvmSendData( DeviceExtension, 0xA0 | 0x00 | 0x01 ); /* read */
+ (void)NvmReadData(DeviceExtension);
+ NvmSendNoAck(DeviceExtension); /* Also sends stop */
+ }
+
+ /* Turn the clock back into an input signal so that the I2C won't
+ * recognize our LED line (same as the data line) toggling. Then turn the
+ * data line to an output signal for the drive activity LED.
+ */
+
+ WRITE_SIOP_UCHAR( GPCNTL,
+ (UCHAR)((READ_SIOP_UCHAR( GPCNTL ) & (~DATA_MASK)) | CLOCK_MASK ));
+
+ return( (flag == 0) ? SUCCESS : FAILURE );
+}
+
+
+/******************************************************************************
+ *
+ * void NvmSendStop( PHW_DEVICE_EXTENSION )
+ *
+ * Input:
+ *
+ * DATA line is an output
+ * CLOCK line is an output
+ *
+ * Output:
+ *
+ * An I2C 'stop' signal is sent.
+ * DATA line is asserted
+ * CLOCK line is deasserted
+ *
+ * Returns
+ *
+ * NONE
+ *
+ * Purpose:
+ *
+ * This routine is used to send an I2C stop signal.
+ */
+
+void NvmSendStop( PHW_DEVICE_EXTENSION DeviceExtension )
+{
+ RESET_DATA();
+ ScsiPortStallExecution(10L);
+ SET_CLOCK();
+ ScsiPortStallExecution(10L);
+ SET_DATA();
+ ScsiPortStallExecution(10L);
+ RESET_CLOCK();
+}
+
+
+/******************************************************************************
+ *
+ * void NvmSendStart( PHW_DEVICE_EXTENSION )
+ *
+ * Input:
+ *
+ * DATA line is an output
+ * CLOCK line is an output
+ *
+ * Output:
+ *
+ * An I2C 'start' signal is sent.
+ * DATA line is deasserted
+ * CLOCK line is deasserted
+ *
+ * Returns
+ *
+ * NONE
+ *
+ * Purpose:
+ *
+ * This routine is used to send an I2C start signal.
+ */
+
+void NvmSendStart( PHW_DEVICE_EXTENSION DeviceExtension )
+{
+ SET_DATA();
+ ScsiPortStallExecution(10L);
+ SET_CLOCK();
+ ScsiPortStallExecution(10L);
+ RESET_DATA();
+ ScsiPortStallExecution(10L);
+ RESET_CLOCK();
+}
+
+
+/******************************************************************************
+ *
+ * UINT NvmSendData( PHW_DEVICE_EXTENSION, UINT Value )
+ *
+ * Input:
+ *
+ * UINT Value - This is the data value to send (lower 8 bits only)
+ *
+ * ???
+ *
+ * Output:
+ *
+ * ???
+ *
+ * Returns
+ *
+ * UINT - == 0 if no acknowledge signal is present.
+ * != 0 if an acknowledge signal is present.
+ *
+ * Purpose:
+ *
+ * This routine is used to send a single data byte to the I2C interface.
+ */
+
+UINT NvmSendData( PHW_DEVICE_EXTENSION DeviceExtension, UINT Value )
+{
+ UINT i;
+ UINT8 bit;
+
+ for (i = 0, bit = 0x80; i < 8; i++, bit >>= 1)
+ {
+ if (Value & bit)
+ {
+ SET_DATA();
+ }
+ else
+ {
+ RESET_DATA();
+ }
+
+ ScsiPortStallExecution(10L);
+ SET_CLOCK();
+ ScsiPortStallExecution(10L);
+ RESET_CLOCK();
+ }
+ return( NvmReceiveAck(DeviceExtension) );
+}
+
+
+/******************************************************************************
+ *
+ * UINT8 NvmReadData( PHW_DEVICE_EXTENSION )
+ *
+ * Input:
+ *
+ * ???
+ *
+ * Output:
+ *
+ * ???
+ *
+ * Returns
+ *
+ * UINT8 - The data byte read from the I2C interface.
+ *
+ * Purpose:
+ *
+ * This routine is used to read a single data byte from the I2C interface.
+ */
+
+UINT8 NvmReadData( PHW_DEVICE_EXTENSION DeviceExtension )
+{
+ UINT i;
+ UINT8 value;
+
+ value = 0;
+ DATA_INPUT();
+ for (i = 0; i < 8; i++)
+ {
+ ScsiPortStallExecution(10L);
+ SET_CLOCK();
+ ScsiPortStallExecution(10L);
+
+ /* Read in the next bit and shift it into place.
+ *
+ * NOTE: The following code only works properly because we know that
+ * DATA_MASK is bit 0. If that ever changes, then this code
+ * must also change.
+ */
+
+ value = (UINT8)(value << 1) | (READ_SIOP_UCHAR( GPREG ) & DATA_MASK);
+ RESET_CLOCK();
+ }
+ DATA_OUTPUT();
+ return( value );
+}
+
+
+/******************************************************************************
+ *
+ * void NvmSendAck( PHW_DEVICE_EXTENSION )
+ *
+ * Input:
+ *
+ * ???
+ *
+ * Output:
+ *
+ * ???
+ *
+ * Returns
+ *
+ * NONE
+ *
+ * Purpose:
+ *
+ * This routine is used to send an acknowledge signal to the I2C part.
+ */
+
+void NvmSendAck( PHW_DEVICE_EXTENSION DeviceExtension )
+{
+ ScsiPortStallExecution(10L);
+ RESET_DATA();
+ SET_CLOCK();
+ ScsiPortStallExecution(10L);
+ RESET_CLOCK();
+ RESET_DATA();
+}
+
+
+/******************************************************************************
+ *
+ * UINT NvmReceiveAck( PHW_DEVICE_EXTENSION )
+ *
+ * Input:
+ *
+ * ???
+ *
+ * Output:
+ *
+ * ???
+ *
+ * Returns
+ *
+ * UINT - == 0 if no acknowledge signal is present.
+ * != 0 if an acknowledge signal is present.
+ *
+ * Purpose:
+ *
+ * This routine is used to check for an acknowledge signal from the I2C
+ * part.
+ */
+
+UINT NvmReceiveAck( PHW_DEVICE_EXTENSION DeviceExtension )
+{
+ UINT status;
+
+ DATA_INPUT();
+ ScsiPortStallExecution(10L);
+ SET_CLOCK();
+ status = READ_SIOP_UCHAR( GPREG ) & DATA_MASK;
+ ScsiPortStallExecution(10L);
+ RESET_CLOCK();
+ DATA_OUTPUT();
+ return( status );
+}
+
+
+/******************************************************************************
+ *
+ * void NvmSendNoAck( PHW_DEVICE_EXTENSION )
+ *
+ * Input:
+ *
+ * ???
+ *
+ * Output:
+ *
+ * ???
+ *
+ * Returns
+ *
+ * NONE
+ *
+ * Purpose:
+ *
+ * This routine is used to send a 'no acknowledge' signal to the I2C part.
+ */
+
+void NvmSendNoAck( PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ ScsiPortStallExecution(10L);
+ SET_DATA();
+ SET_CLOCK();
+ ScsiPortStallExecution(10L);
+ RESET_CLOCK();
+ RESET_DATA();
+ NvmSendStop(DeviceExtension);
+}
+
+
+/******************************************************************************
+ *
+ * MEMORY_STATUS HwReadNonVolatileMemory(PHW_DEVICE_EXTENSION DeviceExtension,
+ * UINT8 *Buffer, UINT Offset,
+ * UINT Length )
+ *
+ * Input:
+ *
+ * PHW_DEVICE_EXTENSION DevcieExtesnion - The adapter whose NVM is being
+ * read. If the ACF_NO_NON_VOLATILE_MEMORY bit in the Public.ControlFlags
+ * field is set, then it is illegal to call this routine.
+ *
+ * UINT8 far *Buffer - The data buffer in which to store the data being
+ * accessed. This buffer must be Length UINT8 elements in size.
+ *
+ * UINT Offset - The non-volatile memory offset to start reading at.
+ *
+ * UINT Length - The number of UINT8 elements to read from the NVM.
+ *
+ * Output:
+ *
+ * UINT8 far *Buffer - If this routine returns MS_GOOD, then this buffer
+ * is filled with Length UINT8 elements from the NVM.
+ *
+ * Returns:
+ *
+ * MS_GOOD - If the operation completed successfully.
+ *
+ * Another MEMORY_STATUS - If the operation failed for some reason.
+ *
+ * Purpose:
+ *
+ * This routine is used to read the non-volatile memory of a particular
+ * adapter.
+ */
+
+MEMORY_STATUS HwReadNonVolatileMemory( PHW_DEVICE_EXTENSION DeviceExtension,
+ UINT8 *Buffer,
+ UINT Offset, UINT Length )
+{
+ UINT i;
+ UINT nvmAddress;
+
+ /* Make sure that the requested addresses are in range */
+
+ if (Offset + Length > 2048)
+ {
+ return( MS_ILLEGAL_ADDRESS );
+ }
+
+ /* Turn the data line into an output and the clock line into an output,
+ * then send a stop signal to the I2C chip to reset it to a known state.
+ */
+
+ WRITE_SIOP_UCHAR( GPCNTL,
+ (UCHAR)(READ_SIOP_UCHAR( GPCNTL ) & (~(DATA_MASK | CLOCK_MASK ))) );
+ NvmSendStop(DeviceExtension); // Reset the I2C chip
+
+ /* Now read in all of the requested data */
+
+ nvmAddress = 0xA0 | ((Offset & 0x700) >> 7);
+ do
+ {
+ NvmSendStart(DeviceExtension);
+ } while ( NvmSendData( DeviceExtension, nvmAddress | 0x00 ) != 0x00 );
+ // dummy write
+
+ (void)NvmSendData( DeviceExtension, Offset & 0x00FF ); // address
+ NvmSendStart(DeviceExtension);
+ (void)NvmSendData( DeviceExtension, nvmAddress | 0x01 ); // read
+
+ *Buffer = NvmReadData(DeviceExtension);
+ for (i = 1; i < Length; i++)
+ {
+ NvmSendAck(DeviceExtension);
+ Buffer++;
+ *Buffer = NvmReadData(DeviceExtension);
+ }
+
+ NvmSendNoAck(DeviceExtension); // Also sends Stop
+
+ /* Turn the clock back into an input signal so that the I2C won't
+ * recognize our LED line (same as the data line) toggling. Then turn the
+ * data line to an output signal for the drive activity LED.
+ */
+
+ WRITE_SIOP_UCHAR( GPCNTL,
+ (UCHAR)((READ_SIOP_UCHAR( GPCNTL ) & (~DATA_MASK)) | CLOCK_MASK ));
+
+ return( MS_GOOD );
+}
+
+
+/******************************************************************************
+ *
+ * void InvalidateNvmData(PHW_DEVICE_EXTENSION DeviceExtension)
+ *
+ * Input:
+ *
+ * PHW_DEVICE_EXTENSION DevcieExtesnion - The adapter whose NVM
+ * is being used.
+ *
+ * Returns:
+ * None
+ *
+ * Purpose:
+ *
+ * This routine is used to corrupt the nv ram fields so the rest of the
+ * driver will not try to use them.
+ *
+ */
+
+void InvalidateNvmData( PHW_DEVICE_EXTENSION DeviceExtension )
+{
+ DeviceExtension->UsersHBAId = 0x07;
+#ifdef FOR_95
+ DeviceExtension->NumValidScamDevices = 0x00;
+#endif
+}
+
+
+/******************************************************************************
+ *
+ * BOOLEAN RetrieveNvmData( PHW_DEVICE_EXTENSION)
+ *
+ * Input:
+ *
+ * PHW_DEVICE_EXTENSION DevcieExtesnion - The adapter whose NVM
+ * is being read.
+ *
+ *
+ * Returns:
+ *
+ * BOOLEAN
+ * SUCCESS if nvram data is of correct type, correct sumcheck and
+ * correct major\minor numbers, FAILURE if any flaws are found.
+ *
+ *
+ * Purpose:
+ *
+ * This routine is used to read the non-volatile memory of a particular
+ * adapter, verify it as valid and to fill the DeviceExtension fields
+ * housed within the nvram structure.
+ */
+
+ BOOLEAN RetrieveNvmData( PHW_DEVICE_EXTENSION DeviceExtension)
+ {
+ NVM_HEADER NvmHeader;
+ NON_VOLATILE_SETTINGS NvmData;
+ BOOLEAN Status = FAILURE;
+ USHORT maxid = (SYM_NARROW_MAX_TARGETS - 1);
+#ifdef FOR_95
+ ULONG i;
+ UINT8 *ScamBuffer, *NvmBuffer;
+#endif
+
+ if (HwReadNonVolatileMemory(DeviceExtension, (UINT8 *)&NvmHeader,
+ (0 + NVMDATAOFFSET), sizeof(NvmHeader)) == MS_GOOD)
+ {
+ if (NvmHeader.Type == HT_BOOT_ROM)
+ {
+ if (HwReadNonVolatileMemory(DeviceExtension, (UINT8 *)&NvmData,
+ (sizeof(NvmHeader) + NVMDATAOFFSET), sizeof(NvmData)) == MS_GOOD)
+ {
+ if (CalculateCheckSum((UINT8 *)&NvmData, NvmHeader.Length) ==
+ NvmHeader.CheckSum)
+ {
+ if ( (NvmData.VersionMajor == NVS_VERSION_MAJOR) &&
+ (NvmData.VersionMinor == NVS_VERSION_MINOR) )
+ {
+ DeviceExtension->UsersHBAId = NvmData.HostScsiId;
+ if ( DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE )
+ {
+ maxid = (SYM_MAX_TARGETS - 1);
+ }
+
+ if ((DeviceExtension->UsersHBAId > maxid))
+ {
+ DeviceExtension->UsersHBAId = 0x07;
+ }
+
+#ifdef FOR_95
+ DeviceExtension->NumValidScamDevices=NvmData.NumValidScamDevices;
+ ScamBuffer = (UINT8 *)&DeviceExtension->ScamTables[0];
+ NvmBuffer = (UINT8 *)&(NvmData.ScamTable[0]);
+ if (DeviceExtension->NumValidScamDevices > HW_MAX_SCAM_DEVICES)
+ {
+ DeviceExtension->NumValidScamDevices = HW_MAX_SCAM_DEVICES;
+ }
+ for( i=0;
+ i<(DeviceExtension->NumValidScamDevices * sizeof(SCAM_TABLE));
+ i++, ScamBuffer++, NvmBuffer++)
+ {
+ *ScamBuffer = *NvmBuffer;
+ }
+#endif
+ Status = SUCCESS;
+ }
+ }
+ }
+ }
+ }
+ return (Status);
+}
+
+
+/******************************************************************************
+ *
+ * UINT16 CalculateCheckSum( UINT8 * PNvmData, UINT16 Length)
+ *
+ * Input:
+ *
+ * UINT8 * PNvmData Pointer to the NVRAM data just read
+ * UINT16 Length length of the data to calculate sum check against
+ *
+ *
+ * Returns:
+ *
+ * UINT16 returns the 16 bit sum of NVRAM data ( read as all 8 bit members)
+ *
+ *
+ * Purpose:
+ *
+ * This routine is used calculate the sum check of the nvram data
+ * area to insure it is valid before its use.
+ */
+
+UINT16 CalculateCheckSum(UINT8 * PNvmData, UINT16 Length)
+{
+ UINT16 i;
+ UINT16 CheckSum = 0;
+
+ for ( i = 0; i < Length; i++, PNvmData++)
+ {
+ CheckSum += *PNvmData;
+ }
+
+ return ( CheckSum);
+}
+
+
+/*******************************************************
+** **
+** set_8xx_clock **
+** **
+*******************************************************/
+
+UCHAR set_8xx_clock(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR scntl3Value = 0;
+
+ //
+ // set SCSI clock frequency
+ // fast20 assumes 80Mhz clock else 40Mhz
+ //
+
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_FAST20)
+ scntl3Value = 0xD5;
+ else
+ scntl3Value = 0x33;
+
+ WRITE_SIOP_UCHAR( SCNTL3, scntl3Value );
+
+ return (scntl3Value);
+}
+
+
+/*******************************************************
+** **
+** set_875_multipler **
+** **
+*******************************************************/
+
+UCHAR set_875_multipler(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR scntl3Value = 0;
+
+ WRITE_SIOP_UCHAR( STEST1,
+ (UCHAR)(READ_SIOP_UCHAR(STEST1) | STEST1_DOUBLER_ENABLE));
+
+ // wait at least 20 usec.
+ ScsiPortStallExecution( RESET_STALL_TIME );
+
+ WRITE_SIOP_UCHAR( STEST3,
+ (UCHAR)(READ_SIOP_UCHAR(STEST3) | STEST3_HALT_CLOCK));
+
+ scntl3Value = 0xD5; // 80Mhz clock speed after doubling
+
+ WRITE_SIOP_UCHAR( SCNTL3, scntl3Value );
+
+ WRITE_SIOP_UCHAR( STEST1,
+ (UCHAR)(READ_SIOP_UCHAR(STEST1) | STEST1_DOUBLER_SELECT));
+
+ WRITE_SIOP_UCHAR( STEST3,
+ (UCHAR)(READ_SIOP_UCHAR(STEST3) & ~STEST3_HALT_CLOCK));
+
+ return (scntl3Value);
+}
+
+#ifdef FOR_95
+/*******************************************************
+
+
+
+** SCAM Code procedures **
+
+
+
+*******************************************************/
+
+/*******************************************************
+** **
+** Scam_Scan **
+** **
+*******************************************************/
+
+VOID scam_scan(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR overall_timer = 0;
+ UCHAR scntl3Value = 0;
+
+ if (DeviceExtension->initial_run)
+ {
+ DeviceExtension->initial_run = 0;
+ DeviceExtension->eatint_flag=FALSE;
+ DeviceExtension->current_state=FALSE;
+ save_reg(DeviceExtension, &(DeviceExtension->ScamStore));
+ // RESET the chip
+ WRITE_SIOP_UCHAR(ISTAT,0x40);
+ delay_mils(1);
+ // Clear reset
+ WRITE_SIOP_UCHAR(ISTAT,0x00);
+ delay_mils(750);
+
+ /* Enable function complete int */
+ WRITE_SIOP_UCHAR(SIEN0,(UCHAR)(READ_SIOP_UCHAR(SIEN0) | 0x40));
+
+ /* Enable sel\resel timeout int */
+ WRITE_SIOP_UCHAR(SIEN1,(UCHAR)(READ_SIOP_UCHAR(SIEN1) | 0x04));
+
+ if ( (DeviceExtension->hbaCapability & HBA_CAPABILITY_875_FAMILY) &&
+ (READ_SIOP_UCHAR(CTEST3) & 0xF0) > 0x10 )
+ {
+ // 875 rev. E or greater part with clock doubler
+ scntl3Value = set_875_multipler (DeviceExtension);
+ }
+
+ //
+ // Still need to set up the clock stuff if we did not already do it
+ // in the clock doubler code above.
+ //
+ if (!scntl3Value)
+ {
+ scntl3Value = set_8xx_clock (DeviceExtension);
+ }
+
+ EnterLLM(DeviceExtension);
+ delay_mils(1);
+
+ /* Mark all IDs except own as available */
+ DeviceExtension->ID_map = 1 << DeviceExtension->SIOPBusID;
+ Find_nonSCAM_IDs(DeviceExtension);
+
+ do
+ {
+ DeviceExtension->sna_delay=0;
+ SCAM_Arbitrate(DeviceExtension);
+ delay_mils(270);
+
+ SCAM_master_select(DeviceExtension);
+ SCAM_assign_IDs(DeviceExtension);
+ SCAM_release(DeviceExtension);
+
+ if (DeviceExtension->sna_delay)
+ delay_mils(750);
+ else
+ delay_mils(1);
+
+ overall_timer++;
+ } while ( (DeviceExtension->sna_delay != 0) &&
+ (overall_timer < 10) &&
+ (DeviceExtension->eatint_flag != TRUE) );
+
+ if (DeviceExtension->eatint_flag)
+ SCAM_release(DeviceExtension);
+
+ ExitLLM(DeviceExtension);
+
+ // Reset chip
+ WRITE_SIOP_UCHAR(ISTAT,0x40);
+ delay_mils(1);
+ // Clear reset
+ WRITE_SIOP_UCHAR(ISTAT,0x00);
+ delay_mils(750);
+
+ if (DeviceExtension->eatint_flag)
+ {
+ InitializeSIOP(DeviceExtension);
+ ResetSCSIBus(DeviceExtension);
+ }
+ else
+ {
+ restore_reg(DeviceExtension, &(DeviceExtension->ScamStore));
+ scntl3Value = 0x00;
+ if ( (DeviceExtension->hbaCapability & HBA_CAPABILITY_875_FAMILY) &&
+ (READ_SIOP_UCHAR(CTEST3) & 0xF0) > 0x10 )
+ {
+ // 875 rev. E or greater part with clock doubler
+ scntl3Value = set_875_multipler (DeviceExtension);
+ }
+
+ //
+ // Still need to set up the clock stuff if we did not already do it
+ // in the clock doubler code above.
+ //
+ if (!scntl3Value)
+ {
+ scntl3Value = set_8xx_clock (DeviceExtension);
+ }
+
+ DeviceExtension->scam_completed=TRUE;
+ }
+
+ return;
+ }
+ else
+ {
+ if (DeviceExtension->current_state)
+ {
+ DebugPrint((0, "Sym8xx: Entering SCAM code... \n"));
+ DeviceExtension->eatint_flag=FALSE;
+ save_reg(DeviceExtension, &(DeviceExtension->ScamStore));
+ DeviceExtension->nextstate=10;
+ DeviceExtension->timer_value=1000;
+ DeviceExtension->current_state=FALSE;
+ }
+ else
+ {
+ switch (DeviceExtension->nextstate)
+ {
+ case 10:
+
+ DebugPrint((2, "SCAM phase 1... \n"));
+
+ // Reset Chip
+ WRITE_SIOP_UCHAR(ISTAT,0x40);
+ DeviceExtension->timer_value=1000;
+ DeviceExtension->nextstate=20;
+ break;
+
+ case 20:
+ DebugPrint((2, "SCAM phase 2... \n"));
+
+ // Clear reset
+ WRITE_SIOP_UCHAR(ISTAT,0x00);
+ DeviceExtension->timer_value=750000;
+ DeviceExtension->nextstate=30;
+ break;
+
+
+ case 30:
+ DebugPrint((2, "SCAM phase 3... \n"));
+
+ /* Enable function complete int */
+ WRITE_SIOP_UCHAR(SIEN0,(UCHAR)(READ_SIOP_UCHAR(SIEN0) | 0x40));
+
+ /* Enable sel\resel timeout int */
+ WRITE_SIOP_UCHAR(SIEN1,(UCHAR)(READ_SIOP_UCHAR(SIEN1) | 0x04));
+
+ /* Set divide by 2 for 40MHz clock */
+ /* divide by 4 if 80 MHz */
+ if (DeviceExtension->ClockSpeed == 0x80)
+ {
+ WRITE_SIOP_UCHAR(SCNTL3, 0x55);
+ }
+ else
+ {
+ WRITE_SIOP_UCHAR(SCNTL3,0x33);
+ }
+
+ EnterLLM(DeviceExtension);
+ DeviceExtension->timer_value=1000;
+ DeviceExtension->nextstate=40;
+ break;
+
+ case 40:
+ DeviceExtension->timer_value=1000;
+ DeviceExtension->nextstate=50;
+ DebugPrint((2, "SCAM phase 4... \n"));
+
+ // loop up to 5 times to clear the C.A. conditions
+ // of the found legacy devices. O.S. could be in
+ // Queueing environment which means leaving the C.A.
+ // condition present could present a BUSY Status problem
+
+ for (i = 0; i < 5; i++)
+ {
+ /* Mark all IDs except own as available */
+ DeviceExtension->ID_map = 1 << DeviceExtension->SIOPBusID;
+ Find_nonSCAM_IDs(DeviceExtension);
+ if (!DeviceExtension->checkseen)
+ break;
+ }
+ break;
+
+ case 50:
+ DeviceExtension->timer_value=270000;
+ DeviceExtension->nextstate=60;
+ DeviceExtension->sna_delay=0;
+ DebugPrint((2, "SCAM phase 5... \n"));
+ SCAM_Arbitrate(DeviceExtension);
+ break;
+
+ case 60:
+ DebugPrint((2, "SCAM phase 6... \n"));
+ SCAM_master_select(DeviceExtension);
+ SCAM_assign_IDs(DeviceExtension);
+ SCAM_release(DeviceExtension);
+
+ if (DeviceExtension->sna_delay)
+ {
+ DeviceExtension->timer_value=750000;
+ DeviceExtension->nextstate=50;
+ }
+ else
+ {
+ DeviceExtension->timer_value=1000;
+ DeviceExtension->nextstate=70;
+ }
+ break;
+
+ case 70:
+ DebugPrint((2, "SCAM phase 7... \n"));
+ if (DeviceExtension->eatint_flag)
+ SCAM_release(DeviceExtension);
+
+ ExitLLM(DeviceExtension);
+
+ // Reset chip
+ WRITE_SIOP_UCHAR(ISTAT,0x40);
+ DeviceExtension->timer_value=1000;
+ DeviceExtension->nextstate=80;
+ break;
+
+ case 80:
+ DebugPrint((2, "SCAM phase 8... \n"));
+
+ // Clear reset
+ WRITE_SIOP_UCHAR(ISTAT,0x00);
+ DeviceExtension->timer_value=750000;
+ DeviceExtension->nextstate=90;
+ break;
+
+ case 90:
+ if (DeviceExtension->eatint_flag)
+ DeviceExtension->nextstate=150;
+ else
+ DeviceExtension->nextstate=100;
+ DeviceExtension->timer_value=5000;
+ break;
+
+ case 100:
+ DebugPrint((2, "SCAM phase 100... \n"));
+ restore_reg(DeviceExtension, &(DeviceExtension->ScamStore));
+
+ if ((DeviceExtension->hbaCapability & HBA_CAPABILITY_875_FAMILY)
+ && (READ_SIOP_UCHAR(CTEST3) & 0xF0) > 0x10 )
+ {
+ // 875 rev. E or greater part with clock doubler
+ scntl3Value = set_875_multipler (DeviceExtension);
+ }
+
+ //
+ // Still need to set up the clock stuff if we did not
+ // already do it in the clock doubler code above.
+ //
+ if (!scntl3Value)
+ {
+ scntl3Value = set_8xx_clock (DeviceExtension);
+ }
+
+ DeviceExtension->scam_completed=TRUE;
+ DebugPrint((0, "Sym8xx: Exiting SCAM code!! \n"));
+ ISR_Service_Next(DeviceExtension,ISR_START_NEXT_REQUEST);
+ DeviceExtension->nextstate=0;
+ DeviceExtension->timer_value=1000;
+ break;
+
+ case 150:
+ DebugPrint((2, "SCAM phase 150... \n"));
+ InitializeSIOP(DeviceExtension);
+ ResetSCSIBus(DeviceExtension);
+ DeviceExtension->timer_value=270000;
+ DeviceExtension->nextstate=0;
+ break;
+
+ default:
+ DeviceExtension->nextstate=0;
+ break;
+ }
+ }
+ }
+
+ if (DeviceExtension->nextstate)
+ {
+ ScsiPortNotification(RequestTimerCall,
+ DeviceExtension,
+ scam_scan,
+ DeviceExtension->timer_value);
+ }
+ else
+ {
+ return;
+ }
+}
+
+
+
+/*******************************************************
+** **
+** save_reg **
+** **
+*******************************************************/
+
+VOID save_reg(PHW_DEVICE_EXTENSION DeviceExtension,
+ PSIOP_REG_STORE RegStore)
+{
+ RegStore->reg_st[0] = READ_SIOP_UCHAR(SCNTL0);
+ RegStore->reg_st[1] = READ_SIOP_UCHAR(SCNTL3);
+ RegStore->reg_st[2] = READ_SIOP_UCHAR(SCID);
+ RegStore->reg_st[3] = READ_SIOP_UCHAR(SXFER);
+ RegStore->reg_st[4] = READ_SIOP_UCHAR(SDID);
+ RegStore->reg_st[5] = READ_SIOP_UCHAR(GPREG);
+ RegStore->reg_st[6] = READ_SIOP_UCHAR(CTEST3);
+ RegStore->reg_st[7] = READ_SIOP_UCHAR(CTEST4);
+ RegStore->reg_st[8] = READ_SIOP_UCHAR(CTEST5);
+ RegStore->reg_st[9] = READ_SIOP_UCHAR(DMODE);
+ RegStore->reg_st[10] = READ_SIOP_UCHAR(DIEN);
+ RegStore->reg_st[11] = READ_SIOP_UCHAR(DCNTL);
+ RegStore->reg_st[12] = READ_SIOP_UCHAR(SIEN0);
+ RegStore->reg_st[13] = READ_SIOP_UCHAR(SIEN1);
+ RegStore->reg_st[14] = READ_SIOP_UCHAR(GPCNTL);
+ RegStore->reg_st[15] = READ_SIOP_UCHAR(STIME0);
+ RegStore->reg_st[16] = READ_SIOP_UCHAR(STIME1);
+ RegStore->reg_st[17] = READ_SIOP_UCHAR(RESPID0);
+ RegStore->reg_st[18] = READ_SIOP_UCHAR(RESPID1);
+ RegStore->reg_st[19] = READ_SIOP_UCHAR(STEST2);
+ RegStore->reg_st[20] = READ_SIOP_UCHAR(STEST3);
+ RegStore->long_st = READ_SIOP_ULONG(DSA);
+}
+
+
+/************************************************************************/
+/* This routine puts the 720 into Low Level Mode, enables SCE and ADB */
+/* to allow direct drive of ALL SCSI signals, plus the data bus. ADB */
+/* is required to have the 720 generate parity on direct driven data. */
+/************************************************************************/
+
+VOID EnterLLM(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR id = DeviceExtension->SIOPBusID;
+
+ WRITE_SIOP_UCHAR(SCID,id);
+
+ /* Make sure no control signals are asserted */
+ WRITE_SIOP_UCHAR(SOCL,0x00);
+ WRITE_SIOP_UCHAR(SODL,0x00);
+ WRITE_SIOP_UCHAR(SODL+1,0x00);
+
+ /* Enable Lower Level Mode */
+
+ WRITE_SIOP_UCHAR(STEST2,(UCHAR)(READ_SIOP_UCHAR(STEST2) | 0x81));
+
+ /* Sometimes have interrupt on entry to LLM */
+ EatInts(DeviceExtension);
+}
+
+
+/************************************************************************/
+/* This routine finds hard IDs not already in the passed-in idmap, and */
+/* returns the new filled-in idmap. */
+/************************************************************************/
+
+VOID Find_nonSCAM_IDs(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR current_id=0;
+ UCHAR istat=0;
+ UCHAR dispose;
+ UCHAR count;
+ UCHAR maxim_ID;
+ ULONG idmap = DeviceExtension->ID_map;
+
+ DebugPrint((2, "Sym8xx: Entering Find_nonSCAM_IDs...\n"));
+
+ /* Wide Support */
+ if (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE)
+ maxim_ID = 15;
+ else
+ maxim_ID=7;
+
+ // clear out the C.A. check condition
+ DeviceExtension->checkseen = 0;
+ while (current_id <= maxim_ID)
+ {
+ if (idmap & (ULONG)(1 << current_id))
+ {
+ ;
+ }
+
+ else
+ { /* Check for unoccupied ID */
+
+ /* Eat the interrupt (possible UDC after bus free)
+ /* from previous loop put here to give longer delay
+
+ DebugPrint((2, "EatInts [1] \n"));
+ if (!EatInts(DeviceExtension))
+ {
+ DeviceExtension->nextstate=70;
+ DeviceExtension->eatint_flag=TRUE;
+ DeviceExtension->ID_map = 0;
+ return;
+ }
+
+ WRITE_SIOP_UCHAR(STIME1,0x00); /* Disable GEN timer */
+ WRITE_SIOP_UCHAR(STIME0,(UCHAR)SHORT_720_STO);
+ /* Enable short SEL TO */
+ WRITE_SIOP_UCHAR(SDID,current_id); /* Choose current ID target */
+ WRITE_SIOP_UCHAR(SCNTL0,0xe0); /* Full arb & select wo/ATN */
+ istat=READ_SIOP_UCHAR(ISTAT);
+
+ count=0;
+ /* Wait for completion */
+ while ( !(istat & 0x02) )
+ {
+ DebugPrint((2, "Stuck... [10], istat=%2x \n",istat));
+ count++;
+
+ if (count > 30)
+ {
+ DeviceExtension->nextstate=70;
+ DeviceExtension->eatint_flag=TRUE;
+ DeviceExtension->ID_map = 0;
+ return;
+ }
+ ScsiPortStallExecution(5000);
+ istat=READ_SIOP_UCHAR(ISTAT);
+ }
+
+ if (istat & CONNECTED)
+ {
+ /* Someone responded! */
+ if (!EatInts(DeviceExtension))
+ {
+ DeviceExtension->nextstate=70;
+ DeviceExtension->eatint_flag=TRUE;
+ DeviceExtension->ID_map = 0;
+ return;
+ }
+ idmap |= (1 << current_id);
+
+ /* Send Test Unit Ready cmd */
+ init_send_byte(0x00,DeviceExtension);
+ init_send_byte(0x00,DeviceExtension);
+ init_send_byte(0x00,DeviceExtension);
+ init_send_byte(0x00,DeviceExtension);
+ init_send_byte(0x00,DeviceExtension);
+ init_send_byte(0x00,DeviceExtension);
+
+ /* Accept STATUS */
+ dispose=(UCHAR)init_recv_byte(DeviceExtension);
+ if (dispose == 0x02)
+ DeviceExtension->checkseen = 1;
+
+ /* Accept MSG_IN */
+ dispose=(UCHAR)init_recv_byte(DeviceExtension);
+
+ /* Wait for BUS FREE */
+ while(READ_SIOP_UCHAR(ISTAT) & CONNECTED)
+ DebugPrint((2, "Stuck... [11] \n"));
+
+ DebugPrint((2, "EatInts [2] \n"));
+ if (!EatInts(DeviceExtension))
+ {
+ DeviceExtension->nextstate=70;
+ DeviceExtension->eatint_flag=TRUE;
+ DeviceExtension->ID_map = 0;
+ return;
+ }
+
+ }
+ else
+ {
+ DebugPrint((2, "EatInts [3] \n"));
+ if (!EatInts(DeviceExtension))
+ {
+ DeviceExtension->nextstate=70;
+ DeviceExtension->eatint_flag=TRUE;
+ DeviceExtension->ID_map = 0;
+ return;
+ }
+ }
+ }
+ current_id++;
+ }
+
+ DebugPrint((2, "Sym8xx: Exiting Find_nonSCAM_IDs, Idmap=%2x \n",idmap));
+ DeviceExtension->ID_map = idmap;
+ return;
+}
+
+
+/************************************************************************/
+/* This routine performs a SCAM Level I arbitration with the already */
+/* set chip SCID value. It asserts SEL and MSG to indicate a SCAM */
+/* selection will follow. */
+/************************************************************************/
+
+VOID SCAM_Arbitrate(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR count;
+ volatile UCHAR won_arb=FALSE;
+ long ID_seen;
+ UCHAR sstat0;
+
+ DebugPrint((2, "Sym8xx: Entering SCAM_Arbitrate... \n"));
+
+ while (!won_arb)
+ {
+ /* Start simple arb */
+ WRITE_SIOP_UCHAR(SCNTL0,0x20);
+
+ count=0;
+ sstat0=READ_SIOP_UCHAR(SSTAT0);
+
+ /* Wait for arb to begin */
+ while ( !(sstat0 & ARB_IN_PROGRESS))
+ {
+ DebugPrint((2, "Stuck... [20] \n"));
+ count++;
+
+ if (count > 30)
+ {
+ EatInts(DeviceExtension);
+ DeviceExtension->nextstate=70;
+ DeviceExtension->eatint_flag=TRUE;
+ return;
+ }
+ ScsiPortStallExecution(5000);
+ sstat0=READ_SIOP_UCHAR(SSTAT0);
+ }
+
+ ID_seen = READ_SIOP_UCHAR(SBDL);
+
+ /* Need code in here to take care of the case where we have been selected
+ or reselected while waiting to win BUS arbitration */
+
+ if ( ID_seen > (1 << (READ_SIOP_UCHAR(SCID) & 0x0F) ) )
+ {
+ DebugPrint((2, "SCAM Arbitrate, ID_seen=%2l \n",ID_seen));
+
+ } /* Higher ID asserted, wait 'til next time */
+ else
+ { /* We win, so assert SEL & MSG */
+ WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) | MSG | SEL));
+
+ /* End simple arb */
+ WRITE_SIOP_UCHAR(SCNTL0,0x00);
+ won_arb=TRUE;
+ }
+ }
+ DebugPrint((2, "Sym8xx: Exiting SCAM_Arbitrate... \n"));
+}
+
+
+/************************************************************************/
+/* This routine performs a SCAM Level I selection. It assumes SEL and */
+/* MSG are already asserted, and that a SCAM arbitration has been done. */
+/************************************************************************/
+
+VOID SCAM_master_select(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ DebugPrint((3, "Sym8xx: Entering SCAM_master_select... \n"));
+
+ /* De-assert message */
+ WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) & ~MSG));
+
+ /* Wait for message release */
+ de_glitch(0x0B,MSG,DeviceExtension);
+// while ((READ_SIOP_UCHAR(SBCL) & MSG) || (READ_SIOP_UCHAR(SBCL) & MSG));
+
+ /* Re-assert busy */
+ WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) | BSY));
+
+ /* Assert CD & IO */
+ WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) | IO | CD));
+
+ /* Assert DB7 & DB6 */
+ WRITE_SIOP_UCHAR(SODL,0xC0);
+
+ /* Assert SCSI data bus */
+ WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) | 0x40));
+
+ /* De-assert select */
+ WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) & ~SEL));
+
+ /* Wait for select release */
+ de_glitch(0x0B,SEL,DeviceExtension);
+// while ((READ_SIOP_UCHAR(SBCL) & SEL) || (READ_SIOP_UCHAR(SBCL) & SEL));
+
+ /* De-assert DB6 */
+ WRITE_SIOP_UCHAR(SODL,0x80);
+
+ /* Wait for DB6 release */
+ de_glitch(0x58,0x40,DeviceExtension);
+// while ((READ_SIOP_UCHAR(SBDL) & 0x40) || (READ_SIOP_UCHAR(SBDL) & 0x40));
+
+ /* Re-assert select */
+ WRITE_SIOP_UCHAR(SOCL,(UCHAR)(READ_SIOP_UCHAR(SOCL) | SEL));
+
+ DebugPrint((3, "Sym8xx: Exiting SCAM_master_select \n"));
+}
+
+
+/************************************************************************/
+/* 1 routine assigns IDs from the passed-in idmap, and returns the */
+/* new filled-in idmap. */
+/************************************************************************/
+
+VOID SCAM_assign_IDs(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ LONG isolation; /* SCAM_isolation() status return */
+ UCHAR i;
+ UCHAR scam_str[SCAM_ID_STRLEN];
+ UCHAR encoded_id[8];
+ UCHAR greatest_ID;
+ UCHAR desired_ID;
+ UCHAR *greatest_IDptr;
+ UCHAR *desired_IDptr;
+ UCHAR *scam_strptr;
+ CHAR wide, set_greater, try_greater;
+ UCHAR wanted_id, min_id;
+ UCHAR new_id;
+ ULONG idmap = DeviceExtension->ID_map;
+
+ isolation=ISOLATED;
+
+ encoded_id[0] = 0x18;
+ encoded_id[1] = 0x11;
+ encoded_id[2] = 0x12;
+ encoded_id[3] = 0x0b;
+ encoded_id[4] = 0x14;
+ encoded_id[5] = 0x0d;
+ encoded_id[6] = 0x0e;
+ encoded_id[7] = 0x07;
+
+ desired_IDptr = &desired_ID;
+ greatest_IDptr = &greatest_ID;
+ scam_strptr = scam_str;
+
+ DebugPrint((3, "Sym8xx: Entering SCAM_assign_IDs... \n"));
+
+ while ( isolation==ISOLATED )
+ {
+ SCAM_xfer(SCAM_SYNC,DeviceExtension);
+ SCAM_xfer(SCAM_ASSIGN_ID,DeviceExtension);
+
+ isolation=SCAM_isolate(NULL, scam_strptr, greatest_IDptr, desired_IDptr,
+ DEFER,DeviceExtension);
+ if (DeviceExtension->sna_delay)
+ {
+ DeviceExtension->ID_map = idmap;
+ return;
+ }
+
+ if (isolation == ISOLATED)
+ {
+ /* Assign desired Id if possible, if not, scan to the next lowest
+ value possible, if none lower found then search for higer ID to
+ assign */
+
+ /* Check for wide support */
+ if ( (DeviceExtension->hbaCapability & HBA_CAPABILITY_WIDE) &&
+ (greatest_ID == 0x01) )
+ {
+ wide = 1;
+ }
+
+ else
+ {
+ wide = 0;
+ }
+
+ new_id = 0xFF;
+
+ if (desired_ID & ASSIGNABLE_ID)
+ {
+ /* Leave only wanted ID */
+ desired_ID &= ~ASSIGNABLE_ID;
+ min_id = 0;
+
+ /* Set to correct max ID for bus type */
+ if ( !wide && (desired_ID > 7) )
+ {
+ desired_ID = 0;
+ }
+ else if (wide)
+ {
+ if (desired_ID > 7)
+ min_id = 8;
+ if (desired_ID > 15)
+ desired_ID = 8;
+ }
+
+ try_greater = 0;
+ set_greater = 0;
+ wanted_id = desired_ID;
+
+ /* This do loop is for the 2nd try at finding an open ID.
+ * If the next do loop fails to find an ID that is the desired
+ * ID or one that is lower, this loop will be enabled to try
+ * scanning from highest ID to lowest ID.
+ */
+
+ do
+ {
+ if (set_greater)
+ {
+ try_greater = 1;
+ set_greater = 0;
+ }
+
+ do
+ {
+ /* Search desired ID then all lower IDs till an
+ available one is found or set flag to indicate
+ higher priority IDs need to be searched */
+
+ for ( i=0; (idmap & (ULONG)(1<<(wanted_id - i))) &&
+ ((wanted_id-i) >= min_id); i++);
+ if ( (wanted_id - i) >= min_id )
+ {
+ new_id = wanted_id - i;
+ idmap |= (ULONG)(1 << new_id);
+ }
+ else if (min_id == 0)
+ {
+ if (wide)
+ {
+ min_id = 8;
+ wanted_id = 15;
+ }
+ else
+ set_greater = 1;
+ }
+ else
+ set_greater = 1;
+
+ } while ( (new_id == 0xff) && (set_greater == 0) );
+
+ /* heres the check to see if we need to continue */
+ if (set_greater)
+ {
+ wanted_id = 7;
+ min_id = 0;
+ }
+
+ } while ( !try_greater && set_greater );
+ }
+
+ if ( new_id != 0xff )
+ {
+ if ( new_id <= 7 )
+ SCAM_xfer(SCAM_SET_ID_00,DeviceExtension);
+ else
+ SCAM_xfer(SCAM_SET_ID_01,DeviceExtension);
+
+ /* Send encoded ID */
+ SCAM_xfer(encoded_id[new_id],DeviceExtension);
+ }
+ else
+ isolation = NOBODY_HOME;
+ }
+ }
+
+ /* This SCAM iteration is to stop all SCAM protocol on the bus. Possibly
+ get a broken drive off the bus or one that can not be assigned an ID. */
+
+ SCAM_xfer(SCAM_SYNC,DeviceExtension);
+ SCAM_xfer(SCAM_ASSIGN_ID,DeviceExtension);
+ isolation=SCAM_isolate(NULL, scam_strptr, greatest_IDptr, desired_IDptr,
+ STOP,DeviceExtension);
+
+ DebugPrint((3, "Sym8xx: Exiting SCAM_assign_IDs, Idmap=%2x \n",idmap));
+
+ DeviceExtension->ID_map = idmap;
+ return;
+}
+
+
+/************************************************************************/
+/* Returns: */
+/* ISOLATED valid isolation cycle */
+/* NOBODY_HOME no data was transferred */
+/************************************************************************/
+
+LONG SCAM_isolate(UCHAR *outstr, UCHAR *instr,
+ UCHAR *greatest_ID, UCHAR *desired_ID,
+ UCHAR function,PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR first_quintet=1;
+ UCHAR byteloop=0;
+ UCHAR strloop=0;
+ UCHAR valid_id;
+ UCHAR *sendstr;
+ UCHAR *recvstr;
+ CHAR sendchar='\0',recvchar='\0';
+ UCHAR terminate=0,quintet=0;
+
+ sendstr=outstr; /* Make copies of the string pointers */
+ recvstr=instr; /* for local manipulation. */
+
+ strloop=1; /* Init loop count */
+ while ((strloop <= SCAM_ID_STRLEN) && (!terminate))
+ {
+ if (sendstr==NULL)
+ sendchar='\0';
+ else
+ sendchar=*sendstr++;
+
+ byteloop=1; /* Init loop count through the byte */
+ recvchar='\0'; /* Clear received character */
+
+ while ((byteloop <= 8) && (!terminate))
+ {
+ if (function == DEFER)
+ {
+ quintet=SCAM_xfer(0,DeviceExtension);
+ terminate=(quintet==0); /* Abort if no players */
+ }
+ else if (function == STOP)
+ {
+ quintet = SCAM_xfer(0x10,DeviceExtension);
+ terminate=1;
+ }
+ else
+ {
+ quintet = (sendchar & 0x80) ? 2 : 1;
+ quintet = SCAM_xfer(quintet, DeviceExtension);
+
+ /* Defer if sent a 0 bit and saw a 1 bit */
+ function=(!(sendchar & 0x80) && (quintet==0x3));
+ }
+
+ /* Always terminate if DB4 asserted */
+ if (quintet & 0x10)
+ terminate=1;
+
+ recvchar=(recvchar | ((quintet == 0x01) ? 0 : 1));
+
+ /* Don't shift on last read */
+ if (byteloop != 8)
+ {
+ sendchar=(sendchar << 1); /* Shift to next bit */
+ recvchar=(recvchar << 1); /* Shift to next bit */
+ }
+ byteloop++;
+
+ if (first_quintet && terminate)
+ return(NOBODY_HOME);
+ first_quintet=0; /* Clear first flag */
+ }
+
+ if (recvstr != NULL)
+ *recvstr++ = recvchar;
+
+ if (strloop == 1)
+ {
+ *greatest_ID = ( (recvchar & 0x30) >> 4);
+ valid_id = ( (recvchar & 0x06) >> 1 );
+
+ if (!(recvchar & 0x01))
+ {
+ DeviceExtension->sna_delay=0x01;
+ return(NOBODY_HOME);
+ }
+ }
+ else if (strloop == 2)
+ {
+ switch ( valid_id )
+ {
+ case 1:
+ {
+ *desired_ID = ( (recvchar & 0x1F) | ASSIGNABLE_ID );
+ break;
+ }
+ case 2:
+ {
+ *desired_ID = ( recvchar & 0x1F );
+ break;
+ }
+ default:
+ {
+ *desired_ID = 0x7F;
+ break;
+ }
+ }
+ }
+ strloop++;
+ }
+
+ return(ISOLATED);
+}
+
+
+/************************************************************************/
+/* This routine performs all SCAM handshaking necessary to transfer a */
+/* single quintet. It leaves the bus ready for another transfer. */
+/* It returns the actual quintet which was transferred on the bus. */
+/************************************************************************/
+
+UCHAR SCAM_xfer(UCHAR quintet,PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR actual;
+ UCHAR myquint;
+
+#define CURRENT READ_SIOP_UCHAR(SBDL)
+
+ myquint=quintet & QUINTET_MASK;
+
+ /* While waiting for bits to drop read reg twice to take care of glitches */
+
+ /* Assert data and DB5 */
+ WRITE_SIOP_UCHAR(SODL,(UCHAR)(myquint |DB5 |DB7));
+
+ /* Assert SCSI data bus */
+ WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) | 0x40));
+
+ /* Release DB7 */
+ WRITE_SIOP_UCHAR(SODL,(UCHAR)((CURRENT & ~DB7) | DB5));
+
+ /* Wait for DB7 release */
+ de_glitch(0x58,DB7,DeviceExtension);
+// while((READ_SIOP_UCHAR(SBDL) & DB7) || (READ_SIOP_UCHAR(SBDL) & DB7));
+
+ /* Latch quintet */
+ actual = READ_SIOP_UCHAR(SBDL) & QUINTET_MASK;
+
+ /* Assert DB6 (begin handshake) */
+ WRITE_SIOP_UCHAR(SODL,(UCHAR)(CURRENT | DB5 | DB6));
+
+ /* Release DB5 (end Handshake) */
+ WRITE_SIOP_UCHAR(SODL,(UCHAR)((CURRENT & ~DB5) | DB6));
+
+ /* Wait for DB5 release */
+ de_glitch(0x58,DB5,DeviceExtension);
+// while ((READ_SIOP_UCHAR(SBDL) & DB5) || (READ_SIOP_UCHAR(SBDL) & DB5));
+
+ /* Assert DB7 (begin handshake) */
+ WRITE_SIOP_UCHAR(SODL,(UCHAR)(DB6 | DB7));
+
+ /* Release DB6 (end handshake) */
+ WRITE_SIOP_UCHAR(SODL,(UCHAR)(DB7));
+
+ /* Wait for DB6 release */
+ de_glitch(0x58,DB6,DeviceExtension);
+// while ((READ_SIOP_UCHAR(SBDL) & DB6) || (READ_SIOP_UCHAR(SBDL) & DB6));
+
+ return(actual);
+}
+
+
+/************************************************************************/
+/* This routine ends the current SCAM protocol by dropping all signals */
+/************************************************************************/
+
+VOID SCAM_release(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ /* Make sure no control signals are asserted */
+ WRITE_SIOP_UCHAR(SOCL,0x00);
+ WRITE_SIOP_UCHAR(SODL,0x00);
+ WRITE_SIOP_UCHAR(SODL+1,0x00);
+}
+
+
+/************************************************************************/
+/* This routine restores the 720 to a normal operating mode. */
+/************************************************************************/
+
+VOID ExitLLM(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ /* Disable low level mode */
+ WRITE_SIOP_UCHAR(STEST2,(UCHAR)(READ_SIOP_UCHAR(STEST2) & 0x7E));
+
+ EatInts(DeviceExtension);
+}
+
+
+/*******************************************************
+** **
+** restore_reg **
+** **
+*******************************************************/
+
+VOID restore_reg( PHW_DEVICE_EXTENSION DeviceExtension,
+ PSIOP_REG_STORE RegStore)
+{
+ WRITE_SIOP_UCHAR(SCNTL0,RegStore->reg_st[0]);
+ WRITE_SIOP_UCHAR(SCNTL3,RegStore->reg_st[1]);
+ WRITE_SIOP_UCHAR(SCID,RegStore->reg_st[2]);
+ WRITE_SIOP_UCHAR(SXFER,RegStore->reg_st[3]);
+ WRITE_SIOP_UCHAR(SDID,RegStore->reg_st[4]);
+ WRITE_SIOP_UCHAR(GPREG,RegStore->reg_st[5]);
+ WRITE_SIOP_UCHAR(CTEST3,RegStore->reg_st[6]);
+ WRITE_SIOP_UCHAR(CTEST4,RegStore->reg_st[7]);
+ WRITE_SIOP_UCHAR(CTEST5,RegStore->reg_st[8]);
+ WRITE_SIOP_UCHAR(DMODE,RegStore->reg_st[9]);
+ WRITE_SIOP_UCHAR(DIEN,RegStore->reg_st[10]);
+ WRITE_SIOP_UCHAR(DCNTL,RegStore->reg_st[11]);
+ WRITE_SIOP_UCHAR(SIEN0,RegStore->reg_st[12]);
+ WRITE_SIOP_UCHAR(SIEN1,RegStore->reg_st[13]);
+ WRITE_SIOP_UCHAR(GPCNTL,RegStore->reg_st[14]);
+ WRITE_SIOP_UCHAR(STIME0,RegStore->reg_st[15]);
+ WRITE_SIOP_UCHAR(STIME1,RegStore->reg_st[16]);
+ WRITE_SIOP_UCHAR(RESPID0,RegStore->reg_st[17]);
+ WRITE_SIOP_UCHAR(RESPID1,RegStore->reg_st[18]);
+ WRITE_SIOP_UCHAR(STEST2,RegStore->reg_st[19]);
+ WRITE_SIOP_UCHAR(STEST3,RegStore->reg_st[20]);
+ WRITE_SIOP_ULONG(DSA,RegStore->long_st);
+}
+
+
+
+/******************************************************/
+/* This routine eats any interrupts pending. */
+/******************************************************/
+
+UCHAR EatInts(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR dispose;
+ UCHAR istat=0;
+ UCHAR sist0=0;
+ UCHAR reset_flag;
+
+#define DIP 0x01
+#define SIP 0x02
+
+ reset_flag=TRUE;
+ istat=READ_SIOP_UCHAR(ISTAT);
+ sist0=READ_SIOP_UCHAR(SIST0);
+
+ /* Spin until no DMA or SCSI interrupts left */
+ while ( (istat & (DIP + SIP)) || (sist0 & 0x02) )
+ {
+ if (sist0 & 0x02)
+ {
+ reset_flag=FALSE;
+ dispose=READ_SIOP_UCHAR(SIST0);
+ dispose=READ_SIOP_UCHAR(SIST1);
+ }
+
+ if (istat & SIP)
+ {
+ dispose=READ_SIOP_UCHAR(SIST0);
+ dispose=READ_SIOP_UCHAR(SIST1);
+ }
+
+ if (istat & DIP)
+ {
+ dispose=READ_SIOP_UCHAR(DSTAT);
+ }
+
+ ScsiPortStallExecution(5000);
+ istat=READ_SIOP_UCHAR(ISTAT);
+ sist0=READ_SIOP_UCHAR(SIST0);
+ }
+ return(reset_flag);
+}
+
+
+/************************************************************************/
+/* This routine handshakes ACK based on REQ to send a byte to a target */
+/************************************************************************/
+
+VOID init_send_byte(LONG dbyte,PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ /* Wait for REQ asserted */
+ while (!(READ_SIOP_UCHAR(SBCL) & REQ))
+ {
+ if (READ_SIOP_UCHAR(ISTAT) & 0x02)
+ return;
+ }
+
+ WRITE_SIOP_UCHAR(SODL,(UCHAR)dbyte); /* Assert data */
+
+ WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) | 0x40));
+ /* Assert SCSI data bus */
+ WRITE_SIOP_UCHAR(SOCL,0x00); /* Clear ATN */
+ WRITE_SIOP_UCHAR(SOCL,ACK); /* Set ACK */
+
+ /* Wait for REQ released */
+ while (READ_SIOP_UCHAR(SBCL) & REQ);
+
+ WRITE_SIOP_UCHAR(SODL,0x00); /* Clear data */
+ WRITE_SIOP_UCHAR(SOCL,0x00); /* Clear ACK */
+
+ /* De-assert SCSI data bus */
+ WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) & ~0x40));
+}
+
+
+/************************************************************************/
+/* This routine handshakes ACK based on REQ to receive a byte from a */
+/* target. */
+/************************************************************************/
+
+UCHAR init_recv_byte(PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR dbyte;
+
+ /* De-assert SCSI data bus */
+ WRITE_SIOP_UCHAR(SCNTL1,(UCHAR)(READ_SIOP_UCHAR(SCNTL1) & ~0x40));
+
+ /* Wait for REQ asrt */
+ while (!(READ_SIOP_UCHAR(SBCL) & REQ))
+ {
+ if (READ_SIOP_UCHAR(ISTAT) & 0x02)
+ return(0);
+ }
+
+ dbyte=READ_SIOP_UCHAR(SBDL); /* Latch data */
+ WRITE_SIOP_UCHAR(SOCL,0x00); /* Clear ATN */
+ WRITE_SIOP_UCHAR(SOCL,ACK); /* Set ACK */
+
+ /* Wait for REQ released */
+ while (READ_SIOP_UCHAR(SBCL) & REQ);
+
+ WRITE_SIOP_UCHAR(SOCL,0x00); /* Clear ACK */
+ return(dbyte);
+}
+
+
+/************************************************************************/
+/* de-glitch is used to take the bounce off the async control lines */
+/* used for SCAM data passing. The glitch value is set to 32 to */
+/* take care of the possible 32 wired or glitches if a wide 32 bit bus */
+/* is used and all ID's are taken. */
+/************************************************************************/
+
+VOID de_glitch(ULONG offset,UCHAR value,PHW_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR glitch,i;
+ ULONG chip_base=(ULONG)DeviceExtension->SIOPRegisterBase;
+ PUCHAR chip_reg;
+
+ chip_reg = (PUCHAR)(chip_base+offset);
+
+ do
+ {
+ glitch=0;
+ for (i=0;i<32;i++)
+ {
+ if (ScsiPortReadPortUchar(chip_reg) & value)
+ {
+ glitch=1;
+ i=32;
+ }
+ }
+ } while (glitch);
+}
+
+
+/*****************************************************************************/
+/* delay_mils is used to delay the scam code X amount of milliseconds by
+** using the system call of scsiportstallexecution
+**
+******************************************************************************/
+void delay_mils( USHORT counter)
+{
+ USHORT i;
+
+ for ( i = counter; i > 0; i--)
+ ScsiPortStallExecution(999);
+}
+
+#endif
diff --git a/private/ntos/miniport/symbios/symc810/symc810.h b/private/ntos/miniport/symbios/symc810/symc810.h
new file mode 100644
index 000000000..06b917fd6
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/symc810.h
@@ -0,0 +1,101 @@
+/************************************************************************
+* *
+* Copyright 1994 Symbios Logic Inc. All rights reserved. *
+* *
+* This file is confidential and a trade secret of Symbios Logic *
+* The receipt of or possession of this file does not convey any *
+* rights to reproduce or disclose its contents or to manufacture, *
+* use, or sell anything is may describe, in whole, or in part, *
+* without the specific written consent of Symbios Logic Inc *
+* *
+************************************************************************/
+
+/*+++HDR
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Who? Description
+ * -------- ---- -------------------------------------------------------
+ *
+ *
+---*/
+
+
+#ifndef _SYM53C810_
+#define _SYM53C810_
+
+
+//
+// 53C8XX SIOP I/O registers.
+//
+
+typedef struct _SIOP_REGISTER_BASE {
+ UCHAR SCNTL0; // 00 SCSI control 0
+ UCHAR SCNTL1; // 01 SCSI control 1
+ UCHAR SCNTL2; // 02 SCSI control 2
+ UCHAR SCNTL3; // 03 SCSI control 3
+ UCHAR SCID; // 04 SCSI chip ID
+ UCHAR SXFER; // 05 SCSI transfer
+ UCHAR SDID; // 06 SCSI destination ID
+ UCHAR GPREG; // 07 general purpose bits
+ UCHAR SFBR; // 08 SCSI first byte received
+ UCHAR SOCL; // 09 SCSI output control latch
+ UCHAR SSID; // 0a SCSI selector id
+ UCHAR SBCL; // 0b SCSI bus control lines
+ UCHAR DSTAT; // 0c DMA status
+ UCHAR SSTAT0; // 0d SCSI status 0
+ UCHAR SSTAT1; // 0e SCSI status 1
+ UCHAR SSTAT2; // 0f SCSI status 2
+ ULONG DSA; // 10-13 data structure address
+ UCHAR ISTAT; // 14 interrupt status
+ UCHAR RESERVED0[3]; // 15-17 reserved
+ UCHAR CTEST0; // 18 chip test 0
+ UCHAR CTEST1; // 19 chip test 1
+ UCHAR CTEST2; // 1a chip test 2
+ UCHAR CTEST3; // 1b chip test 3
+ ULONG TEMP; // 1c-1f temporary stack
+ UCHAR DFIFO; // 20 DMA fifo
+ UCHAR CTEST4; // 21 chip test 4
+ UCHAR CTEST5; // 22 chip test 5
+ UCHAR CTEST6; // 23 chip test 6
+ UCHAR DBC[3]; // 24-26 DMA byte counter
+ UCHAR DCMD; // 27 DMA command
+ ULONG DNAD; // 28-2b DMA next address for data
+ ULONG DSP; // 2c-2f DMA scripts pointer
+ UCHAR DSPS[4]; // 30-33 DMA scripts pointer save
+ UCHAR SCRATCH[4]; // 34-37 general purpose scratch pad A
+ UCHAR DMODE; // 38 DMA mode
+ UCHAR DIEN; // 39 DMA interrupt enable
+ UCHAR DWT; // 3a DMA watchdog timer
+ UCHAR DCNTL; // 3b DMA control
+ ULONG ADDER; // 3c-3f sum output of internal adder
+ UCHAR SIEN0; // 40 SCSI interrupt enable 0
+ UCHAR SIEN1; // 41 SCSI interrupt enable 1
+ UCHAR SIST0; // 42 SCSI interrupt status 0
+ UCHAR SIST1; // 43 SCSI interrupt status 1
+ UCHAR SLPAR; // 44 SCSI longitudinal parity
+ UCHAR SWIDE; // 45 SCSI wide residue
+ UCHAR MACNTL; // 46 memory access control
+ UCHAR GPCNTL; // 47 general purpose control
+ UCHAR STIME0; // 48 SCSI timer 0
+ UCHAR STIME1; // 49 SCSI timer 1
+ UCHAR RESPID0; // 4a response ID low-byte
+ UCHAR RESPID1; // 4b response ID high-byte
+ UCHAR STEST0; // 4c SCSI test 0
+ UCHAR STEST1; // 4d SCSI test 1
+ UCHAR STEST2; // 4e SCSI test 2
+ UCHAR STEST3; // 4f SCSI test 3
+ UCHAR SIDL; // 50-51 SCSI input data latch
+ UCHAR SIDL_LOWER;
+ UCHAR RESERVED3[2]; // 52-53 reserved
+ UCHAR SODL; // 54-55 SCSI output data latch
+ UCHAR SODL_LOWER;
+ UCHAR RESERVED4[2]; // 56-57 reserved
+ UCHAR SBDL; // 58-59 SCSI bus data lines
+ UCHAR SBDL_LOWER;
+ UCHAR RESERVED5[2]; // 5a-5b reserved
+ ULONG SCRATCHB; // 5c-5f general purpose scratch pad B
+} SIOP_REGISTER_BASE, *PSIOP_REGISTER_BASE;
+
+#endif
diff --git a/private/ntos/miniport/symbios/symc810/symc810.rc b/private/ntos/miniport/symbios/symc810/symc810.rc
new file mode 100644
index 000000000..38d852f94
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/symc810.rc
@@ -0,0 +1,41 @@
+/************************************************************************
+* *
+* Copyright 1994 Symbios Logic Inc. All rights reserved. *
+* *
+* This file is confidential and a trade secret of Symbios Logic Inc. *
+* The receipt of or possession of this file does not convey any *
+* rights to reproduce or disclose its contents or to manufacture, *
+* use, or sell anything is may describe, in whole, or in part, *
+* without the specific written consent of Symbios Logic inc. *
+* *
+************************************************************************/
+
+/*+++HDR
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Who? Description
+ * -------- ---- -------------------------------------------------------
+ *
+ *
+---*/
+
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Symbios Logic Inc. SCSI Miniport Driver"
+#define VER_INTERNALNAME_STR "SYMC8XX.SYS"
+
+
+#define VER_COMPANYNAME_STR "Symbios Logic Inc."
+#define VER_LEGALCOPYRIGHT_YEARS "1992-1994"
+#define VER_LEGALCOPYRIGHT_STR "Copyright \251 Symbios Logic Inc. " VER_LEGALCOPYRIGHT_YEARS
+#define VER_PRODUCTNAME_STR "Symbios Logic Inc. SCSI Miniport Driver"
+#define VER_PRODUCTVERSION_STR "DULUTH-1.92.05"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/symbios/symc810/symnvm.h b/private/ntos/miniport/symbios/symc810/symnvm.h
new file mode 100644
index 000000000..5d09df2a1
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/symnvm.h
@@ -0,0 +1,325 @@
+/***************************************************************************
+ * *
+ * Copyright 1995 Symbios Logic Incorporated. All rights reserved. *
+ * *
+ * This file is confidential and a trade secret of Symbios Logic. The *
+ * receipt of or possession of this file does not convey any rights to *
+ * reproduce or disclose its contents or to manufacture, use, or sell *
+ * anything it may describe, in whole, or in part, without the specific *
+ * written consent of Symbios Logic Incorporated. *
+ * *
+ ***************************************************************************/
+
+/* Name: SYMNVM.H
+ * Title: NT's header file for NVRAM support
+ * $Workfile: symnvm.h $
+ * $Revision: 1.1 $
+ * $Modtime: 22 Sep 1995 13:03:58 $
+ * Programmer: Scott Masterson
+ * Creation Date: July 14, 1995
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Who? Description
+ * -------- ---- -------------------------------------------------------
+#BeginRevision
+ * 7/14/95 SAM Initial check in. For definitions of fields see the SDMS4.0
+ * bootrom files.
+ * 7/18/95 SAM updated structures to match major 0 minor 0x30 rev levels
+ * added IoPort field to HBA_INIT structure
+#EndRevision
+ *
+ *
+#BeginDescription
+ *
+ * This include file contains the definitions for the NT driver to read user
+ * set values in the nvram chip. The driver looks at the HBA ID and scam ID values.
+ * The structure version number for this code is major -0x00 minor -0x21.
+ * To get the definitions of the fields look at the SDMS4.0 bootrom include files
+ * ROMTYPES.H
+ * ROMPUBLC.H
+ * ROMSTRUC.H
+ * ROMSCAM.H
+ * ROMHW.H
+ * ROMBIOS.H
+
+ *
+#EndDescription
+ *
+ *-------------------------------------------------------------------------
+ *
+ * $Header: P:/VCS/WINNT/DULUTH/SYMNVM.H_v 1.1 29 Feb 1996 13:50:46 SDENNY $
+ *
+ */
+
+/* If this header file has not been included yet */
+#if ! defined SYMNVM_H
+#define SYMNVM_H
+
+/* Since all data structures must be byte aligned throughout this file, we
+ * issue the commands to perform that alignment once, and then restore the
+ * compilers default alignment at the end of this file.
+ */
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ * Non Volatile Memory types
+ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ */
+
+/* NVS_VERSION_MAJOR and NVS_VERSION_MINOR are #defined to the revision of the
+ * main data structure (NON_VOLATILE_SETTINGS) in this document.
+ */
+
+#define NVS_VERSION_MAJOR (0x00)
+#define NVS_VERSION_MINOR (0x30)
+
+#define BI_MAX_HBA 4
+#define HW_MAX_DEVICES 16
+#define HW_MAX_SCAM_DEVICES 4
+#define NVMDATAOFFSET 0x100
+
+#define DATA_MASK 0x01
+#define CLOCK_MASK 0x02
+
+#define FAILURE (0)
+#define SUCCESS (1)
+
+typedef enum _HEADER_TYPE
+{
+ HT_BOOT_ROM = 0,
+ HT_DOS_ASPI = 1,
+ HT_WINDOWS_ASPI = 2,
+ HT_NETWARE = 3,
+ HT_UNIXWARE = 4,
+ HT_SCO_UNIX = 5,
+ HT_WINDOWS_NT = 6,
+ HT_WINDOWS95 = 7,
+ HT_OS_2 = 8,
+ HT_SOLARIS = 9,
+ HT_INTERACTIVE = 10,
+ HT_NEXTSTEP = 11,
+ HT_END_MEMORY_BLOCK = 0xFEFE
+} HEADER_TYPE;
+
+typedef unsigned int UINT;
+typedef unsigned char UINT8;
+typedef unsigned int UINT16;
+typedef unsigned long UINT32;
+
+#define WIDE_NONE (8)
+#define WIDE_16 (16)
+#define WIDE_32 (32)
+#define WIDE_NO_CHANGE (0xFF)
+
+typedef UINT8 WIDE_PARAMETERS;
+typedef USHORT IO_ADDRESS;
+typedef UINT32 PHYS_ADDRESS;
+
+typedef USHORT HBA_FLAGS;
+#define HF_SCAM_ENABLED (0x0001)
+#define HF_PARITY_ENABLED (0x0002)
+#define HF_DISPLAY_VERBOSE_ENABLED (0x0004)
+#define HF_NO_NON_VOLATILE_MEMORY (0x0008)
+
+typedef UINT8 DEVICE_FLAGS;
+#define DF_DISCONNECT_ENABLED (0x01)
+#define DF_SCAN_ENABLED (0x02)
+#define DF_LUNS_ENABLED (0x04)
+#define DF_QT_ENABLED (0x08)
+#define DF_ALL_FEATURES_ENABLED (DF_DISCONNECT_ENABLED | DF_SCAN_ENABLED | \
+ DF_LUNS_ENABLED | DF_QT_ENABLED)
+
+typedef enum MEMORY_STATUS
+{
+ MS_GOOD = 0,
+ MS_ILLEGAL_ADDRESS,
+ MS_GENERAL_ERROR
+} MEMORY_STATUS;
+
+typedef enum _TERMINATION_STATE
+{
+ TS_CANT_PROGRAM = 0,
+ TS_ENABLED = 1,
+ TS_DISABLED = 2
+} TERMINATION_STATE;
+
+typedef enum _ADAPTER_TYPE
+{
+ AT_UNKNOWN = 0,
+ AT_400A = 1,
+ AT_406A = 2,
+ AT_416 = 3,
+ AT_8XX = 4
+} ADAPTER_TYPE;
+
+typedef struct _ADAPTER_IO_INFO
+{
+ USHORT RangeSize;
+ IO_ADDRESS IoBasePort;
+} ADAPTER_IO_INFO, * PTR_ADAPTER_IO_INFO;
+
+typedef struct _ADAPTER_MEMORY_INFO
+{
+ PHYS_ADDRESS PhyMemoryBase;
+ UINT8 *VirtMemoryBase;
+} ADAPTER_MEMORY_INFO, * PTR_ADAPTER_MEMORY_INFO;
+
+typedef struct _ADAPTER_416_INFO
+{
+ UINT32 DeviceId;
+ UINT32 SerialNumber;
+} ADAPTER_416_INFO, * PTR_ADAPTER_416_INFO;
+
+typedef struct _ADAPTER_8XX_INFO
+{
+ USHORT DeviceId;
+ USHORT VendorId;
+ UINT8 BusNumber;
+ UINT8 BusIndex;
+} ADAPTER_8XX_INFO, * PTR_ADAPTER_8XX_INFO;
+
+typedef union _ADAPTER_INFO
+{
+ ADAPTER_416_INFO Hba416;
+ ADAPTER_8XX_INFO Hba8xx;
+ ADAPTER_IO_INFO HbaIo;
+ ADAPTER_MEMORY_INFO HbaMemory;
+} ADAPTER_INFO, * PTR_ADAPTER_INFO;
+
+typedef enum _SCAN_ORDER
+{
+ SO_LOW_TO_HIGH = 0,
+ SO_HIGH_TO_LOW = 1
+} SCAN_ORDER;
+
+typedef enum _REMOVABLE_MEDIA
+{
+ RM_NO_SUPPORT = 0,
+ RM_BOOT_DEVICE_ONLY = 1,
+ RM_MEDIA_INSTALLED_ONLY = 2
+} REMOVABLE_MEDIA;
+
+typedef struct _HBA_INIT
+{
+ USHORT Type;
+ ADAPTER_INFO HbaInfo;
+ BOOLEAN InitStatus;
+ IO_ADDRESS IoPort;
+} HBA_INIT, * PTR_HBA_INIT;
+
+typedef struct _DEVICE_TABLE
+{
+ USHORT Flags; // 8 bits
+ UINT8 Reserved;
+ USHORT WideDataBits; // 8 bits
+ UINT8 SyncOffset;
+ USHORT SyncPeriodNs;
+ USHORT Timeout;
+} DEVICE_TABLE, * PTR_DEVICE_TABLE;
+
+typedef struct _SCAM_IDENTIFIER
+{
+ UINT8 DeviceType[ 2 ];
+ char VendorId[ 8 ];
+ char VendorSpecific[ 21 ];
+ UINT8 Reserved;
+} SCAM_IDENTIFIER, * PTR_SCAM_IDENTIFIER;
+
+typedef enum _SCAM_ID_METHOD
+{
+ SIM_DEFAULT_METHOD = 0,
+ SIM_DONT_ASSIGN = 1,
+ SIM_SET_SPECIFIC_ID = 2,
+ SIM_USE_ORDER_GIVEN = 3
+} SCAM_ID_METHOD;
+
+typedef enum _SCAM_STATUS
+{
+ SS_UNKNOWN = 0,
+ SS_DEVICE_NOT_FOUND = 1,
+ SS_ID_NOT_SET = 2,
+ SS_ID_VALID = 3
+} SCAM_STATUS;
+
+typedef struct _SCAM_TABLE
+{
+ USHORT ScamId;
+ USHORT HowToSetId;
+ USHORT ScamStatus;
+ UINT8 ScamTargetId;
+ UINT8 Reserved;
+} SCAM_TABLE, * PTR_SCAM_TABLE;
+
+typedef struct _NVM_HEADER
+{
+ USHORT Type;
+ USHORT Length;
+ USHORT CheckSum;
+} NVM_HEADER, * PTR_NVM_HEADER;
+
+typedef SCAM_TABLE NVM_SCAM_DATA;
+typedef PTR_SCAM_TABLE PTR_NVM_SCAM_DATA;
+
+
+typedef struct _NON_VOLATILE_SETTINGS
+{
+ UINT8 VersionMajor;
+ UINT8 VersionMinor;
+ UINT8 BootCrc[4]; // changed def. to match our compiler
+ USHORT HbaFlags;
+ USHORT ScanOrder;
+ USHORT TerminatorState;
+ USHORT RemovableMediaSetting;
+ UINT8 HostScsiId;
+ UINT8 NumHba;
+ UINT8 NumDevices;
+ UINT8 MaxScamDevices;
+ UINT8 NumValidScamDevices;
+ UINT8 Reserved;
+ HBA_INIT HbaInit[ BI_MAX_HBA ];
+ DEVICE_TABLE DeviceTable[ HW_MAX_DEVICES ];
+ NVM_SCAM_DATA ScamTable[ HW_MAX_SCAM_DEVICES ];
+ UINT8 freespace[1024]; // this added by NT so we can read past end
+ // of the NVRAM structure to get all data
+ // used for checksum
+
+} NON_VOLATILE_SETTINGS, * PTR_NON_VOLATILE_SETTINGS;
+
+
+/* Define some macros to access the offsets of particular portions of this
+ * data structure. These macros are then used to allow the code to more
+ * easily program only those parts of non-volatile memory which might have
+ * changed when the user issues a set NVM call.
+ */
+
+#define NVS_ADAPTER_BEGIN (offsetof(struct _NON_VOLATILE_SETTINGS, HbaFlags))
+#define NVS_ADAPTER_END (offsetof(struct _NON_VOLATILE_SETTINGS, \
+ DeviceTable[ 0 ]))
+#define NVS_ADAPTER_LENGTH (NVS_ADAPTER_END - NVS_ADAPTER_BEGIN)
+
+#define NVS_DEVICE_BEGIN(x) (offsetof(struct _NON_VOLATILE_SETTINGS, \
+ DeviceTable[(x)]))
+#define NVS_DEVICE_END(x) (offsetof(struct _NON_VOLATILE_SETTINGS, \
+ DeviceTable[(x)+1]))
+#define NVS_DEVICE_LENGTH (sizeof( DEVICE_TABLE ))
+
+#if HW_MAX_SCAM_DEVICES != 0
+ #define NVS_SCAM_BEGIN (offsetof(struct _NON_VOLATILE_SETTINGS, \
+ ScamTable[0]))
+ #define NVS_SCAM_END (sizeof(NON_VOLATILE_SETTINGS))
+ #define NVS_SCAM_LENGTH (NVS_SCAM_END - NVS_SCAM_BEGIN)
+#endif
+
+/* NVM_DATA_SIZE defines the number of bytes of data we need to access the
+ * NVM header structure and the NVM data structure for our ROM.
+ */
+
+#define NVM_DATA_SIZE (sizeof(NVM_HEADER) + sizeof(NON_VOLATILE_SETTINGS))
+
+/* We are now done with the requirement of forcing byte alignment on all
+ * elements so restore the compilers default structure alignment.
+ */
+
+#endif /* End of if SYMNVM_H */
+
diff --git a/private/ntos/miniport/symbios/symc810/symscam.h b/private/ntos/miniport/symbios/symc810/symscam.h
new file mode 100644
index 000000000..2b65c33d3
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/symscam.h
@@ -0,0 +1,107 @@
+/************************************************************************
+* *
+* Copyright 1994 Symbios Logic Inc. All rights reserved. *
+* *
+* This file is confidential and a trade secret of Symbios Logic Inc. *
+* The receipt of or possession of this file does not convey any *
+* rights to reproduce or disclose its contents or to manufacture, *
+* use, or sell anything is may describe, in whole, or in part, *
+* without the specific written consent of Symbios Logic Inc. *
+* *
+************************************************************************/
+
+/*+++HDR
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Who? Description
+ * -------- ---- -------------------------------------------------------
+ *
+ *
+---*/
+
+
+#ifndef _SYMSCAM_
+#define _SYMSCAM_
+
+
+
+
+
+/************************/
+/* SCAM data structures */
+/************************/
+
+/* TC1_TC2_VENDOR__VENDOR_UNIQUE________ */
+static CHAR our_scam_id_str[]= {"\045\007SYM SDMS SCAMCore - Alpha"};
+
+typedef struct _SIOP_REG_STORE { // storage to save/restore SIOP state
+ UCHAR reg_st[21]; // used by AdapterState and SCAM
+ ULONG long_st;
+} SIOP_REG_STORE, *PSIOP_REG_STORE;
+
+/************************/
+/* SCAM definitions */
+/************************/
+
+#define Ent_fragmovefirstin 0
+#define Ent_fragmovelastin 8
+#define INSTRUCT 1
+#define ISOLATED 0
+#define NOBODY_HOME -1
+
+#define QUINTET_MASK 0x1F
+#define SCAM_SYNC 0x1F
+#define SCAM_ASSIGN_ID 0x00
+#define SCAM_SET_PRIO 0x01
+#define SCAM_SET_ID_00 0x18
+#define SCAM_SET_ID_01 0x11
+#define SCAM_SET_ID_10 0x12
+#define SCAM_SET_ID_11 0x0B
+
+#define ASSIGNABLE_ID 0x80
+#define DEFER 0x01
+#define STOP 0x02
+
+#define SCAM_ID_STRLEN 0x20
+#define SCAM_DEFERRED -1
+#define SCAM_TERMINATED -2
+
+#define MSG_NOOP 0x08
+#define MSG_RESET 0x0C
+
+#define ARB_IN_PROGRESS 0x10
+#define CONNECTED 0x08
+
+/* Timer value for HTH/SEL/GEN timers for short timeout */
+/* 0x05 is 1.6mS which is comfortably between the 1 & 4 */
+/* mS times for SCAM tolerant vs SCAM compliant. */
+#define SHORT_720_STO 0x05
+#define DISABLE_720_STO 0x00
+
+#define IO 0x01
+#define CD 0x02
+#define MSG 0x04
+#define ATN 0x08
+#define SEL 0x10
+#define BSY 0x20
+#define ACK 0x40
+#define REQ 0x80
+
+/* SBCL phases */
+#define PHASE_MASK (MSG & CD & IO)
+#define DATA__OUT (~MSG & ~CD & ~IO)
+#define DATA__IN (~MSG & ~CD & IO)
+#define COMMAND (~MSG & CD & ~IO)
+#define STATUS (~MSG & CD & IO)
+#define MESSAGE_OUT (MSG & CD & ~IO)
+#define MESSAGE_IN (MSG & CD & IO)
+#define PHASE (READ_SIOP_UCHAR(SBCL) & PHASE_MASK)
+
+#define DB5 0x20
+#define DB6 0x40
+#define DB7 0x80
+
+#endif
+
diff --git a/private/ntos/miniport/symbios/symc810/symsiop.h b/private/ntos/miniport/symbios/symc810/symsiop.h
new file mode 100644
index 000000000..15b67c09a
--- /dev/null
+++ b/private/ntos/miniport/symbios/symc810/symsiop.h
@@ -0,0 +1,452 @@
+/************************************************************************
+* *
+* Copyright 1994 Symbios Logic Inc. All rights reserved. *
+* *
+* This file is confidential and a trade secret of Symbios Logic Inc. *
+* The receipt of or possession of this file does not convey any *
+* rights to reproduce or disclose its contents or to manufacture, *
+* use, or sell anything is may describe, in whole, or in part, *
+* without the specific written consent of Symbios Logic Inc. *
+* *
+************************************************************************/
+
+/*+++HDR
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Who? Description
+ * -------- ---- -------------------------------------------------------
+ * 1-16-96 SPD Added define for new ISR disposition
+ *
+---*/
+
+
+#ifndef _SYMSIOP_
+#define _SYMSIOP_
+
+//
+// Define miniport constants.
+//
+
+#define MAX_SYNCH_TABLE_ENTRY 8 // # of entries in synch period array
+#define ASYNCHRONOUS_MODE_PARAMS 0x00 // asychronous xfer mode
+#define MAX_SG_ELEMENTS 18 // max # of page breaks + 1
+#define MAX_ABORT_TRIES 100 // max times we will try to abort script
+#define ABORT_STALL_TIME 3 // stall time between script abort tries
+#define MAX_SYNCH_OFFSET 0x08 // max synchronous offset supported
+#define MAX_875_SYNCH_OFFSET 0x10 // 875 larger sync offset
+#define ENABLE_WIDE 0x08 // enable wide scsi
+#define MAX_PHYS_BREAK_COUNT 18 // Max # of S/G elements
+#define MESSAGE_BUFFER_SIZE 8 // maximum message size
+#define RESET_STALL_TIME 30 // length of time bus reset line high
+#define POST_RESET_STALL_TIME 1000 // drive recovery time after reset
+#define CLEAR_FIFO_STALL_TIME 500 // Time to clear SCSI and DMA fifos
+#define MAX_CLEAR_FIFO_LOOP 10 // Number of times in clear loop
+#define SYM_MAX_TARGETS 16
+#define SYM_NARROW_MAX_TARGETS 8
+
+//#define ADAPTER_CRYSTAL_SPEED 40 // adapter crystal speed
+//#define DCNTL_DIVIDE_FACTOR 2 // crystal divide factor set in DCNTL
+ // register (see 53c8xx data manual)
+#define MAX_XFER_LENGTH 0x00FFFFFF // maximum transfer length per request
+// speed at which SIOP is clocked...
+//#define SIOP_CLOCK_SPEED (ADAPTER_CRYSTAL_SPEED / DCNTL_DIVIDE_FACTOR)
+
+//
+// SCSI equates and flags not included in SCSI.H
+// TODO: Rework code to omit these
+//
+
+#define SCSIMESS_IDENTIFY_DISC_PRIV_MASK 0x40
+#define SCSIMESS_IDENTIFY_LUN_MASK 0x07
+#define DSPS_RESELOP 0x80
+
+#define CTEST3_CLEAR_FIFO 0x04
+#define CTEST3_FLUSH_FIFO 0x08
+#define CTEST5_USE_LARGE_FIFO 0x20
+#define CTEST5_BURST 0x04
+
+#define DCMD_WAIT_DISCONNECT 0x48
+#define SSTAT1_ORF 0x40
+#define SSTAT1_OLF 0x20
+#define SSTAT2_ORF 0x40
+#define SSTAT2_OLF 0x20
+#define SBCL_MSG 0x04
+#define DFIFO_LOW_SEVEN 0x7F
+
+//
+// Retry limits.
+//
+
+#define MAX_SELECTION_RETRIES 1
+
+//
+// Symbios Logic 53C8xx script interrupt definitions. These values are returned in the
+// DSPS register when a script routine completes.
+//
+
+#define SCRIPT_INT_COMMAND_COMPLETE 0x00 // SCSI command complete
+#define SCRIPT_INT_SAVE_DATA_PTRS 0x01 // save data ptrs
+#define SCRIPT_INT_SAVE_WITH_DISCONNECT 0x02 // combination SDP & disconnect
+#define SCRIPT_INT_DISCONNECT 0x03 // disconnect from SCSI bus
+#define SCRIPT_INT_RESTORE_POINTERS 0x04 // restore data pointers
+#define SCRIPT_INT_SCRIPT_ABORTED 0x05 // SCSI script aborted
+#define SCRIPT_INT_TAG_RECEIVED 0x06 // Queue tag message recieved
+#define SCRIPT_INT_DEV_RESET_OCCURRED 0x07 // indicates device was reset
+ // due to wierd phase
+#define SCRIPT_INT_DEV_RESET_FAILED 0x08 // indicates above effort
+ // failed
+#define SCRIPT_INT_IDE_MSG_SENT 0x0A // initiator detected error
+#define SCRIPT_INT_SYNC_NOT_SUPP 0x0B // synchronous not supported
+#define SCRIPT_INT_SYNC_NEGOT_COMP 0x0C // synchronous neg complete
+#define SCRIPT_INT_WIDE_NOT_SUPP 0x1B // synchronous not supported
+#define SCRIPT_INT_WIDE_NEGOT_COMP 0x1C // synchronous neg complete
+#define SCRIPT_INT_INVALID_RESELECT 0x0D // reselecting device returned
+ // invalid SCSI id.
+#define SCRIPT_INT_REJECT_MSG_RECEIVED 0x0E // message reject msg received
+#define SCRIPT_INT_INVALID_TAG_MESSAGE 0x0F // target did not send tag
+#define SCRIPT_INT_ABORT_OCCURRED 0x10
+#define SCRIPT_INT_ABORT_FAILED 0x11
+
+
+//
+// define 53C810 SCSI Script instruction size
+//
+
+#define SCRIPT_INS_SIZE 8 // size of a script instruction
+
+//
+// ISR disposition codes. these codes are returned by ISR subroutines to
+// indicate what should be done next.
+//
+
+#define ISR_START_NEXT_REQUEST 0x00 // indicates bus is free for new req.
+#define ISR_RESTART_SCRIPT 0x01 // indicates script restart necessary
+#define ISR_EXIT 0x02 // indicates no action needed
+#define ISR_CONT_NEG_SCRIPT 0x03 // indicates to continue with Synch
+ // negotiations after wide
+ // negotiations have completed
+
+//
+// Device Extension driver flags.
+//
+
+#define DFLAGS_WORK_REQUESTED 0x01 // indicates new work has been requested.
+ // this flag was necessary because
+ // NextRequest port notification is not
+ // reentrant
+
+#define DFLAGS_BUS_RESET 0x02 // indicates SCSI bus was reset internally
+
+#define DFLAGS_SCRIPT_RUNNING 0x04 // indicates SCSI scripts processor running
+ // this flag does NOT indicate bus busy.
+ // (used in conjunction with WAIT
+ // RESELECT script instruction which runs
+ // when bus is not busy)
+
+#define DFLAGS_CONNECTED 0x08 // indicate that a lun is currently
+ // connected, but is not active.
+
+#define DFLAGS_TAGGED_SELECT 0x10 // The last select was for a tagged command.
+
+#define DFLAGS_DIFF_SCSI 0x40 // indicates that this SIOP should be
+ // configured to support differential
+ // SCSI devices
+
+#define DFLAGS_IRQ_NOT_CONNECTED 0x80 // Indicates that the chip is 'disabled' but resources
+ // were still assigned. (Omniplex problem)
+
+//
+// Logical Unit Extension flags.
+//
+
+#define LUFLAGS_SYNC_NEGOT_PEND 0x0001 // synch negot in prog.
+#define LUFLAGS_SYNC_NEGOT_DONE 0x0002 // synch negot done
+#define LUFLAGS_SYNC_NEGOT_FAILED 0x0004 // synch not supp.
+
+//
+// Future wide...
+//
+
+#define LUFLAGS_WIDE_NEGOT_PEND 0x0010 // wide negot in prog.
+#define LUFLAGS_WIDE_NEGOT_DONE 0x0020 // wide negot done
+#define LUFLAGS_WIDE_NEGOT_FAILED 0x0040 // wide not supp.
+#define LUFLAGS_WIDE_NEGOT_CHECK 0x0080 // need to check inquiry data
+
+#define LUFLAGS_WIDE_NEGOT_MASK 0xFF0F // mask for wide flags
+
+#define LUFLAGS_ASYNC_NEGOT_PEND 0x0100 // asynch negot in prog.
+#define LUFLAGS_ASYNC_NEGOT_DONE 0x0200 // asynch negot done.
+#define LUFLAGS_NARROW_NEGOT_PEND 0x0400 // narrow negot in prog.
+#define LUFLAGS_NARROW_NEGOT_DONE 0x0800 // narrow negot done.
+
+
+#define HBA_CAPABILITY_WIDE 0x01
+#define HBA_CAPABILITY_DIFFERENTIAL 0x02
+#define HBA_CAPABILITY_FAST20 0x04
+#define HBA_CAPABILITY_REGISTRY_FAST20 0x08
+#define HBA_CAPABILITY_SYNC_16 0x10
+#define HBA_CAPABILITY_810_FAMILY 0x20
+#define HBA_CAPABILITY_825_FAMILY 0x40
+#define HBA_CAPABILITY_875_LARGE_FIFO 0x80
+#define HBA_CAPABILITY_SCRIPT_RAM 0x100
+#define HBA_CAPABILITY_875_FAMILY 0x200
+
+//
+// Inquiry data representing the capabilities of the SCSI peripheral.
+//
+
+#define INQUIRY_DATA_SYNC_SUPPORTED 0x10
+#define INQUIRY_DATA_WIDE_SUPPORTED 0x20
+#define INQUIRY_DATA_TAGS_SUPPORTED 0x02
+
+//
+// SCSI Protocol Chip Definitions.
+//
+
+//
+// Define the SCSI Control Register 0 bit equates
+//
+
+#define SCNTL0_ARB_MODE_1 0x80
+#define SCNTL0_ARB_MODE_0 0x40
+#define SCNTL0_ENA_PARITY_CHK 0x08
+
+#define SCNTL0_ASSERT_ATN_PAR 0x02
+#define SCNTL0_TAR 0x01
+
+//
+// Define the SCSI Control Register 1 bit equates
+//
+
+#define SCNTL1_EXT_CLK_CYC 0x80
+#define SCNTL1_SODLTOSCSI 0x40
+
+#define SCNTL1_CONNECTED 0x10
+#define SCNTL1_RESET_SCSI_BUS 0x08
+
+//
+// Define the SCSI Control Register 2 bit equates
+//
+
+#define SCNTL2_WSS 0x08
+#define SCNTL2_WSR 0x01
+
+//
+// Define the SCSI Interrupt Enable register bit equates
+//
+
+#define SIEN0_PHASE_MISMATCH 0x80
+#define SIEN0_FUNCTION_COMP 0x40
+
+#define SIEN0_RESELECT 0x10
+#define SIEN0_SCSI_GROSS_ERROR 0x08
+#define SIEN0_UNEXPECTED_DISCON 0x04
+#define SIEN0_RST_RECEIVED 0x02
+#define SIEN0_PARITY_ERROR 0x01
+
+//
+// Define the DMA Status Register bit equates
+//
+
+#define DSTAT_ILLEGAL_INSTRUCTION 0x01
+#define DSTAT_ABORTED 0x10
+#define DSTAT_SCRPTINT 0x04
+
+//
+// Define the SCSI Status Register 0 bit equates
+//
+
+#define SSTAT0_PHASE_MISMATCH 0x80
+#define SSTAT0_RESELECTED 0x10
+#define SSTAT0_GROSS_ERROR 0x08
+#define SSTAT0_UNEXPECTED_DISCONNECT 0x04
+#define SSTAT0_RESET 0x02
+#define SSTAT0_PARITY_ERROR 0x01
+
+//
+// Define the Interrupt Status Register bit equates
+//
+
+#define ISTAT_ABORT 0x80
+#define ISTAT_RESET 0x40
+#define ISTAT_SIGP 0x20
+#define ISTAT_SEM 0x10
+#define ISTAT_CON 0x08
+#define ISTAT_INTF 0x04
+#define ISTAT_SCSI_INT 0x02
+#define ISTAT_DMA_INT 0x01
+
+//
+// Define the DMA Mode Register bit equates
+//
+
+#define DMODE_BURST_1 0x80
+#define DMODE_BURST_0 0x40
+
+//
+// Define the DMA Interrupt Enable Register bit equates
+//
+#define DIEN_BUS_FAULT 0x20
+#define DIEN_ENA_ABRT_INT 0x10
+#define DIEN_ENA_SNGL_STP_INT 0x08
+#define DIEN_ENABLE_INT_RCVD 0x04
+#define DIEN_ENABLE_ILL_INST 0x01
+
+//
+// Define the SIST1 equates. SCSI Interrupt Status 1.
+//
+
+#define SIST1_SEL_RESEL_TIMEOUT 0x04
+
+//
+// Define STEST1 equates
+//
+
+#define STEST1_DOUBLER_SELECT 0x04
+#define STEST1_DOUBLER_ENABLE 0x08
+
+//
+// Define STEST2 equates
+//
+
+#define STEST2_DIFF_MODE 0x20
+
+//
+// Define STEST3 equates
+//
+
+#define STEST3_HALT_CLOCK 0x20
+
+//
+// Define GPCNTL equates
+//
+
+#define GPCNTL_GPIO3 0x08
+
+
+//
+// Define specific script instruction structures
+//
+
+//
+// Define the scatter/gather move script instruction
+//
+
+typedef struct _SCRIPTSG {
+ ULONG SGByteCount;
+ ULONG SGBufferPtr;
+} SCRIPTSG, *PSCRIPTSG;
+
+//
+// Define the structure for the CDB move script instruction
+//
+
+typedef struct _SCRIPTCDB {
+ UCHAR CDBLength;
+ UCHAR Reserved1;
+ UCHAR Reserved2;
+ UCHAR CDBMoveOpcode;
+ ULONG CDBBufferPtr;
+} SCRIPTCDB, *PSCRIPTCDB;
+
+//
+// Define the structure for the SELECT script instruction
+//
+
+typedef struct _SCRIPTSELECT {
+ UCHAR Reserved1;
+ UCHAR Reserved2;
+ UCHAR SelectID;
+ UCHAR SelectOpcode;
+ ULONG AltAddress;
+} SCRIPTSELECT, *PSCRIPTSELECT;
+
+//
+// Define the structure for the JUMP script instruction
+//
+
+typedef struct _SCRIPTJUMP {
+ ULONG JumpOpcode;
+ ULONG JumpAddress;
+} SCRIPTJUMP, *PSCRIPTJUMP;
+
+//
+// Build a composite script instruction structure
+//
+
+typedef union _SCRIPTINS {
+ SCRIPTCDB ScriptCDB;
+ SCRIPTSELECT ScriptSelect;
+ SCRIPTJUMP ScriptJump;
+ SCRIPTSG ScriptSG;
+} SCRIPTINS, *PSCRIPTINS;
+
+//
+// SDTR extended message structure used by scsi scripts
+//
+
+typedef struct SYNCH_MESSAGE_STRUCT {
+ UCHAR ExtMsg;
+ UCHAR ExtMsgCount;
+ UCHAR SynchMsgOpcode;
+ UCHAR OurSynchPeriod;
+ UCHAR OurSynchOffset;
+} SYNCHMESSAGESTRUCT, *PSYNCHMESSAGESTRUCT;
+
+//
+// Symbios SIOP I/O macros.
+//
+
+#ifdef PORT_IO // either driver can use Port IO
+#define READ_SIOP_UCHAR(RegisterOffset) \
+ (ScsiPortReadPortUchar( &(DeviceExtension-> \
+ SIOPRegisterBase)->RegisterOffset)) \
+
+
+#define WRITE_SIOP_UCHAR(RegisterOffset, BitMask) \
+{ \
+ ScsiPortWritePortUchar( &(DeviceExtension-> \
+ SIOPRegisterBase)->RegisterOffset, \
+ BitMask); \
+}
+
+#define READ_SIOP_ULONG(RegisterOffset) \
+ (ScsiPortReadPortUlong( &(DeviceExtension-> \
+ SIOPRegisterBase)->RegisterOffset)) \
+
+
+#define WRITE_SIOP_ULONG(RegisterOffset, BitMask) \
+{ \
+ ScsiPortWritePortUlong( &(DeviceExtension-> \
+ SIOPRegisterBase)->RegisterOffset, \
+ BitMask); \
+}
+#else // NT will use Memory Mapped IO
+#define READ_SIOP_UCHAR(RegisterOffset) \
+ (ScsiPortReadRegisterUchar( &(DeviceExtension-> \
+ SIOPRegisterBase)->RegisterOffset)) \
+
+
+#define WRITE_SIOP_UCHAR(RegisterOffset, BitMask) \
+{ \
+ ScsiPortWriteRegisterUchar( &(DeviceExtension-> \
+ SIOPRegisterBase)->RegisterOffset, \
+ BitMask); \
+}
+
+#define READ_SIOP_ULONG(RegisterOffset) \
+ (ScsiPortReadRegisterUlong( &(DeviceExtension-> \
+ SIOPRegisterBase)->RegisterOffset)) \
+
+
+#define WRITE_SIOP_ULONG(RegisterOffset, BitMask) \
+{ \
+ ScsiPortWriteRegisterUlong( &(DeviceExtension-> \
+ SIOPRegisterBase)->RegisterOffset, \
+ BitMask); \
+}
+#endif
+
+#endif
diff --git a/private/ntos/miniport/trantor/dirs b/private/ntos/miniport/trantor/dirs
new file mode 100644
index 000000000..d79c05a00
--- /dev/null
+++ b/private/ntos/miniport/trantor/dirs
@@ -0,0 +1,25 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=winnt
+
+
diff --git a/private/ntos/miniport/trantor/include/card.h b/private/ntos/miniport/trantor/include/card.h
new file mode 100644
index 000000000..8213bf435
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/card.h
@@ -0,0 +1,58 @@
+//-----------------------------------------------------------------------
+//
+// CARD.H
+//
+// Functions exported from the lower level driver. These functions
+// are in the cardtxxx.c files.
+//
+// Only these routines may be accessed from a given cardtxxx.lib file
+// for a given operating system.
+//
+// To use these routines, include TYPEDEFS.H, STATUS.H before this file.
+//
+// Revisions:
+// 03-22-93 KJB First.
+// 03-25-93 JAP Comment changes only.
+// 03-26-93 JAP Fixed up prototype typedef inconsistencies
+// 04-22-93 JAP Added CardGetIRQ() prototype.
+// 05-12-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters. Auto Request Sense is
+// now supported.
+// 05-14-93 KJB CardCheckAdapter now takes only two parameters:
+// PWORKSPACE and PINIT. The baseIoAddress is inside
+// the PINIT structure and must be filled.
+// 05-17-93 KJB Fixed CardParseCommandString parameter warning.
+//
+//-----------------------------------------------------------------------
+
+//
+// Functions
+//
+
+PBASE_REGISTER CardAddress (USHORT i);
+USHORT CardNumberOfAddressRanges (VOID);
+ULONG CardMaxTransferSize (VOID);
+BOOLEAN CardAddressRangeInIoSpace (VOID);
+USHORT CardAddressRangeLength (VOID);
+BOOLEAN CardSupportsInterrupts (VOID);
+UCHAR CardDefaultInterruptLevel (VOID);
+USHORT CardStartCommandInterrupt (PTSRB t);
+USHORT CardFinishCommandInterrupt (PTSRB t);
+USHORT CardDoCommand (PTSRB t);
+BOOLEAN CardCheckAdapter (PWORKSPACE w, PINIT init);
+BOOLEAN CardInterrupt (PWORKSPACE w);
+VOID CardResetBus (PWORKSPACE w);
+PUCHAR CardGetName (VOID);
+PUCHAR CardGetShortName (VOID);
+UCHAR CardGetType (VOID);
+USHORT CardGetIRQ (USHORT i);
+USHORT CardGetWorkspaceSize (VOID);
+BOOLEAN CardParseCommandString (PINIT init, PCHAR str);
+
diff --git a/private/ntos/miniport/trantor/include/cardlib.h b/private/ntos/miniport/trantor/include/cardlib.h
new file mode 100644
index 000000000..6d40acdf4
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardlib.h
@@ -0,0 +1,29 @@
+//-----------------------------------------------------------------------
+//
+// CARDLIB.H
+//
+// Generic Library Access File
+//
+// Only these routines may be accessed from a given cardtxxx.lib file
+// for a given operating system.
+//
+// Only this file --CARDLIB.H-- and the cardtxxx.lib file should be used
+// to build an application or driver.
+//
+// Revisions:
+//
+// 03-22-93 KJB First.
+//
+//-----------------------------------------------------------------------
+
+// General typedefs
+
+#include "typedefs.h"
+
+// Return status codes for all SHORT functions
+
+#include "status.h"
+
+// Functions that are exported...
+
+#include "card.h"
diff --git a/private/ntos/miniport/trantor/include/cardt128.h b/private/ntos/miniport/trantor/include/cardt128.h
new file mode 100644
index 000000000..4aa120385
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardt128.h
@@ -0,0 +1,108 @@
+#ifndef _CARDT128_H
+#define _CARDT128_H
+
+//-----------------------------------------------------------------------
+//
+// CARDT128.H
+//
+// T128 Adapter Definitions File
+//
+// Revision History:
+// 09-01-92 KJB First.
+// 03-05-93 JAP Cleaned comments, modified string in CardGetName()
+// to conform to ASM Driver names.
+// NOTE: This file was dated 03-04-93, but with no
+// corresponding Revision History log.
+// 03-08-93 JAP Added CardGetShortName() to conform to c_name
+// returned in ASM-Drivers.
+// 03-09-93 JAP Added CardGetType() function and included cardtype.h
+// 03-23-93 KJB Reorged for functional library interface.
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+//
+//-----------------------------------------------------------------------
+
+// include general os definitions
+
+#include "osdefs.h"
+
+//
+// Global per Adapter Information
+//
+typedef struct tagAdapterInfo {
+
+ PBASE_REGISTER BaseIoAddress; // address of this card
+
+} ADAPTER_INFO, FARP PADAPTER_INFO;
+
+// they have an n5380
+
+#include "n5380.h"
+
+
+// all 5380 type cards use the scsifnc module
+
+#include "scsifnc.h"
+
+
+// all port access routines
+
+#include "portmem.h"
+
+
+// the t128 specific file
+
+#include "t128.h"
+
+
+// CARDTYPE definitions file
+
+#include "cardtype.h"
+
+// include exported function definitions
+
+#include "card.h"
+
+//-----------------------------------------------------------------------
+//
+// Redefined routines
+//
+//-----------------------------------------------------------------------
+
+// Routines used by T128.c
+
+#define T128PortTest(g, reg, mask) \
+ PortMemTest(&((PUCHAR)g->BaseIoAddress)[reg],mask)
+
+#define T128PortSet(g, reg, mask) \
+ PortMemSet(&((PUCHAR)g->BaseIoAddress)[reg],mask);
+
+#define T128PortClear(g, reg, mask) \
+ PortMemClear(&((PUCHAR)g->BaseIoAddress)[reg],mask);
+
+#define T128PortPut(g,reg,byte) \
+ PortMemPut(&((PUCHAR)g->BaseIoAddress)[reg],byte);
+
+#define T128PortGet(g,reg,byte) \
+ PortMemGet(&((PUCHAR)g->BaseIoAddress)[reg],byte);
+
+//
+// Other Routines
+//
+#define CardReadBytesFast T128ReadBytesFast
+#define CardWriteBytesFast T128WriteBytesFast
+#define CardWriteBytesCommand ScsiWriteBytesSlow
+
+//
+// Local routines (to the whole lower level driver)
+//
+VOID CardEnableInterrupt (PADAPTER_INFO g);
+VOID CardDisableInterrupt (PADAPTER_INFO g);
+
+#endif // _CARDT128_H
diff --git a/private/ntos/miniport/trantor/include/cardt13b.h b/private/ntos/miniport/trantor/include/cardt13b.h
new file mode 100644
index 000000000..e287ee5d0
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardt13b.h
@@ -0,0 +1,149 @@
+#ifndef _CARDT13B_H
+#define _CARDT13B_H
+
+//-----------------------------------------------------------------------
+//
+// CARD.H
+//
+// T13B Adapter Definitions File
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 03-05-93 JAP Cleaned comments, modified string in CardGetName()
+// to conform to ASM Driver names.
+// NOTE: This file was dated 03-03-93, but with no
+// corresponding Revision History log.
+// 03-08-93 JAP Added CardGetShortName() to conform to c_name
+// returned in ASM-Drivers.
+// 03-09-93 JAP Added CardGetType() function and included cardtype.h
+// 03-22-93 KJB Reorged for functional library interface.
+// 03-26-93 JAP Added CARDIOPORTLEN to define number of I/O ports
+// the card uses. Used for NOVELL builds only.
+// 04-01-93 KJB Moved N53C400 register offsets into here from
+// n53c400.h.
+// 05-05-93 KJB Added definition of T13B_SWITCH register.
+// 05-13-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters.
+// 05-14-93 KJB CardCheckAdapter now does not take a PBASE_REGISTER
+// parameter, this parameter is now in the PINIT
+// structure.
+//
+//-----------------------------------------------------------------------
+
+// include general os definitions
+
+#include "osdefs.h"
+
+//
+// Global per Adapter Information
+//
+typedef struct tagAdapterInfo {
+
+ PBASE_REGISTER BaseIoAddress; // address of this card
+
+} ADAPTER_INFO, FARP PADAPTER_INFO;
+
+// they have an n5380
+
+#include "n5380.h"
+
+//
+// 53c400 register offsets from 53c400 base
+//
+
+#define N53C400_CONTROL 0
+#define N53C400_STATUS 0
+#define N53C400_COUNTER 1
+#define T13B_SWITCH 2
+#define N53C400_HOST_BFR 4
+#define N53C400_5380 8
+
+// all of these cards have a 53c400
+
+#include "n53c400.h"
+
+// all 5380 type cards use the scsifnc module
+
+#include "scsifnc.h"
+
+// use generic port io routines
+
+#include "portio.h"
+
+// type of cards
+
+#include "cardtype.h"
+
+// include exported function definitions
+
+#include "card.h"
+
+
+//-----------------------------------------------------------------------
+//
+// Definitions
+//
+//-----------------------------------------------------------------------
+
+//-----------------------------------------------------------------------
+// For Novell, we need #define for number of I/O ports the card uses.
+//-----------------------------------------------------------------------
+ #ifdef NOVELL
+#define CARDIOPORTLEN 16 // number of IO ports in card
+ #endif
+
+
+//-----------------------------------------------------------------------
+//
+// Redefined Functions
+//
+//-----------------------------------------------------------------------
+
+// These are card specific routines, but since this card has a 5380, we
+// will redefine these to the generic n5380 or other routines.
+
+#define CardWriteBytesCommand CardWriteBytesFast
+#define CardReadBytesFast N53C400ReadBytesFast
+#define CardWriteBytesFast N53C400WriteBytesFast
+
+// the N53C400.C module needs access to the IO ports, PortIO provides this
+
+#define N53C400PortTest(g, reg, mask) \
+ PortIOTest(&((PUCHAR)g->BaseIoAddress)[reg],mask)
+
+#define N53C400PortSet(g, reg, mask) \
+ PortIOSet(&((PUCHAR)g->BaseIoAddress)[reg],mask);
+
+#define N53C400PortClear(g, reg, mask) \
+ PortIOClear(&((PUCHAR)g->BaseIoAddress)[reg],mask);
+
+#define N53C400PortPut(g,reg,byte) \
+ PortIOPut(&((PUCHAR)g->BaseIoAddress)[reg],byte);
+
+#define N53C400PortGet(g,reg,byte) \
+ PortIOGet(&((PUCHAR)g->BaseIoAddress)[reg],byte);
+
+#define N53C400PortGetBuffer(g, reg, buffer, len) \
+ ScsiPortReadPortBufferUshort ( \
+ (PUSHORT)&(((PUCHAR)g->BaseIoAddress)[reg]), \
+ (PUSHORT)buffer, len/2);
+
+#define N53C400PortPutBuffer(g, reg, buffer, len) \
+ ScsiPortWritePortBufferUshort ( \
+ (PUSHORT)&(((PUCHAR)g->BaseIoAddress)[reg]), \
+ (PUSHORT)buffer, len/2);
+
+//
+// Local routines (to the whole lower level driver)
+//
+VOID CardEnableInterrupt (PADAPTER_INFO g);
+VOID CardDisableInterrupt (PADAPTER_INFO g);
+
+#endif // _CARDT13B_H
diff --git a/private/ntos/miniport/trantor/include/cardt160.h b/private/ntos/miniport/trantor/include/cardt160.h
new file mode 100644
index 000000000..9d13a6617
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardt160.h
@@ -0,0 +1,133 @@
+#ifndef _CARDT160_H
+#define _CARDT160_H
+
+//-----------------------------------------------------------------------
+//
+// CARDT160.H
+//
+// T160 Adapter Definitions File
+//
+// Revisions:
+// 02-24-92 KJB First.
+// 03-05-93 JAP Cleaned comments, modified string in CardGetName()
+// to conform to ASM Driver names.
+// NOTE: This file was dated 03-04-93, but with no
+// corresponding Revision History log.
+// 03-08-93 JAP Added CardGetShortName() to conform to c_name
+// returned in ASM-Drivers.
+// 03-09-93 JAP Added CardGetType() function and included cardtype.h
+// 03-10-93 KJB Changed default interrupt to 12
+// 03-24-93 KJB Reorged for functional library interface.
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+//
+//-----------------------------------------------------------------------
+
+
+// include general os definitions
+
+#include "osdefs.h"
+
+
+//
+// Global per Adapter Information
+//
+typedef struct tagAdapterInfo {
+
+ PBASE_REGISTER BaseIoAddress; // address of this card
+
+} ADAPTER_INFO, FARP PADAPTER_INFO;
+
+// they have an n5380
+
+#include "n5380.h"
+
+// all of these cards have a pc9010
+
+#include "pc9010.h"
+
+
+// all 5380 type cards use the scsifnc module
+
+#include "scsifnc.h"
+
+
+// io routines to the io ports
+
+#include "portio.h"
+
+
+// CARDTYPE definitions file
+
+#include "cardtype.h"
+
+
+// include exported function definitions
+
+#include "card.h"
+
+//-----------------------------------------------------------------------
+//
+// Definitions
+//
+//-----------------------------------------------------------------------
+
+//-----------------------------------------------------------------------
+//
+// Redefined Functions
+//
+//-----------------------------------------------------------------------
+
+#define CardReadBytesFast PC9010ReadBytesFast
+#define CardWriteBytesFast PC9010WriteBytesFast
+#define CardWriteBytesCommand CardWriteBytesFast
+
+// the PC9010.C module needs access to the IO ports, PortIO provides this
+
+#define PC9010PortTest(g, reg, mask) \
+ PortIOTest(&((PUCHAR)(g->BaseIoAddress))[reg],mask)
+
+#define PC9010PortSet(g, reg, mask) \
+ PortIOSet(&((PUCHAR)(g->BaseIoAddress))[reg],mask);
+
+#define PC9010PortClear(g, reg, mask) \
+ PortIOClear(&((PUCHAR)(g->BaseIoAddress))[reg],mask);
+
+#define PC9010PortPut(g,reg,byte) \
+ PortIOPut(&((PUCHAR)(g->BaseIoAddress))[reg],byte);
+
+#define PC9010PortGet(g,reg,byte) \
+ PortIOGet(&((PUCHAR)(g->BaseIoAddress))[reg],byte);
+
+
+#define PC9010PortGetWord(g, reg, pword) \
+ *(PUSHORT)pword = ScsiPortReadPortUshort ( \
+ (PUSHORT)&(((PUCHAR)(g->BaseIoAddress))[reg]));
+
+#define PC9010PortGetBufferWord(g, reg, buffer, len) \
+ ScsiPortReadPortBufferUshort ( \
+ (PUSHORT)&(((PUCHAR)(g->BaseIoAddress))[reg]), \
+ (PUSHORT)buffer, len);
+
+#define PC9010PortPutWord(g, reg, word) \
+ ScsiPortWritePortUshort ( \
+ (PUSHORT)&(((PUCHAR)(g->BaseIoAddress))[reg]),(USHORT)word)
+
+#define PC9010PortPutBufferWord(g, reg, buffer, len) \
+ ScsiPortWritePortBufferUshort ( \
+ (PUSHORT)&(((PUCHAR)(g->BaseIoAddress))[reg]), \
+ (PUSHORT)buffer, len);
+
+//
+// Local routines (to the whole lower level driver)
+//
+VOID CardEnableInterrupt (PADAPTER_INFO g);
+VOID CardDisableInterrupt (PADAPTER_INFO g);
+
+#endif // _CARDT160_H
diff --git a/private/ntos/miniport/trantor/include/cardt338.h b/private/ntos/miniport/trantor/include/cardt338.h
new file mode 100644
index 000000000..f8ad8ba69
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardt338.h
@@ -0,0 +1,84 @@
+//-----------------------------------------------------------------------
+//
+// CARDT338.H
+//
+// T338 Adapter Definitions File
+//
+// Revisions:
+// 02-01-93 KJB First.
+// 02-25-93 KJB Reorganized, supports dataunderrun with long delay
+// for under run on large xfers. Can we fix this?
+// 03-05-93 JAP Cleaned comments, modified string in CardGetName()
+// to conform to ASM Driver names.
+// NOTE: This file was dated 02-26-93, but with no
+// corresponding Revision History log.
+// 03-08-93 JAP Added CardGetShortName() to conform to c_name
+// returned in ASM-Drivers.
+// 03-09-93 JAP Added CardGetType() function and included cardtype.h
+// 03-12-93 KJB Now supports polling thru CardInterrupt and
+// StartCommandInterrupt/FinishCommandInterrupt.
+// 03-22-93 KJB Reorged for functional interface.
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+//
+//-----------------------------------------------------------------------
+
+// include general os definitions
+
+#include "osdefs.h"
+
+//
+// Global per Adapter Information
+//
+typedef struct tagAdapterInfo {
+
+ PBASE_REGISTER BaseIoAddress; // address of this card
+
+} ADAPTER_INFO, FARP PADAPTER_INFO;
+
+// they have an n5380
+
+#include "n5380.h"
+
+// all 5380 type cards use the scsifnc module
+
+#include "scsifnc.h"
+
+// this card uses io ports
+
+#include "portio.h"
+
+// the parallel port defs
+
+#include "parallel.h"
+
+// the t338 board logic defs
+
+#include "t338.h"
+
+// CARDTYPE definitions file
+
+#include "cardtype.h"
+
+// Functions exported from library
+
+#include "card.h"
+
+// Redefined routines..
+
+#define CardWriteBytesFast T338WriteBytesFast
+#define CardReadBytesFast T338ReadBytesFast
+#define CardWriteBytesCommand ScsiWriteBytesSlow
+
+//
+// Local routines (to the whole lower level driver)
+//
+VOID CardEnableInterrupt (PADAPTER_INFO g);
+VOID CardDisableInterrupt (PADAPTER_INFO g);
+
diff --git a/private/ntos/miniport/trantor/include/cardt348.h b/private/ntos/miniport/trantor/include/cardt348.h
new file mode 100644
index 000000000..790a521ce
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardt348.h
@@ -0,0 +1,94 @@
+//-----------------------------------------------------------------------
+//
+// CARDT348.H
+//
+// T348 Adapter Definitions File
+//
+//
+// Revision History:
+//
+// 09-01-92 KJB First.
+// 02-25-93 KJB Reorganized, supports dataunderrun with long delay
+// for under run on large xfers. Can we fix this?
+// 03-05-93 JAP Cleaned comments, modified string in CardGetName()
+// to conform to ASM Driver names.
+// 03-08-93 JAP Added CardGetShortName() to conform to c_name
+// returned in ASM-Drivers.
+// 03-09-93 JAP Added CardGetType() function and included cardtype.h
+// 03-12-93 KJB Now supports polling thru CardInterrupt and
+// StartCommandInterrupt/FinishCommandInterrupt.
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+//
+//-----------------------------------------------------------------------
+
+// include general os definitions
+
+#include "osdefs.h"
+
+
+//
+// Global per Adapter Information
+//
+typedef struct tagAdapterInfo {
+
+ PBASE_REGISTER BaseIoAddress; // address of this card
+ UCHAR ParallelPortType; // the type of parallel port being used
+
+} ADAPTER_INFO, FARP PADAPTER_INFO;
+
+// they have an n5380
+
+#include "n5380.h"
+
+
+// all 5380 type cards use the scsifnc module
+
+#include "scsifnc.h"
+
+
+// the paralle port uses io ports
+
+#include "portio.h"
+
+
+// the parallel port defs
+
+#include "parallel.h"
+
+
+// the p3c chip defs
+
+#include "p3c.h"
+
+
+// CARDTYPE definitions file
+
+#include "cardtype.h"
+
+// Functions exported to library
+
+#include "card.h"
+
+//-----------------------------------------------------------------------
+//
+// Redefined routines
+//
+//-----------------------------------------------------------------------
+
+#define CardWriteBytesCommand ScsiWriteBytesSlow
+#define CardWriteBytesFast P3CWriteBytesFast
+#define CardReadBytesFast P3CReadBytesFast
+
+//
+// Local routines (to the whole lower level driver)
+//
+VOID CardEnableInterrupt (PADAPTER_INFO g);
+VOID CardDisableInterrupt (PADAPTER_INFO g);
+
diff --git a/private/ntos/miniport/trantor/include/cardt358.h b/private/ntos/miniport/trantor/include/cardt358.h
new file mode 100644
index 000000000..68020bf15
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardt358.h
@@ -0,0 +1,115 @@
+//-----------------------------------------------------------------------
+//
+// CARDT358.H
+//
+// T358 Adapter Definitions File
+//
+//
+// Revision History:
+//
+// 03-26-93 KJB First.
+// 05-13-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters.
+// 05-14-93 KJB CardCheckAdapter now does not take a PBASE_REGISTER
+// parameter, this parameter is now in the PINIT
+// structure.
+//
+//-----------------------------------------------------------------------
+
+// include general os definitions
+
+#include "osdefs.h"
+
+// the parallel port uses io ports
+
+#include "portio.h"
+
+
+// the parallel port defs
+
+#include "parallel.h"
+
+//
+// Global per Adapter Information
+//
+typedef struct tagAdapterInfo {
+ PBASE_REGISTER BaseIoAddress; // address of this card
+ UCHAR ParallelPortType; // the type of parallel port being used
+ UCHAR Delay; // amount of delay for t358
+ BOOLEAN EnableInterrupt; // whether or not interrupt should be enabled
+ UCHAR SignatureBytes[2]; // signature bytes of T358
+
+ // the following routines are all remapped based on the type of
+ // parallel port detected...
+
+ VOID (*EP3CWriteControlRegister)(struct tagAdapterInfo FARP g,
+ UCHAR reg, UCHAR value);
+ VOID (*EP3CReadControlRegister)(struct tagAdapterInfo FARP g,
+ PUCHAR value);
+ VOID (*EP3CReadDataRegister)(struct tagAdapterInfo FARP g,
+ UCHAR reg, PUCHAR byte);
+ VOID (*EP3CWriteDataRegister)(struct tagAdapterInfo FARP g,
+ UCHAR reg, UCHAR byte);
+ VOID (*EP3CReadFifo)(PBASE_REGISTER baseIoAddress, PUCHAR buffer);
+ VOID (*EP3CWriteFifo)(PBASE_REGISTER baseIoAddress, PUCHAR buffer);
+ VOID (*EP3CSetRegister)(struct tagAdapterInfo FARP g, UCHAR reg);
+
+} ADAPTER_INFO, FARP PADAPTER_INFO;
+
+
+// the ep3c chip defs
+
+#include "ep3c.h"
+
+
+// the 386sl and 80360 definitions
+
+#include "sl386.h"
+
+
+// they have an n5380
+
+#include "n5380.h"
+
+
+// all of these cards have a 53c400
+
+#include "n53c400.h"
+
+
+// all 5380 type cards use the scsifnc module
+
+#include "scsifnc.h"
+
+
+// CARDTYPE definitions file
+
+#include "cardtype.h"
+
+// Functions exported to library
+
+#include "card.h"
+
+//-----------------------------------------------------------------------
+//
+// Redefined routines
+//
+//-----------------------------------------------------------------------
+
+#define CardWriteBytesCommand N53C400WriteBytesFast
+#define CardWriteBytesFast N53C400WriteBytesFast
+#define CardReadBytesFast N53C400ReadBytesFast
+
+//
+// Local routines (to the whole lower level driver)
+//
+VOID CardEnableInterrupt (PADAPTER_INFO g);
+VOID CardDisableInterrupt (PADAPTER_INFO g);
+
diff --git a/private/ntos/miniport/trantor/include/cardtmv1.h b/private/ntos/miniport/trantor/include/cardtmv1.h
new file mode 100644
index 000000000..366ff74da
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardtmv1.h
@@ -0,0 +1,112 @@
+#ifndef _CARDTMV1_H
+#define _CARDTMV1_H
+
+//-----------------------------------------------------------------------
+//
+// CARDTMV1.H
+//
+// TMV1 Adapter Definitions File
+//
+// Revision History:
+//
+// 01-28-92 KJB First.
+// 03-05-93 JAP Cleaned comments, modified string in CardGetName()
+// to conform to ASM Driver names.
+// NOTE: This file was dated 02-26-93, but with no
+// corresponding Revision History log.
+// 03-08-93 JAP Added CardGetShortName() to conform to c_name
+// returned in ASM-Drivers.
+// 03-09-93 JAP Added CardGetType() function and included cardtype.h
+// 05-14-93 KJB CardCheckAdapter now does not take a PBASE_REGISTER
+// parameter, this parameter is now in the PINIT
+// structure.
+//
+//-----------------------------------------------------------------------
+
+// include general os definitions
+
+#include "osdefs.h"
+
+
+//
+// Global per Adapter Information
+//
+typedef struct tagAdapterInfo {
+ PBASE_REGISTER BaseIoAddress; // address of this card
+ UCHAR InterruptLevel; // interrupt level this card is using
+ UCHAR DRQMask; // mask for DRQ, varies with MV card type
+} ADAPTER_INFO, FARP PADAPTER_INFO;
+
+// they have an n5380
+
+#include "n5380.h"
+
+
+// all 5380 type cards use the scsifnc module
+
+#include "scsifnc.h"
+
+
+// all cards have a MV101 chip
+
+#include "mv101.h"
+
+
+// all port access routines
+
+#include "portio.h"
+
+
+// CARDTYPE definitions file
+
+#include "cardtype.h"
+
+
+// include exported function definitions
+
+#include "card.h"
+
+//-----------------------------------------------------------------------
+//
+// Definitions
+//
+//-----------------------------------------------------------------------
+
+//-----------------------------------------------------------------------
+// Routines used by MV101.c
+//-----------------------------------------------------------------------
+
+#define MV101PortTest(g, reg, mask) \
+ PortIOTest(&((PUCHAR)g->BaseIoAddress)[reg],mask)
+
+#define MV101PortSet(g, reg, mask) \
+ PortIOSet(&((PUCHAR)g->BaseIoAddress)[reg],mask);
+
+#define MV101PortClear(g, reg, mask) \
+ PortIOClear(&((PUCHAR)g->BaseIoAddress)[reg],mask);
+
+#define MV101PortPut(g,reg,byte) \
+ PortIOPut(&((PUCHAR)g->BaseIoAddress)[reg],byte);
+
+#define MV101PortGet(g,reg,byte) \
+ PortIOGet(&((PUCHAR)g->BaseIoAddress)[reg],byte);
+
+
+//-----------------------------------------------------------------------
+//
+// Redefined routines
+//
+//-----------------------------------------------------------------------
+
+#define CardReadBytesFast MV101ReadBytesFast
+#define CardWriteBytesFast MV101WriteBytesFast
+#define CardWriteBytesCommand ScsiWriteBytesSlow
+
+//
+// Local routines (to the whole lower level driver)
+//
+VOID CardEnableInterrupt (PADAPTER_INFO g);
+VOID CardDisableInterrupt (PADAPTER_INFO g);
+
+#endif // _CARDTMV1_H
+
diff --git a/private/ntos/miniport/trantor/include/cardtype.h b/private/ntos/miniport/trantor/include/cardtype.h
new file mode 100644
index 000000000..346decc2c
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/cardtype.h
@@ -0,0 +1,48 @@
+#ifndef _CARDTYPE_H
+#define _CARDTYPE_H
+
+//-----------------------------------------------------------------------
+//
+// CARDTYPE.H
+//
+// CARDTYPE_xxxx Definitions File
+//
+// Revision History:
+// 03-09-93 JAP First.
+//
+//-----------------------------------------------------------------------
+
+
+#define CARDTYPE_UNKNOWN 0
+#define CARDTYPE_T100 1
+#define CARDTYPE_SGATE 2
+#define CARDTYPE_T110_PROTO 3
+#define CARDTYPE_T150 4
+#define CARDTYPE_T200 5
+#define CARDTYPE_T110 6
+#define CARDTYPE_T120 7
+#define CARDTYPE_T140 8
+#define CARDTYPE_T500 9
+#define CARDTYPE_ASPI 10
+#define CARDTYPE_T12P 11
+#define CARDTYPE_T338 12
+#define CARDTYPE_TP30 13
+#define CARDTYPE_T130 14
+#define CARDTYPE_TMV1 15
+#define CARDTYPE_TMG1 16
+#define CARDTYPE_T348 17
+#define CARDTYPE_TP43 18
+#define CARDTYPE_T295 19
+#define CARDTYPE_T130B 20
+#define CARDTYPE_T180 21
+#define CARDTYPE_MK5087 22
+#define CARDTYPE_T160 23
+#define CARDTYPE_T358 24
+
+
+#endif // _CARDTYPE_H
+
+
+//-----------------------------------------------------------------------
+// End Of File.
+//-----------------------------------------------------------------------
diff --git a/private/ntos/miniport/trantor/include/ep3c.h b/private/ntos/miniport/trantor/include/ep3c.h
new file mode 100644
index 000000000..28d2380ce
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/ep3c.h
@@ -0,0 +1,78 @@
+//-----------------------------------------------------------------------
+//
+// EP3C.H
+//
+// Trantor EP3C Definitions File
+//
+// Revisions:
+// 04-01-93 KJB First.
+// 05-17-93 KJB Added some missing prototypes.
+//
+//-----------------------------------------------------------------------
+
+// mappings for registers
+
+#define EP3C_AREG1 0x00
+#define EP3C_AREG2 0x80
+
+// bits for aux reg 1
+
+#define EP3C_IRQEN 0x40
+#define EP3C_RSVD1 0x20
+#define EP3C_ADRS 0x1f
+
+// bits for aux reg 2
+
+#define EP3C_RST 0x40
+#define EP3C_UNIDIR 0x20
+#define EP3C_RSVD2 0x18
+#define EP3C_DLY 0x07
+
+//
+// Public Functions
+//
+
+//
+// for the n53c400 that is in the EP3C
+// 53c400 register offsets from 53c400 base
+//
+
+#define N53C400_CONTROL 0x18
+#define N53C400_STATUS 0x18
+#define N53C400_COUNTER 0x19
+#define N53C400_SWITCH 0x1a
+#define N53C400_HOST_BFR 0x10
+#define N53C400_5380 0x08
+#define N53C400_RAM 0x00
+
+// for the 53C400 that is in the P3C
+
+VOID N53C400PortGet(PADAPTER_INFO g,UCHAR reg,PUCHAR byte);
+VOID N53C400PortPut(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+BOOLEAN N53C400PortTest(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+VOID N53C400PortSet(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+VOID N53C400PortClear(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+VOID N53C400PortPutBuffer(PADAPTER_INFO g, UCHAR reg,
+ PUCHAR pbytes, ULONG len);
+VOID N53C400PortGetBuffer(PADAPTER_INFO g, UCHAR reg,
+ PUCHAR pbytes, ULONG len);
+
+// for the parallel port the P3C uses
+
+#define ParallelPortGet(baseIoAddress, reg, byte) \
+ PortIOGet((PUCHAR)baseIoAddress+reg,byte)
+#define ParallelPortPut(baseIoAddress,reg,byte) \
+ PortIOPut((PUCHAR)baseIoAddress+reg,byte)
+
+// exported routines
+
+BOOLEAN EP3CCheckAdapter(PADAPTER_INFO g);
+USHORT EP3CDoCommand(PTSRB t);
+VOID EP3CResetBus(PADAPTER_INFO g);
+USHORT EP3CStartCommandInterrupt(PTSRB t);
+USHORT EP3CFinishCommandInterrupt(PTSRB t);
+BOOLEAN EP3CInterrupt(PADAPTER_INFO g);
+VOID EP3CEnableInterrupt(PADAPTER_INFO g);
+VOID EP3CDisableInterrupt(PADAPTER_INFO g);
+VOID EP3CResetBus(PADAPTER_INFO g);
+
diff --git a/private/ntos/miniport/trantor/include/findpas.h b/private/ntos/miniport/trantor/include/findpas.h
new file mode 100644
index 000000000..758de236e
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/findpas.h
@@ -0,0 +1,319 @@
+//==========================================================================
+//
+// Definitions from findpas.h (card searching)
+//
+// 01-28-93 KJB First.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+//==========================================================================
+
+
+
+typedef struct {
+ USHORT wBoardRev;
+ USHORT wChipRev;
+ union
+ {
+ struct /* Our PAS_16 gives */
+ {
+ unsigned long CDInterfaceType:2; /* 3 */
+ unsigned long EnhancedSCSI:1; /* 0 - not enhanced SCSI*/
+ unsigned long DAC16:1; /* 1 DAC16 */
+
+ unsigned long OPL_3:1; /* 1 OPL3 */
+ unsigned long Mixer_508:1; /* 1 Mixer 508 */
+ unsigned long DualDAC:1; /* 1 Dual DAC */
+ unsigned long MPU401:1; /* 0 NO mpu401 */
+
+ unsigned long Slot16:1; /* 1 - slot 16 */
+ unsigned long MCA:1; /* 0 - not MCA */
+ unsigned long CDPC:1; /* 0 - not CDPC */
+ unsigned long SoundBlaster:1; /* 1 - sound blaster */
+
+ unsigned long SCSI_IO_16:1; /* 1 - ? */
+ unsigned long reserved:2;
+ unsigned long Did_HW_Init:1; /* 0 - ? */
+ unsigned long unused:16;
+ } CapsBits;
+ ULONG dwCaps;
+ } Caps;
+ ULONG ProPort;
+ UCHAR ProDMA;
+ UCHAR ProIRQ;
+ USHORT SBPort;
+ UCHAR SBDMA;
+ UCHAR SBIRQ;
+ USHORT MPUPort;
+ UCHAR MPUIRQ;
+ UCHAR CDIRQ;
+ ULONG TranslateCode;
+ UCHAR ReservedB1;
+ UCHAR ReservedB2;
+ PUCHAR PROBase;
+} FOUNDINFO, FARP PFOUNDINFO;
+
+
+// these version numbers are found in 0B8Bh
+#define PAS_VERSION_1 0x000 // original
+#define PAS_PLUS 0x001 // Pro Audio Spectrum Plus with SCSI
+#define PAS_SIXTEEN 0x001 // Pro Audio Spectrum 16 with SCSI
+#define PAS_STUDIO 0x003
+#define PAS_CDPC 0x007 // CDPC 05/06/92 mmq
+#define BOARD_REV_MASK 07
+
+
+#define CHIP_REV_B 0x002
+#define CHIP_REV_D 0x004
+
+#define NO_PAS_INSTALLED 0x000 // can't find board
+
+
+// CD interface type definitions
+#define NO_INTERFACE 0
+#define MITSUMI_TYPE 1
+#define SONY_TYPE 2
+#define SCSI_TYPE 3
+#define SCSI_TYPE 3
+
+// sound definitions
+#define SOUND_DEF_DMACHANNEL 1 // DMA channel no
+#define SOUND_DEF_INT 7
+#define SOUND_DEF_PORT 0x220
+
+//==========================================================================
+//
+// Definitions from pasdef.h
+//
+//==========================================================================
+
+//
+// THESE DEFINITIONS FOR CAPABILITIES FILED
+//
+
+
+#define DEFAULT_BASE 0x388 // default base I/O address of Pro AudioSpectrum
+
+//// THESE ARE BASE REGISTER ATES
+
+//
+// Used only during initialization
+//
+
+#define PCM_CONTROL 0x0f8a //
+
+#define ENHANCED_SCSI_DETECT_REG 0x7f89 //
+
+#define SYSTEM_CONFIG_1 0x8388 //
+#define SYSTEM_CONFIG_2 0x8389 //
+#define SYSTEM_CONFIG_3 0x838a //
+#define SYSTEM_CONFIG_4 0x838b //
+
+#define IO_PORT_CONFIG_1 0xf388 //
+#define IO_PORT_CONFIG_2 0xf389 //
+#define IO_PORT_CONFIG_3 0xf38a //
+
+#define COMPATIBLE_REGISTER_ENABLE 0xf788 // SB and MPU emulation
+#define EMULATION_ADDRESS_POINTER 0xf789 // D0-D3 is SB; D4-D7 is MPU
+
+#define EMULATION_INTERRUPT_POINTER 0xfb8a // MPU and SB IRQ and SB DMA settings
+
+#define CHIP_REV 0xff88 // MV101 chip revision number
+#define MASTER_MODE_READ 0xff8b // aka Master Address Pointer
+
+//
+// Used for volume setting
+//
+
+#define MIXER_508_REG 0x078b // Mixer 508 1 port
+
+#define SERIAL_MIXER 0x0b88 // for Pas 1 and Pas 8
+#define FEATURE_ENABLE 0x0b88 // for Pas 16 boards only
+#define INTERRUPT_ENABLE 0x0b89 //
+#define FILTER_REGISTER 0x0b8a //
+#define INTERRUPT_CTRL_REG 0x0b8b //
+
+
+//
+// Only one of each of these
+//
+
+#define PAS_2_WAKE_UP_REG 0x9a01 // aka Master Address Pointer
+
+
+//
+// Not used here
+//
+
+#define TIMEOUT_COUNTER 0x4388 //
+#define TIMEOUT_STATUS 0x4389 //
+#define WAIT_STATE 0xbf88 //
+#define PRESCALE_DIVIDER 0xbf8A //
+
+#define SLAVE_MODE_READ 0xef8b // bits D0-D1
+
+
+
+#define READ_PAS(pGDI, port) \
+ READ_PORT_UCHAR((PUCHAR)((port) ^ (pGDI->TranslateCode)))
+
+#define WRITE_PAS(pGDI, port, data) \
+ WRITE_PORT_UCHAR((PUCHAR)((port) ^ (pGDI->TranslateCode)), (UCHAR)(data))
+
+
+// useful bit definitions
+#define D0 (1<<0)
+#define D1 (1<<1)
+#define D2 (1<<2)
+#define D3 (1<<3)
+#define D4 (1<<4)
+#define D5 (1<<5)
+#define D6 (1<<6)
+#define D7 (1<<7)
+
+
+//// BIT FIELDS FOR COMPATIBLE_REGISTER_ENABLE
+#define MPU_ENABLE_BIT D0
+#define SB_ENABLE_BIT D1
+#define SB_IRQ_ENABLE_BIT D2 // read only
+
+//// BIT FIELDS FOR FEATURE_ENABLE (0xb88)
+#define PCM_FEATURE_ENABLE D0
+#define FM_FEATURE_ENABLE D1
+#define MIXER_FEATURE_ENABLE D2
+#define SB_FEATURE_ENABLE D4
+
+/// BIT FIELDS FOR PCM CONTROL
+#define PCM_STEREO D0+D3
+#define PCM_DAC D4
+#define PCM_MONO D5
+#define PCM_ENGINE D6
+#define PCM_DRQ D7
+
+/// BIT FIELDS FOR SYSTEM CONFIG 3
+#define C3_ENHANCED_TIMER D0
+#define C3_SB_CLOCK_EMUL D1 // don't set! see Brian Colvin
+#define C3_VCO_INVERT D2
+#define C3_INVERT_BCLK D3
+#define C3_SYNC_PULSE D4
+#define C3_PSEUDO_PCM_STEREO D5
+
+/// BIT FIELDS FOR INTERRUPT ENABLE
+#define INT_LEFT_FM D0
+#define INT_RIGHT_FM D1
+#define INT_SB D1
+#define INT_SAMPLE_RATE D2
+#define INT_SAMPLE_BUFFER D3
+#define INT_MIDI D4
+
+
+
+/// BIT FIELDS FOR COMPATIBLE REGISTER ENABLE
+#define COMPAT_MPU D0
+#define COMPAT_SB D1
+
+
+/// IRQ POINTER VALUES FOR EMULATION INTERRUPT POINTER
+#define EMUL_IRQ_NONE 0
+#define EMUL_IRQ_2 1
+#define EMUL_IRQ_3 2
+#define EMUL_IRQ_5 3
+#define EMUL_IRQ_7 4
+#define EMUL_IRQ_10 5
+#define EMUL_IRQ_11 6
+#define EMUL_IRQ_12 7
+
+/// DMA POINTER VALUES FOR EMULATION DMA POINTER
+#define EMUL_DMA_NONE 0
+#define EMUL_DMA_1 1
+#define EMUL_DMA_2 2
+#define EMUL_DMA_3 3
+
+
+/// BIT VALUES FOR FILTER REGISTER
+#define FILTER_NOMUTE D5
+
+
+#define MIXCROSSCAPS_NORMAL_STEREO 0 // Left->Left, Right->Right
+#define MIXCROSSCAPS_RIGHT_TO_BOTH 1 // Right->Left, Right->Right
+#define MIXCROSSCAPS_LEFT_TO_BOTH 2 // Left->Left, Left->Right
+#define MIXCROSSCAPS_REVERSE_STEREO 4 // Left->Right, Right->Left
+#define MIXCROSSCAPS_RIGHT_TO_LEFT 8 // Right->Left, Right->Right
+#define MIXCROSSCAPS_LEFT_TO_RIGHT 0x10 // Left->Left, Left->Right
+
+#define OUT_AMPLIFIER 0
+#define OUT_PCM 1
+
+#define _LEFT 1
+#define _RIGHT 2
+
+#define _BASS 0
+#define _TREBLE 1
+
+
+#define MV_508_ADDRESS D7
+#define MV_508_INPUT D4
+#define MV_508_SWAP D6
+#define MV_508_BASS (D0+D1)
+#define MV_508_TREBLE (D2)
+#define MV_508_EQMODE (D2+D0)
+
+#define MV_508_LOUDNESS D2
+#define MV_508_ENHANCE (D1+D0)
+
+/// DEFINES FOR SERIAL MIXER
+#define NATIONAL_SELECTMUTE_REG 0x40
+#define NATIONAL_LOUD_ENH_REG 0x41
+#define NATIONAL_BASS_REG 0x42
+#define NATIONAL_TREB_REG 0x43
+#define NATIONAL_LEFT_VOL_REG 0x44
+#define NATIONAL_RIGHT_VOL_REG 0x45
+#define NATIONAL_MODESELECT_REG 0x46
+
+#define NATIONAL_COMMAND D7
+#define NATIONAL_LOUDNESS D0
+#define NATIONAL_ENHANCE D1
+
+#define SERIAL_MIX_LEVEL D0
+#define SERIAL_MIX_CLOCK D1
+#define SERIAL_MIX_STROBE D2
+#define SERIAL_MIX_MASTER D4
+#define SERIAL_MIX_REALSOUND D6
+#define SERIAL_MIX_DUALFM D7
+
+
+// FILTER_REGISTER
+#define fFIdatabits 0x1f // 00011111B filter select and decode field bits
+#define fFImutebits D5 // filter mute field bit
+#define fFIpcmbits (D7+D6) // 11000000B filter sample rate field bits
+#define bFImute D5 // filter mute bit
+#define bFIsrate D6 // filter sample rate timer mask
+#define bFIsbuff D7 // filter sample buffer counter mask
+
+#define FILTERMAX 6 // six possible settings
+
+#define FILTER_MUTE 0 // mute - goes to PC speaker
+#define FILTER_LEVEL_1 1 // 20hz to 2.9khz
+#define FILTER_LEVEL_2 2 // 20hz to 5.9khz
+#define FILTER_LEVEL_3 3 // 20hz to 8.9khz
+#define FILTER_LEVEL_4 4 // 20hz to 11.9khz
+#define FILTER_LEVEL_5 5 // 20hz to 15.9khz
+#define FILTER_LEVEL_6 6 // 20hz to 17.8khz
+
+
+/// SLAVE_MODE_READ BITS
+#define SLAVE_MODE_OPL3 D2
+#define SLAVE_MODE_16 D3
+
+#define PASX_IN(pFI, port) \
+ ScsiPortReadPortUchar(pFI->PROBase + ( (port) ^ pFI->TranslateCode) )
+
+#define PASX_OUT(pFI, port, data) \
+ ScsiPortWritePortUchar(pFI->PROBase + ((port) ^ pFI->TranslateCode), (UCHAR)(data))
+
+#define WRITE_PORT_UCHAR ScsiPortWritePortUchar
+#define READ_PORT_UCHAR ScsiPortReadPortUchar
+
+//
+// Exported routines
+//
+int FindPasHardware(PFOUNDINFO pFoundInfo);
+void InitProHardware(PFOUNDINFO pFI);
diff --git a/private/ntos/miniport/trantor/include/mv101.h b/private/ntos/miniport/trantor/include/mv101.h
new file mode 100644
index 000000000..bf34042c9
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/mv101.h
@@ -0,0 +1,62 @@
+//-----------------------------------------------------------------------
+//
+// MV101.H
+//
+// Trantor MV101 Definitions File
+//
+// Revisions:
+// 02-25-93 KJB First.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+// 04-05-93 KJB Added prototypes for enable/disable interrupt.
+// 05-13-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters. Auto Request Sense is
+// now supported.
+// 05-13-93 KJB Merged Microsoft Bug fixes to card detection.
+// 05-17-93 KJB Added missing function prototype.
+//
+//-----------------------------------------------------------------------
+
+
+// Register offsets of MV101 used by scsi
+
+#define MV101_5380_1 (0x1f88-0x388)
+#define MV101_5380_2 (0x3f88-0x388)
+#define MV101_TIMEOUT_COUNTER (0x4388-0x388)
+#define MV101_TIMEOUT_STATUS (0x4389-0x388)
+#define MV101_DMA_PORT (0x5f88-0x388)
+#define MV101_DRQ_PORT (0x5f89-0x388)
+#define MV101_IRQ_PORT (0x5f8b-0x388)
+#define MV101_SYSTEM_CONFIG4 (0x838b-0x388)
+#define MV101_WAIT_STATE (0xbf88-0x388)
+#define MV101_IO_PORT_CONFIG3 (0xf38a-0x388)
+
+//
+// Public Functions
+//
+
+// for the 5380 that is in the P3C
+
+VOID N5380PortGet(PADAPTER_INFO g,UCHAR reg,PUCHAR byte);
+VOID N5380PortPut(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+
+// exported routines
+
+BOOLEAN MV101CheckAdapter(PADAPTER_INFO g);
+USHORT MV101DoCommand(PTSRB t);
+USHORT MV101ReadBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT MV101WriteBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+VOID MV101ResetBus(PADAPTER_INFO g);
+VOID MV101EnableInterrupt (PADAPTER_INFO g);
+VOID MV101DisableInterrupt (PADAPTER_INFO g);
+VOID MV101SetInterruptLevel (PADAPTER_INFO g, UCHAR level);
+
diff --git a/private/ntos/miniport/trantor/include/n5380.h b/private/ntos/miniport/trantor/include/n5380.h
new file mode 100644
index 000000000..d0ece3765
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/n5380.h
@@ -0,0 +1,148 @@
+//-----------------------------------------------------------------------
+//
+// FILE: n5380.h
+//
+// N5380 Definitions File
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 01-12-93 KJB Changed reset time.
+// 03-02-93 KJB/JAP Added N5380WaitLastByteSent.
+// 03-09-93 KJB Changed Names of bits/register to be consistent with
+// n5380 manual.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+//
+//-----------------------------------------------------------------------
+
+// scsi reset time in usec
+#define SCSI_RESET_TIME 1000000
+
+//
+// Define the scsi phases
+//
+
+#define PHASE_NULL 0
+#define PHASE_DATAOUT 0
+#define PHASE_DATAIN 1
+#define PHASE_COMMAND 2
+#define PHASE_STATUS 3
+#define PHASE_MSGOUT 6
+#define PHASE_MSGIN 7
+
+//
+// Define n5380 registers
+//
+// NOTE: The names of these registers are
+// made to correspond exactly with the L5380 manual
+// page 7 of Logic Devices Incorporated
+//
+
+#define N5380_CURRENT_DATA 0
+#define N5380_OUTPUT_DATA 0
+#define N5380_INITIATOR_COMMAND 1
+#define N5380_MODE 2
+#define N5380_TARGET_COMMAND 3
+#define N5380_CURRENT_STATUS 4
+#define N5380_ID_SELECT 4
+#define N5380_DMA_STATUS 5
+#define N5380_START_DMA_SEND 5
+#define N5380_INPUT_DATA 6
+#define N5380_START_TARGET_RECIEVE 6
+#define N5380_RESET_INTERRUPT 7
+#define N5380_START_INITIATOR_RECEIVE 7
+
+//
+// Define 5380 register bit assignments
+//
+// NOTE: The names of these bit assignments are
+// made to correspond exactly with the L5380 manual
+// page 7 of Logic Devices Incorporated
+//
+
+// Initiator Command
+
+#define IC_RST 0x80
+#define IC_ARBITRATION_IN_PROGRESS 0x40
+#define IC_LOST_ARBITRATION 0x20
+#define IC_ACK 0x10
+#define IC_BSY 0x8
+#define IC_SEL 0x4
+#define IC_ATN 0x2
+#define IC_DATA_BUS 0x1
+
+// Mode Register
+
+#define MR_BLOCK_MODE_DMA 0x80
+#define MR_TARGET_MODE 0x40
+#define MR_ENABLE_PARITY_CHECKING 0x20
+#define MR_ENABLE_PARITY_INTERRUPT 0x10
+#define MR_ENABLE_EODMA_INTERRUPT 0x8
+#define MR_MONITOR_BSY 0x4
+#define MR_DMA_MODE 0x2
+#define MR_ARBITRATE 0x1
+
+// Target Command Register
+
+#define TC_LAST_BYTE_SENT 0x80
+#define TC_REQ 0x8
+#define TC_MSG 0x4
+#define TC_CD 0x2
+#define TC_IO 0x1
+
+// Current SCSI Control Register
+
+#define CS_RST 0x80
+#define CS_BSY 0x40
+#define CS_REQ 0x20
+#define CS_MSG 0x10
+#define CS_CD 0x8
+#define CS_IO 0x4
+#define CS_SEL 0x2
+#define CS_PARITY 0x1
+
+// DMA Status Register
+
+#define DS_DMA_END 0x80
+#define DS_DMA_REQUEST 0x40
+#define DS_PARITY_ERROR 0x20
+#define DS_INTERRUPT_REQUEST 0x10
+#define DS_PHASE_MATCH 0x8
+#define DS_BUSY_ERROR 0x4
+#define DS_ATN 0x2
+#define DS_ACK 0x1
+
+//
+// Public Routines Definitions
+//
+
+#define N5380EnableInterrupt(g) \
+ N5380PortSet(g,N5380_MODE,MR_DMA_MODE)
+
+//
+// Public Routines
+//
+
+BOOLEAN N5380Interrupt(PADAPTER_INFO g);
+VOID N5380DisableInterrupt(PADAPTER_INFO g);
+USHORT N5380ToggleAck(PADAPTER_INFO g, ULONG usec);
+USHORT N5380GetByte(PADAPTER_INFO g, ULONG usec, PUCHAR byte);
+USHORT N5380PutByte(PADAPTER_INFO g, ULONG usec, UCHAR byte);
+USHORT N5380GetPhase(PADAPTER_INFO g, PUCHAR phase);
+USHORT N5380SetPhase(PADAPTER_INFO g, UCHAR phase);
+USHORT N5380WaitNoRequest(PADAPTER_INFO g, ULONG usec);
+USHORT N5380WaitRequest(PADAPTER_INFO g, ULONG usec);
+USHORT N5380WaitNoBusy(PADAPTER_INFO g, ULONG usec);
+USHORT N5380WaitBusy(PADAPTER_INFO g, ULONG usec);
+USHORT N5380WaitLastByteSent(PADAPTER_INFO g, ULONG usec);
+USHORT N5380Select(PADAPTER_INFO g, UCHAR target, UCHAR lun);
+VOID N5380ResetBus(PADAPTER_INFO g);
+BOOLEAN N5380CheckAdapter(PADAPTER_INFO g);
+VOID N5380DebugDump(PADAPTER_INFO g);
+VOID N5380EnableDmaWrite(PADAPTER_INFO g);
+VOID N5380EnableDmaRead(PADAPTER_INFO g);
+VOID N5380DisableDmaRead(PADAPTER_INFO g);
+BOOLEAN N5380PortTest(PADAPTER_INFO g,UCHAR reg,UCHAR mask);
+VOID N5380PortClear(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+VOID N5380PortSet(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+VOID N5380DisableDmaWrite (PADAPTER_INFO g);
diff --git a/private/ntos/miniport/trantor/include/n53c400.h b/private/ntos/miniport/trantor/include/n53c400.h
new file mode 100644
index 000000000..e9a798643
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/n53c400.h
@@ -0,0 +1,59 @@
+//-----------------------------------------------------------------------
+//
+// FILE: n53c400.h
+//
+// N53C400 Definitions File
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+// 04-01-03 KJB Moved N53C400 register offsets away from here to
+// cardt13b.h. So we can use this module with the
+// t358.
+//
+//-----------------------------------------------------------------------
+
+// Control Register for 53C400
+
+#define CR_RST 0x80
+#define CR_DIR 0x40
+#define CR_BFR_INT 0x20
+#define CR_5380_INT 0x10
+#define CR_SH_INT 0x8
+
+// Status Register for 53C400
+
+#define SR_ACCESS 0x80
+#define SR_DIR 0x40
+#define SR_BFR_INT 0x20
+#define SR_5380_INT 0x10
+#define SR_SH_INT 0x8
+#define SR_HBFR_RDY 0x4
+#define SR_SBFR_RDY 0x2
+#define SR_IRQ_RDY 0x1
+
+//
+// Redefined routines
+//
+
+// Each N53C400 has a 5380 built in
+
+#define N5380PortPut(g,reg,byte) \
+ N53C400PortPut(g,N53C400_5380+reg,byte);
+
+#define N5380PortGet(g,reg,byte) \
+ N53C400PortGet(g,N53C400_5380+reg,byte);
+
+//
+// public functions
+//
+
+BOOLEAN N53C400CheckAdapter(PADAPTER_INFO g);
+USHORT N53C400WriteBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT N53C400ReadBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+VOID N53C400EnableInterrupt(PADAPTER_INFO g);
+VOID N53C400DisableInterrupt(PADAPTER_INFO g);
+VOID N53C400ResetBus(PADAPTER_INFO g);
diff --git a/private/ntos/miniport/trantor/include/p3c.h b/private/ntos/miniport/trantor/include/p3c.h
new file mode 100644
index 000000000..03f6f876d
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/p3c.h
@@ -0,0 +1,75 @@
+//-----------------------------------------------------------------------
+//
+// P3C.H
+//
+// Trantor P3C Definitions File
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 02-25-93 KJB Reorganized, supports dataunderrun with long delay
+// for under run on large xfers. Can we fix this?
+// 03-12-93 KJB Now supports polling thru CardInterrupt and
+// StartCommandInterrupt/FinishCommandInterrupt.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+// 04-05-93 KJB Fixed function prototype.
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+//
+//-----------------------------------------------------------------------
+
+// p3c control
+
+#define PC_RES 0x80
+#define PC_MODE 0x70
+#define PC_ADRS 0x0f
+
+// p3c modes
+
+#define PCCC_MODE_RPER_BYTE 0
+#define PCCC_MODE_RPER_NIBBLE 0x10
+#define PCCC_MODE_RDMA_BYTE 0x20
+#define PCCC_MODE_RDMA_NIBBLE 0x30
+#define PCCC_MODE_WPER 0x40
+#define PCCC_MODE_RSIG_BYTE 0x50
+#define PCCC_MODE_WDMA 0x60
+#define PCCC_MODE_RSIG_NIBBLE 0x70
+
+
+//
+// Public Functions
+//
+
+// for the 5380 that is in the P3C
+
+VOID N5380PortGet(PADAPTER_INFO g,UCHAR reg,PUCHAR byte);
+VOID N5380PortPut(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+
+// for the parallel port the P3C uses
+
+#define ParallelPortGet(baseIoAddress, reg, byte) \
+ PortIOGet((PUCHAR)baseIoAddress+reg,byte)
+#define ParallelPortPut(baseIoAddress,reg,byte) \
+ PortIOPut((PUCHAR)baseIoAddress+reg,byte)
+
+// exported routines
+
+BOOLEAN P3CCheckAdapter(PADAPTER_INFO g);
+USHORT P3CDoCommand(PTSRB t);
+VOID P3CResetBus(PADAPTER_INFO g);
+USHORT P3CStartCommandInterrupt(PTSRB t);
+USHORT P3CFinishCommandInterrupt(PTSRB t);
+BOOLEAN P3CInterrupt(PADAPTER_INFO g);
+USHORT P3CReadBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT P3CWriteBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+VOID P3CResetBus(PADAPTER_INFO g);
+USHORT P3CDoIo(PTSRB t);
+
diff --git a/private/ntos/miniport/trantor/include/parallel.h b/private/ntos/miniport/trantor/include/parallel.h
new file mode 100644
index 000000000..b2314998b
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/parallel.h
@@ -0,0 +1,43 @@
+//
+// PARALLEL.H
+//
+// Parallel Port Definitions File
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+//
+
+// parallel port defs
+
+// p_s - status port
+
+#define P_BUSY 0x80
+#define P_ACK 0x40
+#define P_PE 0x20
+#define P_SELECT 0x10
+#define P_ERR 0x8
+
+// p_c - control port.
+
+#define P_BUFEN 0xE0
+#define P_IRQEN 0x10
+#define P_SLC 0x8
+#define P_INIT 0x4
+#define P_AFX 0x2
+#define P_STB 0x1
+
+// parallel port registers
+
+#define PARALLEL_DATA 0
+#define PARALLEL_STATUS 1
+#define PARALLEL_CONTROL 2
+
+//
+// Public Functions
+//
+
+USHORT ParallelWaitBusy(PBASE_REGISTER baseIoAddress, ULONG usec, PUCHAR data);
+USHORT ParallelWaitNoBusy(PBASE_REGISTER baseIoAddress, ULONG usec, PUCHAR data);
+
+
diff --git a/private/ntos/miniport/trantor/include/pc9010.h b/private/ntos/miniport/trantor/include/pc9010.h
new file mode 100644
index 000000000..b996b3efc
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/pc9010.h
@@ -0,0 +1,92 @@
+//-----------------------------------------------------------------------
+//
+// FILE: pc9010.h
+//
+// PC9010 Definitions File
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+// 05-06-93 KJB Added prototype for PC9010CheckAdapter
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+//
+//-----------------------------------------------------------------------
+
+//
+// PC9010 Register Offsets
+//
+
+#define PC9010_CONFIG 0
+#define PC9010_CONTROL 2
+#define PC9010_FIFO_STATUS 3
+#define PC9010_FIFO 4
+#define PC9010_N5380 8
+
+// size of fifo in bytes
+
+#define PC9010_FIFO_SIZE 128
+
+// Config Register for PC9010
+
+#define CFR_VERSION 0xF0
+#define CFR_SWITCH 0x0F
+
+// Control Register for PC9010
+
+#define CTR_CONFIG 0x80
+#define CTR_SWSEL 0x40
+#define CTR_IRQEN 0x20
+#define CTR_DMAEN 0x10
+#define CTR_FEN 0x8
+#define CTR_FDIR 0x4
+#define CTR_F16 0x2
+#define CTR_FRST 0x1
+
+// Fifo Status Register for PC9010
+
+#define FSR_IRQ 0x80
+#define FSR_DRQ 0x40
+#define FSR_FHFUL 0x20
+#define FSR_FHEMP 0x10
+#define FSR_FLFUL 0x08
+#define FSR_FLEMP 0x04
+#define FSR_FFUL 0x02
+#define FSR_FEMP 0x01
+
+// constant JEDEC ID
+
+#define PC9010_JEDEC_ID 0x8f
+
+//
+// Redefined routines
+//
+
+// Each PC9010 has a 5380 built in
+
+#define N5380PortPut(g,reg,byte) \
+ PC9010PortPut(g,PC9010_N5380+reg,byte);
+
+#define N5380PortGet(g,reg,byte) \
+ PC9010PortGet(g,PC9010_N5380+reg,byte);
+
+//
+// public functions
+//
+
+BOOLEAN PC9010CheckAdapter (PADAPTER_INFO g);
+USHORT PC9010WriteBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT PC9010ReadBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+VOID PC9010EnableInterrupt(PADAPTER_INFO g);
+VOID PC9010DisableInterrupt(PADAPTER_INFO g);
+VOID PC9010ResetBus(PADAPTER_INFO g);
+
diff --git a/private/ntos/miniport/trantor/include/port.h b/private/ntos/miniport/trantor/include/port.h
new file mode 100644
index 000000000..5b4da398e
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/port.h
@@ -0,0 +1,21 @@
+//---------------------------------------------------------------------
+//
+// FILE: PORT.H
+//
+// Port Access Definitions File
+//
+// Revisions:
+// 01-08-92 KJB First.
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+//
+//---------------------------------------------------------------------
+
+VOID CardPortClear (PUCHAR baseIoAddress, UCHAR mask);
+VOID CardPortSet (PUCHAR baseIoAddress, UCHAR mask);
+BOOLEAN CardPortTest (PUCHAR baseIoAddress, UCHAR mask);
+
+// the following definitions must be defined by card.h
+// since there is a difference between io and memory mapped access
+
+// VOID CardPortGet (PUCHAR baseIoAddress, UCHAR *byte);
+// VOID CardPortPut (PUCHAR baseIoAddress, UCHAR byte);
diff --git a/private/ntos/miniport/trantor/include/portio.h b/private/ntos/miniport/trantor/include/portio.h
new file mode 100644
index 000000000..161b8a389
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/portio.h
@@ -0,0 +1,36 @@
+//------------------------------------------------------------------------
+//
+// FILE: PORTIO.H
+//
+// Port Access Definitions File
+//
+// Revisions:
+// 01-08-92 KJB First.
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+// 04-07-93 KJB Added routines to deal with words.
+//
+//------------------------------------------------------------------------
+
+VOID PortIOClear(PBASE_REGISTER baseIoAddress, UCHAR mask);
+VOID PortIOSet(PBASE_REGISTER baseIoAddress, UCHAR mask);
+BOOLEAN PortIOTest(PBASE_REGISTER baseIoAddress, UCHAR mask);
+VOID PortIOClearWord(PBASE_REGISTER baseIoAddress, USHORT mask);
+VOID PortIOSetWord(PBASE_REGISTER baseIoAddress, USHORT mask);
+BOOLEAN PortIOTestWord(PBASE_REGISTER baseIoAddress, USHORT mask);
+
+//
+// Generic Port Access Macros
+//
+#define PortIOGet(baseIoAddress,tmp) \
+ *tmp = ScsiPortReadPortUchar(baseIoAddress);
+
+#define PortIOPut(baseIoAddress,tmp) \
+ ScsiPortWritePortUchar(baseIoAddress,tmp);
+
+#define PortIOGetWord(baseIoAddress,tmp) \
+ *tmp = ScsiPortReadPortUshort(baseIoAddress);
+
+#define PortIOPutWord(baseIoAddress,tmp) \
+ ScsiPortWritePortUshort(baseIoAddress,tmp);
+
+
diff --git a/private/ntos/miniport/trantor/include/portmem.h b/private/ntos/miniport/trantor/include/portmem.h
new file mode 100644
index 000000000..1e99db5c3
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/portmem.h
@@ -0,0 +1,25 @@
+//-----------------------------------------------------------------------
+// FILE: PORTMEM.H
+//
+// Memory Mapped Port Access Definitions File
+//
+// Revisions:
+// 01-08-92 KJB First.
+// 02-25-93 KJB Renamed routines from CardPort to PortMem
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+//
+//-----------------------------------------------------------------------
+
+VOID PortMemClear(PUCHAR baseIoAddress, UCHAR mask);
+VOID PortMemSet(PUCHAR baseIoAddress, UCHAR mask);
+BOOLEAN PortMemTest(PUCHAR baseIoAddress, UCHAR mask);
+
+//
+// Generic Port Access Macros
+//
+#define PortMemGet(baseIoAddress,tmp) \
+ *tmp = ScsiPortReadRegisterUchar(baseIoAddress);
+
+#define PortMemPut(baseIoAddress,tmp) \
+ ScsiPortWriteRegisterUchar(baseIoAddress,tmp);
+
diff --git a/private/ntos/miniport/trantor/include/scsifnc.h b/private/ntos/miniport/trantor/include/scsifnc.h
new file mode 100644
index 000000000..f17892bb1
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/scsifnc.h
@@ -0,0 +1,42 @@
+//-------------------------------------------------------------------------
+//
+// FILE: SCSIFNC.H
+//
+// SCSIFNC Definitions File
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 02-19-93 KJB Added support for data underrun and return of actual
+// transfer size.
+// 03-11-93 JAP Changed TSRB direction flag definitions from
+// TSRB_READ/WRITE to TRSBD_READ/WRITE.
+// Added TSRBD_UNKNOWN
+// 03-11-93 KJB Changed dir flag names and others in TSRB structure.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-22-93 KJB Reorged for stub function library, TSRB def moved
+// to typedefs.h.
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+//
+//-------------------------------------------------------------------------
+
+#ifndef _SCSIFNC_H
+#define _SCSIFNC_H
+
+//
+// Public Functions
+//
+
+USHORT ScsiWriteBytesSlow (PADAPTER_INFO g, UCHAR FARP pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT ScsiReadBytesSlow (PADAPTER_INFO g, UCHAR FARP pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT ScsiSendCommand (PADAPTER_INFO g, UCHAR target,
+ UCHAR lun, UCHAR FARP pcmd, UCHAR cmdlen);
+USHORT ScsiGetStat (PADAPTER_INFO g, PUCHAR pstatus);
+USHORT ScsiDoIo(PTSRB t);
+USHORT ScsiFinishCommandInterrupt (PTSRB t);
+USHORT ScsiStartCommandInterrupt (PTSRB t);
+USHORT ScsiDoCommand (PTSRB t);
+
+#endif // _SCSIFNC_H
+
diff --git a/private/ntos/miniport/trantor/include/scsiport.h b/private/ntos/miniport/trantor/include/scsiport.h
new file mode 100644
index 000000000..67504878a
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/scsiport.h
@@ -0,0 +1,40 @@
+//-------------------------------------------------------------------------
+//
+// FILE: scsiport.h
+//
+// Contains routine definitions for the operating system independent
+// procedures to access i/o and memory locations.
+//
+// Revisions:
+// 03-09-93 KJB First.
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+//
+//-------------------------------------------------------------------------
+
+UCHAR ScsiPortReadPortUchar (PUCHAR Port);
+USHORT ScsiPortReadPortUshort (PUSHORT Port);
+ULONG ScsiPortReadPortUlong (PULONG Port);
+VOID ScsiPortReadPortBufferUchar (PUCHAR Port, PUCHAR Buffer, ULONG Count);
+VOID ScsiPortReadPortBufferUshort (PUSHORT Port, PUSHORT Buffer, ULONG Count);
+VOID ScsiPortReadPortBufferUlong (PULONG Port, PULONG Buffer, ULONG Count);
+UCHAR ScsiPortReadRegisterUchar (PUCHAR Register);
+USHORT ScsiPortReadRegisterUshort (PUSHORT Register);
+ULONG ScsiPortReadRegisterUlong (PULONG Register);
+VOID ScsiPortStallExecution (ULONG Delay);
+VOID ScsiPortWritePortUchar (PUCHAR Port, UCHAR Value);
+VOID ScsiPortWritePortUshort (PUSHORT Port, USHORT Value);
+VOID ScsiPortWritePortUlong (PULONG Port, ULONG Value);
+VOID ScsiPortWritePortBufferUchar (PUCHAR Port, PUCHAR Buffer, ULONG Count);
+VOID ScsiPortWritePortBufferUshort (PUSHORT Port, PUSHORT Buffer, ULONG Count);
+VOID ScsiPortWritePortBufferUlong (PULONG Port, PULONG Buffer, ULONG Count);
+VOID ScsiPortWriteRegisterUchar (PUCHAR Register, UCHAR Value);
+VOID ScsiPortWriteRegisterUshort (PUSHORT Register, USHORT Value);
+VOID ScsiPortWriteRegisterUlong (PULONG Register, ULONG Value);
+
+#if DBG
+VOID ScsiDebugPrint (ULONG DebugPrintLevel, PCCHAR DebugMessage, ...);
+#else
+
+#define ScsiDebugPrint
+
+#endif // DBG
diff --git a/private/ntos/miniport/trantor/include/sl386.h b/private/ntos/miniport/trantor/include/sl386.h
new file mode 100644
index 000000000..4e8a61e94
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/sl386.h
@@ -0,0 +1,202 @@
+//-----------------------------------------------------------------------
+//
+// SL386.H
+//
+// Trantor SL386 Definitions File
+//
+// Revisions:
+// 04-07-93 KJB First, taken from SL386.def.
+// 05-17-93 KJB Added missing prototype.
+//
+//-----------------------------------------------------------------------
+
+//-----------------------------------------------------------------------
+// 80386SL unit configuration spaces
+//
+// Perform the following sequence of IOs to unlock the
+// CPUPWRMODE register.
+//
+// byte write 0h to port 23h
+// byte write 80h to port 22h
+// word write 0080h to port 22h
+//
+// CPUPWRMODE bit definitions:
+//
+// Bit 15: IOCFGOPN
+//
+// Bits 14-9: Not defined here
+//
+// Bit 8: CPUCNFG lock
+//
+// Bits 7-4: Not defined here
+//
+// Bits 3,2: UID1 UID0
+// 0 0 CMCU (Mem ctlr unit cfg space)
+// 0 1 CU (Cache unit cfg space)
+// 1 0 IBU (Internal bus unit cfg space)
+// 1 1 EBU (External bus unit cfg space)
+//
+// Bit 1: Unit enable
+//
+// Bit 0: Unlock status
+//-----------------------------------------------------------------------
+
+#define SL_CPUPWRMODE 0x22
+
+//cpupwrmode_rec record pm_iocfgopn:1,pm_resv:6,pm_cfg_lock:1,
+//pm_resv1:4,pm_uid:2,pm_ue:1,pm_ls:1
+
+#define PM_IOCFGOPN 0x8000
+#define PM_RESV 0x7e00
+#define PM_CFG_LOCK 0x0100
+#define PM_RESV1 0x00f0
+#define PM_UID 0x00c0
+#define PM_UE 0x0002
+#define PM_LS 0x0001
+
+#define PM_UID_CMCU 0x00
+#define PM_UID_CU 0x40
+#define PM_UID_IBU 0x80
+#define PM_UID_EBU 0xc0
+
+
+//-----------------------------------------------------------------------
+// 80386SL configuration space
+//-----------------------------------------------------------------------
+
+// Read the following I/O addresses in the specified order to
+// enable the 386SL configuration space.
+
+#define SL_CNFG_ENA1 0x0fc23
+#define SL_CNFG_ENA2 0x0f023
+#define SL_CNFG_ENA3 0x0c023
+#define SL_CNFG_ENA4 0x00023
+
+#define SL_CFG_STATUS 0x23 //Config space status
+#define SL_CFG_INDEX 0x24 //Config space index
+#define SL_CFG_DATA 0x25 //Config space data
+
+#define SL_IDXLCK 0x0fa //Cfg index lock register
+#define SL_IDXLCK_VAL 0x01 //default value for same
+
+
+//-----------------------------------------------------------------------
+// CFGR2 bit definitions
+//
+// Bit 7: COMA_MIDI
+//
+// Bits 6-4: AIRQ2 AIRQ1 AIRQ0
+// 0 0 0 COMA IRQ3
+// 0 0 1 COMA IRQ4
+// 0 1 0 COMA IRQ10
+// 0 1 1 COMA IRQ11
+// 1 0 0 COMA IRQ12
+// 1 0 1 COMA IRQ15
+//
+// Bit 3: SFIO_EN
+//
+// Bit 2: FD_SEL
+//
+// Bit 1: HD_SEL
+//
+// Bit 0: PS2_EN
+//-----------------------------------------------------------------------
+
+#define SL_CFGR2 0x61 //CFGR2 register index
+
+//cfgr2_rec record c2_midi:1,c2_airq:3,c2_sfio:1,c2_fd:1,c2_hd:1,c2_ps2:1
+
+#define C2_MIDI 0x80
+#define C2_AIRQ 0x70
+#define C2_SFIO 0x08
+#define C2_FD 0x04
+#define C2_HD 0x02
+#define C2_PS2 0x01
+
+
+//-----------------------------------------------------------------------
+// Special feature control registers
+//-----------------------------------------------------------------------
+
+#define SL_SF_INDEX 0x0ae //Special feature index
+#define SL_SF_DATA 0x0af //Special feature data
+
+#define SL_SFS_DISABLE 0x0f9 //Special feature disable
+#define SL_SFS_ENABLE 0x0fb //Special feature enable
+
+
+//-----------------------------------------------------------------------
+// Bit definitions for FPP control register.
+//
+// Bit 7: 0 = ISA or PS/2 modes
+// 1 = FAST_MODE (EPP)
+//
+// Bit 6: 0 = unidirectional mode
+// 1 = bidirectional mode
+//
+// Bits 5,4: CTL5 CTL4
+// 0 0 Parallel port disabled
+// 0 1 Parallel port LPT1 (378h), IRQ7
+// 1 0 Parallel port LPT2 (278h), IRQ5
+// 1 1 Reserved
+//
+// Bits 0-3: Reserved (0)
+//-----------------------------------------------------------------------
+
+#define SL_FPP_CNTL 0x02 //SFS index for FPP_CNTL
+
+// fpp_cntl_rec record fpp_fm:1,fpp_em:1,fpp_ctl:2,fpp_resv:4
+
+#define FPP_FM 0x80
+#define FPP_EM 0x40
+#define FPP_CTL 0x03
+
+#define FPP_CTL_DIS 0
+#define FPP_CTL_LPT1 0x10
+#define FPP_CTL_LPT2 0x20
+#define FPP_CTL_RESV 0x30
+
+
+//-----------------------------------------------------------------------
+// Bit definitions for PPCONFIG register.
+//
+// Bit 7: 0 = unidirectional mode
+// 1 = bidirectional mode
+//
+// Bit 6,5: LPTSL1 LPTSL0
+// 0 0 Selects LPT1 (IO base 378h)
+// 0 1 Selects LPT2 (IO base 278h)
+// 1 0 Selects LPT3 (IO base 3bch)
+// 1 1 Disables internal parallel port
+//
+// Bits 0-4: Reserved
+//-----------------------------------------------------------------------
+
+#define SL_PPCONFIG 0x102 //PPCONFIG reg
+
+//ppconfig_rec record ppc_bid:1,ppc_sel:2,ppc_resv:5
+
+#define PPC_BID 0x80
+#define PPC_SEL 0x60
+#define PPC_SEL_POS 0x05
+#define PPC_SEL_LPT1 0x00
+#define PPC_SEL_LPT2 0x20
+#define PPC_SEL_LPT3 0x40
+#define PPC_SEL_DIS 0x60
+
+
+//-----------------------------------------------------------------------
+// EPP Parallel port register offsets
+//-----------------------------------------------------------------------
+
+#define EPP_DATA 0x0 //read/write
+#define EPP_STATUS 0x1 //read-only
+#define EPP_CTL 0x2 //read/write
+#define EPP_AUTO_ADDRESS 0x3 //read/write
+#define EPP_AUTO_DATA 0x4 //read/write (also at 5h-7h)
+
+//
+// Exported functions.
+//
+
+BOOLEAN SL386EnableEPP(VOID );
diff --git a/private/ntos/miniport/trantor/include/status.h b/private/ntos/miniport/trantor/include/status.h
new file mode 100644
index 000000000..a1079b376
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/status.h
@@ -0,0 +1,58 @@
+//-------------------------------------------------------------------------
+//
+// FILE: status.h
+//
+// Contains scsi status messages.
+//
+// Note: These errors are returned by the lower level drivers functions.
+// At an even lower level, the functions either return these values or
+// 0, where 0 indicates no error; but for cases where the card routines
+// are passed a TSRB, 0 means SRB_STATUS_PENDING, and 1 means SRB_STATUS_
+// SUCCESS.
+//
+// Revisions:
+// 03-09-93 KJB First.
+// 03-11-93 JAP Changed #defines to reflect more appropriate meaning
+// 03-23-93 KJB Added RET_STATUS_MISSED_INTERRUPT.
+//
+//-------------------------------------------------------------------------
+
+
+#if DBG
+#define DebugPrint(x) ScsiDebugPrint x
+#else
+#define DebugPrint(x)
+#endif
+
+//
+// Return Value Definitions
+//
+
+#define RET_STATUS_PENDING 0x00
+#define RET_STATUS_SUCCESS 0x01
+#define RET_STATUS_ABORTED 0x02
+#define RET_STATUS_ABORT_FAILED 0x03
+#define RET_STATUS_ERROR 0x04
+#define RET_STATUS_BUSY 0x05
+#define RET_STATUS_INVALID_REQUEST 0x06
+#define RET_STATUS_INVALID_PATH_ID 0x07
+#define RET_STATUS_NO_DEVICE 0x08
+#define RET_STATUS_TIMEOUT 0x09
+#define RET_STATUS_SELECTION_TIMEOUT 0x0A
+#define RET_STATUS_COMMAND_TIMEOUT 0x0B
+#define RET_STATUS_MESSAGE_REJECTED 0x0D
+#define RET_STATUS_BUS_RESET 0x0E
+#define RET_STATUS_PARITY_ERROR 0x0F
+#define RET_STATUS_REQUEST_SENSE_FAILED 0x10
+#define RET_STATUS_NO_HBA 0x11
+#define RET_STATUS_DATA_OVERRUN 0x12
+#define RET_STATUS_UNEXPECTED_BUS_FREE 0x13
+#define RET_STATUS_PHASE_SEQ_FAILURE 0x14
+#define RET_STATUS_BAD_SRB_BLOCK_LENGTH 0x15
+#define RET_STATUS_REQUEST_FLUSHED 0x16
+#define RET_STATUS_INVALID_LUN 0x20
+#define RET_STATUS_INVALID_TARGET_ID 0x21
+#define RET_STATUS_BAD_FUNCTION 0x22
+#define RET_STATUS_ERROR_RECOVERY 0x23
+#define RET_STATUS_MISSED_INTERRUPT 0x101
+
diff --git a/private/ntos/miniport/trantor/include/t128.h b/private/ntos/miniport/trantor/include/t128.h
new file mode 100644
index 000000000..7d247b6ad
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/t128.h
@@ -0,0 +1,79 @@
+//-----------------------------------------------------------------------
+//
+// T128.H
+//
+// Trantor T128 Definitions File
+//
+// This file contains definitions specific to the logic used on the T128
+// parallel to scsi adapter.
+//
+// Revisions:
+// 02-25-92 KJB First.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+//
+//-----------------------------------------------------------------------
+
+//
+// T128 Specific Hardware Definitions
+//
+
+// T128 Registers
+
+#define T128_RAM 0x0000
+#define T128_ROM 0x1800
+#define T128_CONTROL 0x1C00
+#define T128_STATUS 0x1C20
+#define T128_5380 0x1D00
+#define T128_DATA 0x1E00
+
+// control register definitions
+
+#define CR_UNUSED 0xe0
+#define CR_INTENB 0x10
+#define CR_SCSIWRITE 0x8
+#define CR_SCSIREAD 0x4
+#define CR_TIMEOUT 0x2
+#define CR_16BIT 0x1
+
+// status registers
+
+#define SR_SW5 0x80
+#define SR_SW4 0x40
+#define SR_SW3 0x20
+#define SR_SW2 0x10
+#define SR_PS2 0x8
+#define SR_XFR_READY 0x4
+#define SR_TIMEOUT 0x2
+#define SR_16BIT 0x1
+
+#define SR_ROM_ENABLED SR_SW5
+#define SR_DISABLE_TIMEOUT SR_SW4
+
+// Each T128 has a 5380 built in
+
+#define N5380PortPut(g,reg,byte) \
+ T128PortPut(g,T128_5380+reg*0x20,byte)
+
+#define N5380PortGet(g,reg,byte) \
+ T128PortGet(g,T128_5380+reg*0x20,byte)
+
+//
+// public functions
+//
+
+USHORT T128WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT T128ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+VOID T128EnableInterrupt (PADAPTER_INFO g);
+VOID T128DisableInterrupt (PADAPTER_INFO g);
+VOID T128ResetBus (PADAPTER_INFO g);
diff --git a/private/ntos/miniport/trantor/include/t338.h b/private/ntos/miniport/trantor/include/t338.h
new file mode 100644
index 000000000..665fada0a
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/t338.h
@@ -0,0 +1,68 @@
+//-------------------------------------------------------------------------
+//
+// T338.H
+//
+// Trantor T338 Definitions File
+//
+// This file contains definitions specific to the logic used on the T338
+// parallel to scsi adapter.
+//
+// Revisions:
+// 02-01-92 KJB First.
+// 03-12-93 KJB Now supports polling thru CardInterrupt and
+// StartCommandInterrupt/FinishCommandInterrupt.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-25-93 JAP Fixed up prototype typedef inconsistencies
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+//
+//-------------------------------------------------------------------------
+
+// T338 control
+
+#define T338_RES 0xc0
+#define T338_MODE 0x38
+#define T338_ADRS 0x07
+
+// T338 Modes
+
+#define T338_MR 0x20
+#define T338_IOW 0x10
+#define T338_IOR 0x08
+
+//
+// Public Functions
+//
+
+// for the 5380 that is in the T338
+
+void N5380PortGet(PADAPTER_INFO g,UCHAR reg,PUCHAR byte);
+void N5380PortPut(PADAPTER_INFO g,UCHAR reg,UCHAR byte);
+
+// for the parallel port the T338 uses
+
+#define ParallelPortGet(baseIoAddress, reg, byte) \
+ PortIOGet((PUCHAR)baseIoAddress+reg,byte)
+#define ParallelPortPut(baseIoAddress,reg,byte) \
+ PortIOPut((PUCHAR)baseIoAddress+reg,byte)
+
+// exported T338 functions
+
+BOOLEAN T338CheckAdapter (PADAPTER_INFO g);
+VOID T338ResetBus (PADAPTER_INFO g);
+USHORT T338DoCommand (PTSRB t);
+USHORT T338StartCommandInterrupt (PTSRB t);
+USHORT T338FinishCommandInterrupt (PTSRB t);
+BOOLEAN T338Interrupt (PADAPTER_INFO g);
+USHORT T338WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT T338ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT T338DoIo (PTSRB t);
+
diff --git a/private/ntos/miniport/trantor/include/trantor.h b/private/ntos/miniport/trantor/include/trantor.h
new file mode 100644
index 000000000..ce1054ca5
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/trantor.h
@@ -0,0 +1,28 @@
+//
+// FILE: TRANTOR.H
+//
+// Trantor General Definitions File
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 01-12-93 KJB Added AddressRange structure to determine resources used.
+// 03-22-93 KJB Reorged for stub function library.
+// 04-05-93 KJB Removed unused HOST_ID define.
+//
+
+// wait upto 1 sec for request to come back from target
+#define TIMEOUT_REQUEST 1000000
+
+// wait timeout for a request loop during a fast read
+// this is # of times to loop 0x10000 times
+#define TIMEOUT_READWRITE_LOOP 0x40
+
+// wait upto 1 sec for busy to disappear from scsi bus
+#define TIMEOUT_BUSY 1000000
+
+// wait upto 250 msec for target to be selected
+#define TIMEOUT_SELECT 250000
+
+// wait in a for loop up to TIMEOUT_QUICK times
+#define TIMEOUT_QUICK 10000
+
diff --git a/private/ntos/miniport/trantor/include/typedefs.h b/private/ntos/miniport/trantor/include/typedefs.h
new file mode 100644
index 000000000..4599a4588
--- /dev/null
+++ b/private/ntos/miniport/trantor/include/typedefs.h
@@ -0,0 +1,274 @@
+//-----------------------------------------------------------------------
+//
+// typedefs.h
+//
+// Contains general useful typedefs and defines.
+//
+// History:
+// 03-09-93 KJB First.
+// 03-17-93 JAP Added #ifndef _TYPEDEFS_H to prevent re-definitions
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-22-93 KJB Reorged for stub function library.
+// 03-24-93 KJB Added support for Scatter Gather Lists. This idea
+// Scatter gather has not been added yet, time is
+// not available now.
+// 03-25-93 JAP Added TSRB_DIR_NONE for those SCSI cmds without data
+// 04-06-93 KJB Define HOST_ID here for used outside library.
+// 04-09-93 KJB Added FARP and NEARP defs for WINNT.
+// 05-13-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters. Auto Request Sense is
+// now supported. TSRB Structure changed.
+// 05-13-93 KJB Added RequestSenseValid field to TSRB.
+// 05-14-93 KJB Added BaseIoAddress entry to PINIT structure.
+// 05-17-93 KJB Added ifndef WINNT around some typedefs to
+// prevent multiple definitions for WINNT.
+// 05-17-93 KJB Added ErrorLogging capabilities (used by WINNT).
+//
+//-----------------------------------------------------------------------
+
+#ifndef _TYPEDEFS_H
+#define _TYPEDEFS_H
+
+ #ifndef CONST
+#define CONST const
+ #endif
+
+ #ifdef NOVELL
+#define FARP *
+#define NEARP *
+ #else
+ #ifdef WINNT
+#define FARP *
+#define NEARP *
+ #else
+#define FARP far *
+#define NEARP near *
+ #endif
+ #endif
+
+#ifndef WINNT
+//
+// Void
+//
+
+typedef void FARP PVOID;
+
+//
+// Basics
+//
+
+#ifndef VOID
+#define VOID void
+typedef char CHAR;
+typedef short SHORT;
+typedef long LONG;
+#endif
+
+//
+// ANSI
+//
+
+typedef CHAR FARP PCHAR;
+
+//
+// Pointer to Basics
+//
+
+typedef SHORT FARP PSHORT;
+typedef LONG FARP PLONG;
+
+//
+// Unsigned Basics
+//
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+
+//
+// Pointer to Unsigned Basics
+//
+
+typedef UCHAR FARP PUCHAR;
+typedef UCHAR NEARP NPUCHAR;
+typedef USHORT FARP PUSHORT;
+typedef ULONG FARP PULONG;
+
+//
+// Signed characters
+//
+
+typedef signed char SCHAR;
+typedef SCHAR FARP PSCHAR;
+
+//
+// Cardinal Data Types [0 - 2**N-2)
+//
+
+typedef char CCHAR;
+typedef short CSHORT;
+typedef ULONG CLONG;
+
+typedef CCHAR FARP PCCHAR;
+typedef CSHORT FARP PCSHORT;
+typedef CLONG FARP PCLONG;
+
+//
+// Boolean
+//
+
+typedef CCHAR BOOLEAN; // winnt
+typedef BOOLEAN FARP PBOOLEAN; // winnt
+
+#define FALSE 0
+#define TRUE 1
+#ifndef NULL
+#define NULL ((PVOID)0)
+#endif // NULL
+
+#endif // WINNT
+
+//---------------------------------------------------------------------
+// TSRB and related...
+//---------------------------------------------------------------------
+
+//
+// Scatter Gather Emulation Array
+//
+
+typedef struct tagSCATGATENTRY {
+ PUCHAR buffer;
+ ULONG len;
+} SCATTERGATHERENTRY, FARP PSCATTERGATHERENTRY;
+
+//
+// Flags for the TSRB
+//
+
+typedef struct tagTSRBFLAGS {
+ USHORT DoRequestSense : 1;
+ USHORT RequestSenseValid : 1;
+// USHORT UseScatterGather : 1;
+} TSRBFLAGS;
+
+//
+// The TSRB STRUCTURE
+//
+
+typedef struct tagTSRB {
+ PVOID pWorkspace; // private per-adapter workspace
+ UCHAR Target; // SCSI target id
+ UCHAR Lun; // Logical Unit
+ PUCHAR pCommand; // pointer to SCSI command
+ UCHAR CommandLen; // length of SCSI command
+ UCHAR Dir; // TSRB_READ, TSRB_WRITE, or TSRB_UNKNOWN
+ PUCHAR pData; // pointer to data
+ ULONG DataLen; // length of data transfer
+ ULONG ActualDataLen; // actual amt of data transferred
+ UCHAR Status; // SCSI status byte
+ PUCHAR pSenseData; // location to store sense data
+ UCHAR SenseDataLen; // len of sense data
+ TSRBFLAGS Flags; // boolean values
+ USHORT ReturnCode; // such as RET_STATUS_PENDING, like the func returns
+// UCHAR NumScatGatEntry; // number of entries in scat gat list
+// PSCATTERGATHERENTRY pScatGatEntry; // pointer to scatter gather list
+} TSRB, FARP PTSRB;
+
+
+// defines for direction
+
+#define TSRB_DIR_IN 0
+#define TSRB_DIR_OUT 1
+#define TSRB_DIR_UNKNOWN 2
+#define TSRB_DIR_NONE TSRB_DIR_IN
+
+// host id for the card
+
+#define HOST_ID 0x07
+
+//---------------------------------------------------------------------
+// a generic pointer for card registers
+//---------------------------------------------------------------------
+
+typedef PVOID PBASE_REGISTER;
+typedef PVOID PWORKSPACE;
+
+//---------------------------------------------------------------------
+// CARD SPECIFIC INITIALIZATION DEFINITIONS
+//---------------------------------------------------------------------
+
+// definitions for Parallel Port Type, used by parallel adapters
+
+#define PT_UNKNOWN 0
+#define PT_UNI 1
+#define PT_BI 2
+#define PT_EPP 3
+
+//
+// Initialization information for all cards.
+//
+typedef struct tagInit {
+
+ // the baseIoAddress, used by all cards.
+
+ PBASE_REGISTER BaseIoAddress;
+
+ // used only for media-vision cards
+
+ UCHAR InterruptLevel;
+
+ // used only for parallel cards: T358, T348
+
+ UCHAR ParallelPortType; // the type of parallel port being used
+
+ // used only for T358
+
+ UCHAR Delay; // amount of delay for t358
+
+} INIT, FARP PINIT;
+
+//---------------------------------------------------------------------
+// Used only by WINNT...
+//---------------------------------------------------------------------
+
+#ifdef WINNT
+
+//
+// The following is used along with the constant structure in card.c
+// to define the precise i/o address a card will use
+//
+typedef struct tagCardAddressRange {
+ ULONG offset; // offset from base address
+ ULONG length; // length in memory
+ BOOLEAN memory; // is this address range in memory??
+} CardAddressRange;
+extern const CardAddressRange cardAddressRange[];
+
+//
+// DEBUG LOGGING UTILITY
+//
+VOID TrantorLogError(PBASE_REGISTER IoAddress,USHORT TrantorErrorCode,
+ ULONG UniqueId);
+
+#else
+
+// do nothing for the other operating systems
+
+//
+// DEBUG LOGGING UTILITY
+//
+#define TrantorLogError(IoAddress,TrantorErrorCode,UniqueId)
+
+#endif
+
+//---------------------------------------------------------------------
+
+#endif //_TYPEDEFS_H
+
diff --git a/private/ntos/miniport/trantor/source/cardt128.c b/private/ntos/miniport/trantor/source/cardt128.c
new file mode 100644
index 000000000..c86faea98
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/cardt128.c
@@ -0,0 +1,377 @@
+//------------------------------------------------------------------------
+// CARDT128.C
+//
+// T128 Adapter Specific File
+//
+// See also cardtxxx.h, cardtxxx.h may redefine some functions with #defines.
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 01-08-93 KJB Moved CardPort routines to port.c.
+// 02-18-93 KJB Allowed for data underrun for read & write.
+// 02-25-93 KJB Reorganized routines.
+// 03-23-93 KJB Reorged for functional library interface.
+// 03-26-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-05-93 KJB Fixed definition problem for WINNT.
+// Involving CardAddressRange...
+// 04-26-93 JAP Added AdapterInterrupts[] and CardGetIRQ().
+// 05-05-93 KJB Fixed CheckAdapter to check timeout condition
+// So that memory won't seem like an adapter.
+// 05-06-93 KJB Merged some Microsoft code to make CheckAdapter
+// more stringent.
+// 05-12-93 JAP Altered CardGetShortName() to return only
+// the type of card.
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+//
+//------------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+#ifdef WINNT
+//------------------------------------------------------------------------
+// The address ranges the card will use. These are accessed by trantor.c
+// to inform NTOS of the resources we are using.
+//------------------------------------------------------------------------
+
+const CardAddressRange cardAddressRange [] =
+ {
+ {0x00,0x2000,TRUE},
+ };
+
+#endif
+
+//------------------------------------------------------------------------
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+#ifdef MODE_32BIT
+CONST ULONG AdapterAddresses [] =
+ {0XCC000, 0XC8000, 0XDC000, 0XD8000, 0};
+#else
+CONST ULONG AdapterAddresses [] =
+ {0XCC000000, 0XC8000000, 0XDC000000, 0XD8000000, 0};
+#endif
+
+
+//------------------------------------------------------------------------
+// The following table specifies the possible interrupts that
+// can be used by the adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST USHORT AdapterInterrupts [] =
+ {3, 5, 7, 10, 12, 14, 15, 0};
+
+//-----------------------------------------------------------------------
+//
+// The following routines are stub routines to provide an entry
+// point for the library. They reference the correct routines for
+// the appropriate card. Only these routines may be called from outside
+// the library. See the rouines they reference for a description of
+// the rouines, if the meaning is unclear.
+//
+//-----------------------------------------------------------------------
+
+//-----------------------------------------------------------------------
+// the maximum transfer size
+// by decreasinge this we can get better system performace since
+// the data transfer occurs with interrupts disabled, this might be
+// decreased for our smaller cards
+// Used only by WINNT
+//-----------------------------------------------------------------------
+
+ULONG CardMaxTransferSize (VOID)
+{
+ return 16*1024L;
+}
+
+
+// we use interrupts
+
+BOOLEAN CardSupportsInterrupts (VOID)
+{
+ return TRUE;
+}
+
+
+// default interrupt number is 5
+
+#define CARD_DEFAULT_INTERRUPT_LEVEL 5
+
+UCHAR CardDefaultInterruptLevel (VOID)
+{
+ return 5;
+}
+
+
+// the following info is for initialization only
+// this card is memory mapped
+
+BOOLEAN CardAddressRangeInIoSpace (VOID)
+{
+ return FALSE;
+}
+
+// we use 0x2000 bytes in memory space
+
+USHORT CardAddressRangeLength (VOID)
+{
+ return 0x2000;
+}
+
+
+// The following is used along with the constant structure in card.c
+// to define the precise i/o addresses a card will use
+
+USHORT CardNumberOfAddressRanges (VOID)
+{
+ return 1;
+}
+
+
+USHORT CardStartCommandInterrupt (PTSRB t)
+{
+ return ScsiStartCommandInterrupt (t);
+}
+
+
+USHORT CardDoCommand (PTSRB t)
+{
+ return ScsiDoCommand (t);
+}
+
+
+USHORT CardFinishCommandInterrupt (PTSRB t)
+{
+ return ScsiFinishCommandInterrupt (t);
+}
+
+
+BOOLEAN CardInterrupt (PADAPTER_INFO g)
+{
+ return N5380Interrupt (g);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// BOOLEAN CardCheckAdapter
+//
+// This routine checks for the presense of the card.
+// Initializes a workspace for the adapter at this address.
+// Returns TRUE if adapter found.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN CardCheckAdapter (PWORKSPACE w, PINIT init)
+{
+ PADAPTER_INFO g = (PADAPTER_INFO) w;
+ UCHAR tmp0,tmp1,tmp2;
+ UCHAR tmp;
+ UCHAR rval;
+ ULONG index;
+
+ //
+ // Initialize workspace and takes card specific parameter information
+ // Just the BaseIoAddress for the t13b.
+ //
+
+ g->BaseIoAddress = init->BaseIoAddress;
+
+ // save old values of control and status
+
+ T128PortGet(g,T128_CONTROL,&tmp0);
+ T128PortGet(g,T128_STATUS,&tmp1);
+
+ // check the timeout bit of the t128
+
+ // this should set the timeout bit
+
+ T128PortGet(g,T128_DATA,&tmp2);
+
+ if (!T128PortTest(g,T128_STATUS,SR_TIMEOUT)) {
+
+ // this is not a t128, restore registers
+
+ T128PortPut(g,T128_CONTROL,tmp0);
+ T128PortPut(g,T128_STATUS,tmp1);
+
+ return FALSE;
+ }
+
+ // clear timeout condition
+
+ T128PortPut(g,T128_CONTROL,CR_TIMEOUT);
+ T128PortPut(g,T128_CONTROL,0);
+
+ //
+ // The t128 has a 32 byte stride on the access to the 5380 registers.
+ // Taking advantage of this stride a check is first made that each of
+ // the location in the stride have the same value. After this is
+ // complete, the same destructive scan is made for the data value as
+ // for other 5380 based adapters.
+ //
+
+ N5380PortGet (g, N5380_CURRENT_DATA, &tmp);
+
+ for (index = 0; index < 0x20; index++) {
+ T128PortGet (g,
+ T128_5380+(N5380_CURRENT_DATA*0x20)+index,
+ &rval);
+ if (rval != tmp) {
+ return FALSE;
+ }
+ }
+
+ N5380PortGet (g, N5380_INITIATOR_COMMAND, &tmp);
+
+ for (index = 0; index < 0x20; index++) {
+ T128PortGet (g,
+ T128_5380+(N5380_INITIATOR_COMMAND*0x20)+index,
+ &rval);
+ if (rval != tmp) {
+ return FALSE;
+ }
+ }
+
+ N5380PortGet (g, N5380_CURRENT_STATUS, &tmp);
+
+ for (index = 0; index < 0x20; index++) {
+ T128PortGet (g,
+ T128_5380+(N5380_CURRENT_STATUS*0x20)+index,
+ &rval);
+ if (rval != tmp) {
+ return FALSE;
+ }
+ }
+
+ //
+ // The non-destructive portion of this has passed.
+ // NOTE: May want to reset the bus or the adapter at some point
+ //
+ // CardResetBus(g);
+
+ // set the phase to NULL
+
+ if (rval = (UCHAR) N5380SetPhase (g,PHASE_NULL)) {
+ return FALSE;
+ }
+
+ // check to see that the 5380 data register behaves as expected
+
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, IC_DATA_BUS);
+
+ // check for 0x55 write/read in data register stride
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, 0x55);
+ ScsiPortStallExecution (1);
+ for (index = 0; index < 0x20; index++) {
+ T128PortGet (g,
+ T128_5380+(N5380_CURRENT_DATA*0x20)+index,
+ &rval);
+ if (rval != 0x55) {
+ return FALSE;
+ }
+ }
+
+ // check for 0xaa write/read in data register stride
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, 0xaa);
+ ScsiPortStallExecution (1);
+ for (index = 0; index < 0x20; index++) {
+ T128PortGet (g,
+ T128_5380+(N5380_CURRENT_DATA*0x20)+index,
+ &rval);
+ if (rval != 0xaa) {
+ return FALSE;
+ }
+ }
+
+ //
+ // It is pretty clear this is a 128, but do one last check for
+ // the 5380.
+ //
+
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, 0);
+ ScsiPortStallExecution (1);
+ N5380PortGet (g, N5380_CURRENT_DATA, &tmp);
+
+ // data now should not match ....
+
+ if (tmp == 0xaa) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//
+// CardParseCommandString(PINIT p, PCHAR str)
+//
+// Parses the command string to get all card specific parameters.
+// Will fill in defaults where no parameters are supplied, or
+// if the str pointer is NULL.
+//
+// Returns false if it could not parse the string given.
+//
+// Can be used to parse the string piece by piece, by sending
+// the same INIT structure each time. Send NULL as the string
+// first time to initialize the PINIT structure to the standard defaults.
+//
+// BaseIoAddress will be set to NULL by default, and the program can
+// detect that it has changed during parsing and just search for the
+// card as specified by the command line argument if it has changed. If
+// it does not change, the program should cycle through all valid addresses.
+//
+BOOLEAN CardParseCommandString(PINIT init, PCHAR str)
+{
+ // for now, just fill in some defaults
+
+ init->BaseIoAddress = NULL;
+
+ return TRUE;
+}
+
+
+void CardSetInterruptLevel (PADAPTER_INFO g, UCHAR level)
+{
+ return;
+}
+
+
+PUCHAR CardGetName (VOID)
+{
+ return "T128 SCSI Host Adapter";
+}
+
+
+PUCHAR CardGetShortName (VOID)
+{
+ return "T128";
+}
+
+
+UCHAR CardGetType (VOID)
+{
+ return CARDTYPE_T120;
+}
+
+
+VOID CardDisableInterrupt (PADAPTER_INFO g)
+{
+ T128DisableInterrupt(g);
+}
+
+
+VOID CardEnableInterrupt (PADAPTER_INFO g)
+{
+ T128EnableInterrupt (g);
+}
+
+
+VOID CardResetBus (PADAPTER_INFO g)
+{
+ T128ResetBus (g);
+}
+
+
diff --git a/private/ntos/miniport/trantor/source/cardt13b.c b/private/ntos/miniport/trantor/source/cardt13b.c
new file mode 100644
index 000000000..468aa4e11
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/cardt13b.c
@@ -0,0 +1,299 @@
+//-----------------------------------------------------------------------
+//
+// CARDT13B.C
+//
+// T13B Adapter Specific File
+//
+// See also cardtxxx.h, cardtxxx.h may redefine some functions with #defines.
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 01-08-92 KJB Now use ScsiPortWrite[Read]BufferUshort routines.
+// 02-17-93 JAP Cleaned comments.
+// 02-18-93 KJB Fixed Cleaned comments.
+// 02-24-93 KJB Restructured file.
+// 03-22-93 JAP Added arrays for port and IRQ values for NetWare support.
+// These are conditionally built if NOVELL is defined.
+// 03-22-93 KJB Reorged for functional library interface.
+// 03-26-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-22-93 JAP Added AdapterInterrupts[] and CardGetIRQ().
+// 05-05-93 KJB Added check of T13B_SWITCH register in CheckAdapter.
+// So we won't interfere with a T160.
+// 05-12-93 JAP Altered CardGetShortName() to return only
+// the type of card.
+// 05-13-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters. Auto Request Sense is
+// now supported.
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+//
+//-----------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+//-----------------------------------------------------------------------
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//-----------------------------------------------------------------------
+
+CONST ULONG AdapterAddresses [] = {0X350, 0X340, 0X250, 0X240, 0};
+
+#ifdef WINNT
+//-----------------------------------------------------------------------
+//
+// The address ranges the card will use. These are accessed by trantor.c
+// to inform NTOS of the resources we are using.
+//
+//-----------------------------------------------------------------------
+
+CONST CardAddressRange cardAddressRange [] =
+{
+ {0x00,0x10,FALSE}, // 0x350 - 0x35f
+};
+#endif
+
+
+//------------------------------------------------------------------------
+// The following table specifies the possible interrupts that
+// can be used by the adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST USHORT AdapterInterrupts [] =
+ {3, 5, 7, 0};
+
+
+//-----------------------------------------------------------------------
+//
+// The following routines are stub routines to provide an entry
+// point for the library. They reference the correct routines for
+// the appropriate card. Only these routines may be called from outside
+// the library. See the rouines they reference for a description of
+// the routines, if the meaning is unclear.
+//
+//-----------------------------------------------------------------------
+
+//
+// The following is used along with the constant structure in card.c
+// to define the precise i/o addresses a card will use
+//
+
+USHORT CardNumberOfAddressRanges (VOID)
+{
+ return 1;
+}
+
+
+// the maximum transfer size
+// by decreasing this we can get better system performace since
+// the data transfer occurs with interrupts disabled, this might be
+// decreased for our smaller cards
+// Used only by WINNT
+
+ULONG CardMaxTransferSize (VOID)
+{
+ return (32*1024L);
+}
+
+
+// the following info is for initialization only
+// this card is IO mapped
+
+BOOLEAN CardAddressRangeInIoSpace (VOID)
+{
+ return TRUE;
+}
+
+
+// we use 16 addresses in IO space
+
+USHORT CardAddressRangeLength (VOID)
+{
+ return 16;
+}
+
+
+// we use interrupts
+
+BOOLEAN CardSupportsInterrupts (VOID)
+{
+ return TRUE;
+}
+
+
+// default interrupt level
+
+UCHAR CardDefaultInterruptLevel (VOID)
+{
+ return 5;
+}
+
+
+USHORT CardStartCommandInterrupt (PTSRB t)
+{
+ return (ScsiStartCommandInterrupt (t));
+}
+
+
+USHORT CardFinishCommandInterrupt (PTSRB t)
+{
+ return (ScsiFinishCommandInterrupt (t));
+}
+
+
+USHORT CardDoCommand (PTSRB t)
+{
+ return (ScsiDoCommand (t));
+}
+
+
+//
+// BOOLEAN CardCheckAdapter
+//
+// Initializes a workspace for the adapter at this address.
+// Returns TRUE if adapter found.
+//
+BOOLEAN CardCheckAdapter (PWORKSPACE w, PINIT init)
+{
+ PADAPTER_INFO g = (PADAPTER_INFO) w;
+ UCHAR tmp,tmp0;
+
+ //
+ // Initialize workspace and takes card specific parameter information
+ // Just the BaseIoAddress for the t13b.
+ //
+
+ g->BaseIoAddress = init->BaseIoAddress;
+
+ //
+ // Do a few sanity check reads to see if there is a possibility an
+ // adapter is present at this address.
+ //
+
+ N53C400PortGet(g,N5380_CURRENT_DATA,&tmp);
+ N53C400PortGet(g,N5380_INITIATOR_COMMAND,&tmp0);
+
+ if (tmp == 0xff && tmp0 == 0xff) {
+
+ // nothing there.
+ return FALSE;
+ }
+
+ N53C400PortGet(g,N5380_MODE,&tmp);
+ N53C400PortGet(g,N5380_TARGET_COMMAND,&tmp0);
+
+ if (((tmp & 0xcf) != 0xcf) || ((tmp0 & 0xcf) != 0xcf)) {
+
+ // mode and command always init as 0xff. This is not a 13b
+ return FALSE;
+ }
+
+ // check to see if there is a t160 on this port?
+ // try to write to the switch register.
+
+ N53C400PortGet(g,T13B_SWITCH,&tmp0);
+ N53C400PortPut(g,T13B_SWITCH,0x5c);
+ N53C400PortGet(g,T13B_SWITCH,&tmp);
+
+ // restore original value
+
+ N53C400PortPut(g,T13B_SWITCH,tmp0);
+
+ if (tmp == 0x5c) {
+ // we have a t160, return false
+ return FALSE;
+ }
+
+ return (N53C400CheckAdapter (g));
+}
+
+//
+// CardParseCommandString(PINIT p, PCHAR str)
+//
+// Parses the command string to get all card specific parameters.
+// Will fill in defaults where no parameters are supplied, or
+// if the str pointer is NULL.
+//
+// Returns false if it could not parse the string given.
+//
+// Can be used to parse the string piece by piece, by sending
+// the same INIT structure each time. Send NULL as the string
+// first time to initialize the PINIT structure to the standard defaults.
+//
+BOOLEAN CardParseCommandString(PINIT init, PCHAR str)
+{
+ // for now, just fill in some defaults
+
+ init->BaseIoAddress = NULL;
+
+ return TRUE;
+}
+
+
+BOOLEAN CardInterrupt (PADAPTER_INFO g)
+{
+ return (N5380Interrupt (g));
+}
+
+
+void CardEnableInterrupt (PADAPTER_INFO g)
+{
+ N53C400EnableInterrupt (g);
+}
+
+
+void CardDisableInterrupt (PADAPTER_INFO g)
+{
+ N53C400DisableInterrupt (g);
+}
+
+
+void CardResetBus (PADAPTER_INFO g)
+{
+ N53C400ResetBus (g);
+}
+
+PUCHAR CardGetName (VOID)
+{
+ return "T13B SCSI Host Adapter";
+}
+
+
+PUCHAR CardGetShortName (VOID)
+{
+ return "T130B";
+}
+
+
+UCHAR CardGetType (VOID)
+{
+ return CARDTYPE_T130B;
+}
+
+
+ #ifdef NOVELL
+//-----------------------------------------------------------------------
+// NOVELL Port and IRQ Tables
+//
+// Novell needs these defined in a specific format:
+// long integer array with the number of entries at head of list.
+//-----------------------------------------------------------------------
+
+// The following table specifies the port values Novell will prompt
+// the user with if no port is specified on the LOAD command line.
+
+CONST ULONG possible_port [] = {4, 0X350, 0X340, 0X250, 0X240};
+
+// The following table specifies the IRQ values Novell will prompt
+// the user with if no IRQ is specified on the LOAD command line.
+
+CONST ULONG possible_irq [] = {3, 3, 5, 7};
+
+ #endif // #ifdef NOVELL
+
diff --git a/private/ntos/miniport/trantor/source/cardt160.c b/private/ntos/miniport/trantor/source/cardt160.c
new file mode 100644
index 000000000..2d22df1be
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/cardt160.c
@@ -0,0 +1,273 @@
+//-----------------------------------------------------------------------
+//
+// CARDT160.C
+//
+// T160 Adapter Specific File
+//
+// See also cardtxxx.h, cardtxxx.h may redefine some functions with #defines.
+//
+// Revisions:
+// 02-24-93 KJB First.
+// 03-24-93 KJB Reorged for functional library interface.
+// 03-26-93 JAP Fixed up typedef and prototype inconsistencies
+// 03-29-93 JAP Added arrays for port and IRQ values for NetWare support.
+// These are conditionally built if NOVELL is defined.
+// 04-05-93 KJB Fixed definition problem for WINNT.
+// Involving CardAddressRange...
+// 04-22-93 JAP Added AdapterInterrupts[] and CardGetIRQ().
+// 05-12-93 JAP Altered CardGetShortName() to return only
+// the type of card.
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+// 05-17-93 KJB Fixed warnings.
+//
+//-----------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+
+//------------------------------------------------------------------------
+// The following table specifies the possible interrupts that
+// can be used by the adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST USHORT AdapterInterrupts [] =
+ {3, 5, 7, 10, 12, 14, 15, 0};
+
+
+//-----------------------------------------------------------------------
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//-----------------------------------------------------------------------
+
+CONST ULONG AdapterAddresses [] =
+ {0X350, 0X340, 0X250, 0X240, 0x330, 0x360, 0x230, 0x260, 0};
+
+
+#ifdef WINNT
+//-----------------------------------------------------------------------
+//
+// The address ranges the card will use. These are accessed by trantor.c
+// to inform NTOS of the resources we are using.
+//
+//-----------------------------------------------------------------------
+
+CONST CardAddressRange cardAddressRange [] =
+{
+ {0x00,0x10,FALSE}, // 0x350 - 0x35f
+};
+#endif
+
+
+//-----------------------------------------------------------------------
+//
+// BOOLEAN CardCheckAdapter
+//
+// This routine checks for the presense of the card.
+// Initializes a workspace for the adapter at this address.
+// Returns TRUE if adapter found.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN CardCheckAdapter (PWORKSPACE w, PINIT init)
+{
+ PADAPTER_INFO g = (PADAPTER_INFO) w;
+ BOOLEAN rval;
+
+
+ //
+ // Initialize workspace and takes card specific parameter information
+ // Just the BaseIoAddress for the t13b.
+ //
+
+ g->BaseIoAddress = init->BaseIoAddress;
+
+ // perform normal PC9010 Check Adapter
+
+ rval = PC9010CheckAdapter(g);
+
+ // if no adapter was found, we could have disrupted a t13b
+ // is the following necessary?
+
+ if (!rval) {
+
+ // reset the 53c400 of the t13b, if we messed it up
+ // n53c400 reset reg same as PC9010 config reg
+ // WARNING - Could be destructive to other cards...
+
+ PC9010PortSet(g,PC9010_CONFIG,0x80);
+ PC9010PortSet(g,PC9010_CONFIG,0);
+
+ }
+
+ return rval;
+}
+
+
+//
+// CardParseCommandString(PINIT p, PCHAR str)
+//
+// Parses the command string to get all card specific parameters.
+// Will fill in defaults where no parameters are supplied, or
+// if the str pointer is NULL.
+//
+// Returns false if it could not parse the string given.
+//
+// Can be used to parse the string piece by piece, by sending
+// the same INIT structure each time. Send NULL as the string
+// first time to initialize the PINIT structure to the standard defaults.
+//
+BOOLEAN CardParseCommandString(PINIT init, PCHAR str)
+{
+ // for now, just fill in some defaults
+
+ init->BaseIoAddress = NULL;
+
+ return TRUE;
+}
+
+//
+// The following is used along with the constant structure in card.c
+// to define the precise i/o addresses a card will use
+//
+
+USHORT CardNumberOfAddressRanges (VOID)
+{
+ return 1;
+}
+
+
+// the maximum transfer size
+// by decreasing this we can get better system performace since
+// the data transfer occurs with interrupts disabled, this might be
+// decreased for our smaller cards
+// Used only by WINNT
+
+ULONG CardMaxTransferSize (VOID)
+{
+ return (32*1024L);
+}
+
+
+// the following info is for initialization only
+// this card is IO mapped
+
+BOOLEAN CardAddressRangeInIoSpace (VOID)
+{
+ return TRUE;
+}
+
+
+// we use 16 addresses in IO space
+
+USHORT CardAddressRangeLength (VOID)
+{
+ return 16;
+}
+
+
+// we use interrupts
+
+BOOLEAN CardSupportsInterrupts (VOID)
+{
+ return TRUE;
+}
+
+
+// default interrupt level
+
+UCHAR CardDefaultInterruptLevel (VOID)
+{
+ return 12;
+}
+
+
+USHORT CardStartCommandInterrupt (PTSRB t)
+{
+ return (ScsiStartCommandInterrupt (t));
+}
+
+
+USHORT CardFinishCommandInterrupt (PTSRB t)
+{
+ return (ScsiFinishCommandInterrupt (t));
+}
+
+
+USHORT CardDoCommand (PTSRB t)
+{
+ return (ScsiDoCommand (t));
+}
+
+
+BOOLEAN CardInterrupt (PADAPTER_INFO g)
+{
+ return (N5380Interrupt (g));
+}
+
+
+VOID CardEnableInterrupt (PADAPTER_INFO g)
+{
+ PC9010EnableInterrupt (g);
+}
+
+
+VOID CardDisableInterrupt (PADAPTER_INFO g)
+{
+ PC9010DisableInterrupt (g);
+}
+
+
+VOID CardResetBus (PADAPTER_INFO g)
+{
+ PC9010ResetBus (g);
+}
+
+
+VOID CardSetInterruptLevel (PADAPTER_INFO g, UCHAR level)
+{
+ return;
+}
+
+
+PUCHAR CardGetName (VOID)
+{
+ return "T160 16-Bit SCSI Host Adapter";
+}
+
+
+PUCHAR CardGetShortName (VOID)
+{
+ return "T160";
+}
+
+
+UCHAR CardGetType (VOID)
+{
+ return CARDTYPE_T160;
+}
+
+
+ #ifdef NOVELL
+//-----------------------------------------------------------------------
+// NOVELL Port and IRQ Tables
+//
+// Novell needs these defined in a specific format:
+// long integer array with the number of entries at head of list.
+//-----------------------------------------------------------------------
+
+// The following table specifies the port values Novell will prompt
+// the user with if no port is specified on the LOAD command line.
+
+CONST ULONG possible_port [] =
+ {8, 0x350, 0x340, 0x250, 0x240, 0x330, 0x360, 0x230, 0x260};
+
+// The following table specifies the IRQ values Novell will prompt
+// the user with if no IRQ is specified on the LOAD command line.
+
+CONST ULONG possible_irq [] = {7, 3, 5, 7, 10, 12, 14, 15};
+
+ #endif // #ifdef NOVELL
+
+
+
diff --git a/private/ntos/miniport/trantor/source/cardt338.c b/private/ntos/miniport/trantor/source/cardt338.c
new file mode 100644
index 000000000..d0b69a42f
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/cardt338.c
@@ -0,0 +1,246 @@
+//-----------------------------------------------------------------------
+//
+// CARDT338.C
+//
+// T338 Adapter Specific File
+//
+// See also cardtxxx.h, cardtxxx.h may redefine some functions with #defines.
+//
+// Revisions:
+// 02-01-93 KJB First.
+// 02-25-93 KJB Reorganized, supports dataunderrun with long delay
+// for under run on large xfers. Can we fix this?
+// 03-22-93 KJB Reorged for functional library interface.
+// 03-26-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-22-93 JAP Added AdapterInterrupts[] and CardGetIRQ().
+// 05-12-93 JAP Altered CardGetShortName() to return only
+// the type of card.
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+// 05-17-93 KJB Fixed compiler warnings.
+//
+//-----------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+
+#ifdef WINNT
+//
+// The address ranges the card will use. These are accessed by trantor.c
+// to inform NTOS of the resources we are using.
+//
+CONST CardAddressRange cardAddressRange[] =
+ {
+ {0x00,0x03,FALSE}, // 0x3bc - 0x3be
+ };
+#endif
+
+
+//------------------------------------------------------------------------
+// The following table specifies the possible interrupts that
+// can be used by the adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST USHORT AdapterInterrupts [] = {0}; // no interrupts
+
+
+//------------------------------------------------------------------------
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST ULONG AdapterAddresses[] = {0X3bc, 0X378, 0X278,0};
+
+
+//-----------------------------------------------------------------------
+//
+// The following routines are stub routines to provide an entry
+// point for the library. They reference the correct routines for
+// the appropriate card. Only these routines may be called from outside
+// the library. See the rouines they reference for a description of
+// the rouines, if the meaning is unclear.
+//
+//-----------------------------------------------------------------------
+
+// the maximum transfer size
+// by decreasing this we can get better system performace since
+// the data transfer occurs with interrupts disabled, this might be
+// decreased for our smaller cards
+// Used only by WINNT
+
+ULONG CardMaxTransferSize (VOID)
+{
+ return 8*1024L;
+}
+
+
+// the following info is for initialization only
+// the t348 is IO mapped
+
+BOOLEAN CardAddressRangeInIoSpace (VOID)
+{
+ return TRUE;
+}
+
+
+// we use 3 addresses in IO space
+
+USHORT CardAddressRangeLength (VOID)
+{
+ return 0x3;
+}
+
+
+// The following is used along with the constant structure in card.c
+// to define the precise i/o addresses a card will use
+
+USHORT CardNumberOfAddressRanges (VOID)
+{
+ return 1;
+}
+
+
+// the t348 does not use interrupts
+
+BOOLEAN CardSupportsInterrupts (VOID)
+{
+ return FALSE;
+}
+
+
+// for now, must choose an interupt that doesn't conflict
+// microsoft: jeff said later they will have a method
+
+UCHAR CardDefaultInterruptLevel (VOID)
+{
+ return 15;
+}
+
+//-----------------------------------------------------------------------
+//
+// Redefined routines
+//
+//-----------------------------------------------------------------------
+
+// These are card specific routines, but since this card has a 5380, we
+// will redefine these to the generic n5380 or other routines.
+
+
+//-----------------------------------------------------------------------
+//
+// BOOLEAN CardCheckAdapter
+//
+// This routine checks for the presense of the card.
+// Initializes a workspace for the adapter at this address.
+// Returns TRUE if adapter found.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN CardCheckAdapter (PWORKSPACE w, PINIT init)
+{
+ PADAPTER_INFO g = (PADAPTER_INFO) w;
+
+ //
+ // Initialize workspace and takes card specific parameter information
+ // Just the BaseIoAddress for the t13b.
+ //
+
+ g->BaseIoAddress = init->BaseIoAddress;
+
+ return (T338CheckAdapter (g));
+}
+
+//
+// CardParseCommandString(PINIT p, PCHAR str)
+//
+// Parses the command string to get all card specific parameters.
+// Will fill in defaults where no parameters are supplied, or
+// if the str pointer is NULL.
+//
+// Returns false if it could not parse the string given.
+//
+// Can be used to parse the string piece by piece, by sending
+// the same INIT structure each time. Send NULL as the string
+// first time to initialize the PINIT structure to the standard defaults.
+//
+// BaseIoAddress will be set to NULL by default, and the program can
+// detect that it has changed during parsing and just search for the
+// card as specified by the command line argument if it has changed. If
+// it does not change, the program should cycle through all valid addresses.
+//
+BOOLEAN CardParseCommandString(PINIT init, PCHAR str)
+{
+ // for now, just fill in some defaults
+
+ init->BaseIoAddress = NULL;
+
+ return TRUE;
+}
+
+
+BOOLEAN CardInterrupt (PADAPTER_INFO g)
+{
+ return (T338Interrupt (g));
+}
+
+
+VOID CardResetBus (PADAPTER_INFO g)
+{
+ T338ResetBus (g);
+}
+
+
+VOID CardDisableInterrupt (PADAPTER_INFO g)
+{
+ N5380DisableInterrupt (g);
+}
+
+
+VOID CardEnableInterrupt (PADAPTER_INFO g)
+{
+ N5380EnableInterrupt (g);
+}
+
+
+VOID CardSetInterruptLevel (PADAPTER_INFO g, UCHAR level)
+{
+ return;
+}
+
+
+USHORT CardDoCommand (PTSRB t)
+{
+ return (T338DoCommand (t));
+}
+
+
+USHORT CardStartCommandInterrupt (PTSRB t)
+{
+ return (T338StartCommandInterrupt (t));
+}
+
+
+USHORT CardFinishCommandInterrupt (PTSRB t)
+{
+ return (T338FinishCommandInterrupt (t));
+}
+
+
+PUCHAR CardGetName (VOID)
+{
+ return "T338 SCSI Host Adapter";
+}
+
+
+PUCHAR CardGetShortName (VOID)
+{
+ return "T338";
+}
+
+
+UCHAR CardGetType (VOID)
+{
+ return CARDTYPE_T338;
+}
+
+
diff --git a/private/ntos/miniport/trantor/source/cardt348.c b/private/ntos/miniport/trantor/source/cardt348.c
new file mode 100644
index 000000000..4d2976514
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/cardt348.c
@@ -0,0 +1,220 @@
+//------------------------------------------------------------------------
+//
+// CARDT348.C
+//
+// T348 Adapter Specific File
+//
+// See also cardtxxx.h, cardtxxx.h may redefine some functions with #defines.
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 02-25-93 KJB Reorganized, supports dataunderrun with long delay
+// for under run on large xfers. Can we fix this?
+// 03-22-93 KJB Reorged for functional library interface.
+// 03-26-93 JAP Fixed up prototype typedef inconsistencies
+// 04-05-93 KJB Fixed definition problem for WINNT.
+// Involving CardAddressRange...
+// 04-22-93 JAP Added AdapterInterrupts[] and CardGetIRQ().
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+// 05-17-93 KJB Fixed warning message.
+//
+//------------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+#ifdef WINNT
+//
+// The address ranges the card will use. These are accessed by trantor.c
+// to inform NTOS of the resources we are using.
+//
+CONST CardAddressRange cardAddressRange[] =
+ {
+ {0x00,0x03,FALSE}, // 0x3bc - 0x3be
+ };
+#endif
+
+
+//------------------------------------------------------------------------
+// The following table specifies the possible interrupts that
+// can be used by the adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST USHORT AdapterInterrupts [] = {0}; // no interrupts
+
+
+//------------------------------------------------------------------------
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST ULONG AdapterAddresses [] = {0X3bc, 0X378, 0X278, 0};
+
+
+//-----------------------------------------------------------------------
+//
+// The following routines are stub routines to provide an entry
+// point for the library. They reference the correct routines for
+// the appropriate card. Only these routines may be called from outside
+// the library. See the rouines they reference for a description of
+// the rouines, if the meaning is unclear.
+//
+//-----------------------------------------------------------------------
+
+//------------------------------------------------------------------------
+// the maximum transfer size
+// by decreasing this we can get better system performace since
+// the data transfer occurs with interrupts disabled, this might be
+// decreased for our smaller cards
+// Used only by WINNT
+//------------------------------------------------------------------------
+
+ULONG CardMaxTransferSize(VOID)
+{
+ return 2*1024L;
+}
+
+
+// the following info is for initialization only
+// the t348 is IO mapped
+
+BOOLEAN CardAddressRangeInIoSpace(VOID)
+{
+ return TRUE;
+}
+
+
+// we use 3 addresses in IO space
+
+USHORT CardAddressRangeLength(VOID)
+{
+ return 3;
+}
+
+
+// The following is used along with the constant structure in card.c
+// to define the precise i/o addresses a card will use
+
+USHORT CardNumberOfAddressRanges(VOID)
+{
+ return 1;
+}
+
+
+// the t348 does not use interrupts
+
+BOOLEAN CardSupportsInterrupts(VOID)
+{
+ return FALSE;
+}
+
+// for now, must choose an interupt that doesn't conflict
+// microsoft: jeff said later they will have a method
+
+UCHAR CardDefaultInterruptLevel(VOID)
+{
+ return 15;
+}
+
+USHORT CardDoCommand(PTSRB t)
+{
+ return P3CDoCommand(t);
+}
+USHORT CardFinishCommandInterrupt(PTSRB t)
+{
+ return P3CFinishCommandInterrupt(t);
+}
+USHORT CardStartCommandInterrupt(PTSRB t)
+{
+ return P3CStartCommandInterrupt(t);
+}
+
+//
+// BOOLEAN CardCheckAdapter
+//
+// Initializes a workspace for the adapter at this address.
+// Returns TRUE if adapter found.
+//
+BOOLEAN CardCheckAdapter (PWORKSPACE w, PINIT init)
+{
+ PADAPTER_INFO g = (PADAPTER_INFO) w;
+
+ //
+ // Initialize workspace and takes card specific parameter information
+ // to set how the card will be used. For example, command line information
+ // to force the parallel port to bi-directional or uni-directional modes.
+ //
+
+ // if no init structure, use all defaults
+ if (init) {
+ g->ParallelPortType = init->ParallelPortType;
+ } else {
+ g->ParallelPortType = PT_UNKNOWN;
+ }
+
+ g->BaseIoAddress = init->BaseIoAddress;
+
+ return P3CCheckAdapter(g);
+}
+
+//
+// CardParseCommandString(PINIT p, PCHAR str)
+//
+// Parses the command string to get all card specific parameters.
+// Will fill in defaults where no parameters are supplied, or
+// if the str pointer is NULL.
+//
+// Returns false if it could not parse the string given.
+//
+// Can be used to parse the string piece by piece, by sending
+// the same INIT structure each time. Send NULL as the string
+// first time to initialize the PINIT structure to the standard defaults.
+//
+// BaseIoAddress will be set to NULL by default, and the program can
+// detect that it has changed during parsing and just search for the
+// card as specified by the command line argument if it has changed. If
+// it does not change, the program should cycle through all valid addresses.
+//
+BOOLEAN CardParseCommandString(PINIT init, PCHAR str)
+{
+ // for now, just fill in some defaults
+
+ init->ParallelPortType = PT_UNKNOWN;
+ init->BaseIoAddress = NULL;
+
+ return TRUE;
+}
+
+BOOLEAN CardInterrupt(PADAPTER_INFO g)
+{
+ return P3CInterrupt(g);
+}
+VOID CardDisableInterrupt(PADAPTER_INFO g)
+{
+ N5380DisableInterrupt(g);
+}
+VOID CardEnableInterrupt(PADAPTER_INFO g)
+{
+ N5380EnableInterrupt(g);
+}
+VOID CardResetBus(PADAPTER_INFO g)
+{
+ P3CResetBus(g);
+}
+VOID CardSetInterruptLevel(PADAPTER_INFO g,UCHAR level)
+{
+ return;
+}
+PUCHAR CardGetName(VOID)
+{
+ return "T348 SCSI Host Adapter";
+}
+PUCHAR CardGetShortName(VOID)
+{
+ return "T348.1.0";
+}
+UCHAR CardGetType(VOID)
+{
+ return CARDTYPE_T348;
+}
+
diff --git a/private/ntos/miniport/trantor/source/cardtmv1.c b/private/ntos/miniport/trantor/source/cardtmv1.c
new file mode 100644
index 000000000..152213c2c
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/cardtmv1.c
@@ -0,0 +1,266 @@
+//-------------------------------------------------------------------------
+//
+// CARDTMV1.C
+//
+// TMV1 Adapter Specific File
+//
+// See also cardtxxx.h, cardtxxx.h may redefine some functions with #defines.
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 03-26-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-05-93 KJB Fixed definition problem for WINNT.
+// Involving CardAddressRange...
+// 04-22-93 JAP Added AdapterInterrupts[] and CardGetIRQ().
+// 05-05-93 KJB Fixed CardSetInterruptLevel so that it calls
+// MV101SetInterruptLevel like it should.
+// 05-12-93 JAP Altered CardGetShortName() to return only
+// the type of card.
+// 05-13-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters. Auto Request Sense is
+// now supported.
+// 05-13-93 KJB Merged Microsoft Bug fixes to card detection.
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+// 05-17-93 KJB CardAddressRangeLength now return 0xffff.
+// Fixed compiler warnings.
+//
+//-------------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+#ifdef WINNT
+//------------------------------------------------------------------------
+// The address ranges the card will use. These are accessed by trantor.c
+// to inform NTOS of the resources we are using.
+//------------------------------------------------------------------------
+CONST CardAddressRange cardAddressRange[] =
+ {
+ {0x1c00,0x04,FALSE}, // 0x1f88
+ {0x3c00,0x04,FALSE}, // 0x3f88
+ {0x4000,0x02,FALSE}, // 0x4388
+ {0x5c00,0x04,FALSE}, // 0x5f88
+ {0x8003,0x01,FALSE}, // 0x838b
+ {0xbc00,0x01,FALSE} // 0xbf88
+ };
+#endif
+
+
+//------------------------------------------------------------------------
+// The following table specifies the possible interrupts that
+// can be used by the adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST USHORT AdapterInterrupts [] =
+ {2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 0};
+
+
+//------------------------------------------------------------------------
+// The following table specifies the ports to be checked when searching for
+// an adapter. A zero entry terminates the search.
+//------------------------------------------------------------------------
+
+CONST ULONG AdapterAddresses[] =
+ {0x388, 0x384, 0x38C, 0x288, 0x280, 0x284, 0x28C, 0x0};
+
+
+//-----------------------------------------------------------------------
+//
+// The following routines are stub routines to provide an entry
+// point for the library. They reference the correct routines for
+// the appropriate card. Only these routines may be called from outside
+// the library. See the rouines they reference for a description of
+// the rouines, if the meaning is unclear.
+//
+//-----------------------------------------------------------------------
+
+//------------------------------------------------------------------------
+// the maximum transfer size
+// by decreasinge this we can get better system performace since
+// the data transfer occurs with interrupts disabled, this might be
+// decreased for our smaller cards
+// Used only by WINNT
+//------------------------------------------------------------------------
+
+ULONG CardMaxTransferSize (VOID)
+{
+ return 16*1024L;
+}
+
+
+// we use interrupts
+
+BOOLEAN CardSupportsInterrupts (VOID)
+{
+ return TRUE;
+}
+
+
+// default interrupt number is 10
+
+UCHAR CardDefaultInterruptLevel (VOID)
+{
+ return 15;
+}
+
+
+// the following info is for initialization only
+// this card is memory mapped
+
+BOOLEAN CardAddressRangeInIoSpace (VOID)
+{
+ return TRUE;
+}
+
+
+// we use 0x10000 bytes in memory space
+
+USHORT CardAddressRangeLength (VOID)
+{
+// return 0x10000;
+ return 0xffff;
+}
+
+
+// The following is used along with the constant structure in card.c
+// to define the precise i/o addresses a card will use
+
+USHORT CardNumberOfAddressRanges (VOID)
+{
+ return 0;
+}
+
+
+USHORT CardStartCommandInterrupt (PTSRB t)
+{
+ return (ScsiStartCommandInterrupt (t));
+}
+
+
+USHORT CardFinishCommandInterrupt (PTSRB t)
+{
+ return (ScsiFinishCommandInterrupt (t));
+}
+
+USHORT CardDoCommand (PTSRB t)
+{
+ return (ScsiDoCommand (t));
+}
+
+//
+// BOOLEAN CardCheckAdapter
+//
+// Initializes a workspace for the adapter at this address.
+// Returns TRUE if adapter found.
+//
+BOOLEAN CardCheckAdapter (PWORKSPACE w, PINIT init)
+{
+ PADAPTER_INFO g = (PADAPTER_INFO) w;
+ BOOLEAN rval;
+
+ //
+ // Initialize workspace and takes card specific parameter information
+ // to set how the card will be used. For example, command line info
+ // to force the parallel port to bi-directional or uni-directional modes.
+ //
+
+ g->BaseIoAddress = init->BaseIoAddress;
+
+ // if no init structure, use all defaults
+
+ if (init) {
+ g->InterruptLevel = init->InterruptLevel;
+ } else {
+ g->InterruptLevel = CardDefaultInterruptLevel();
+ }
+
+ rval = MV101CheckAdapter (g);
+
+ // if card found, set interrupt level
+
+ if (rval) {
+
+ MV101SetInterruptLevel (g, g->InterruptLevel);
+ }
+
+ return rval;
+}
+
+//
+// CardParseCommandString(PINIT p, PCHAR str)
+//
+// Parses the command string to get all card specific parameters.
+// Will fill in defaults where no parameters are supplied, or
+// if the str pointer is NULL.
+//
+// Returns false if it could not parse the string given.
+//
+// Can be used to parse the string piece by piece, by sending
+// the same INIT structure each time. Send NULL as the string
+// first time to initialize the PINIT structure to the standard defaults.
+//
+// BaseIoAddress will be set to NULL by default, and the program can
+// detect that it has changed during parsing and just search for the
+// card as specified by the command line argument if it has changed. If
+// it does not change, the program should cycle through all valid addresses.
+//
+BOOLEAN CardParseCommandString(PINIT init, PCHAR str)
+{
+ // for now, just fill in some defaults
+
+ init->InterruptLevel = CardDefaultInterruptLevel();
+ init->BaseIoAddress = NULL;
+
+ return TRUE;
+}
+
+
+VOID CardEnableInterrupt (PADAPTER_INFO g)
+{
+ MV101EnableInterrupt (g);
+}
+
+
+VOID CardDisableInterrupt (PADAPTER_INFO g)
+{
+ MV101DisableInterrupt (g);
+}
+
+
+BOOLEAN CardInterrupt (PADAPTER_INFO g)
+{
+ return (N5380Interrupt (g));
+}
+
+
+VOID CardResetBus (PADAPTER_INFO g)
+{
+ N5380ResetBus (g);
+}
+
+
+PUCHAR CardGetName (VOID)
+{
+ return "Media Vision Pro Audio Spectrum";
+}
+
+
+PUCHAR CardGetShortName (VOID)
+{
+ return "Pro Audio";
+}
+
+
+UCHAR CardGetType (VOID)
+{
+ return CARDTYPE_TMV1;
+}
+
+
diff --git a/private/ntos/miniport/trantor/source/cardutil.c b/private/ntos/miniport/trantor/source/cardutil.c
new file mode 100644
index 000000000..ef0a4b151
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/cardutil.c
@@ -0,0 +1,110 @@
+//-----------------------------------------------------------------------
+//
+// CARDUTIL.C
+//
+// Utility File for all common card routines.
+//
+// History:
+//
+// 02-20-93 KJB/SG First, Placed SG's CardGetNumber function here.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+// 05-12-93 JAP Added version control information.
+// This file should be updated changing the version numbers
+// on EACH significant change to ANY low-level driver.
+// The cause of upping a version should be placed in this
+// files history. (currently Version 1.0)
+// 05-12-93 KJB Moved code from cardtxxx.c to here.
+// 05-12-93 KJB Fixed bugs in CardGetVersion.
+// 05-15-93 KJB Fixed warnings in CardGetNumber.
+//
+//-------------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+#define CDRIVER_MAJOR_VERSION 1
+#define CDRIVER_MINOR_VERSION 0
+
+//
+// Static constant arrays defined in cardtxxx.c
+//
+extern PBASE_REGISTER AdapterAddresses[];
+extern USHORT AdapterInterrupts[];
+
+//-----------------------------------------------------------------------
+// CardGetVersion()
+//
+// Return the CDRIVER version number values.
+//
+// Input: Pointer to ULONG to be filled with major version number
+// Pointer to ULONG to be filled with minor version number
+//
+// Output: None. Major and minor version variables are filled.
+//-----------------------------------------------------------------------
+
+VOID CardGetVersion (PULONG pMajorVersion, PULONG pMinorVersion)
+{
+ *pMajorVersion = CDRIVER_MAJOR_VERSION;
+ *pMinorVersion = CDRIVER_MINOR_VERSION;
+}
+
+
+//-----------------------------------------------------------------------
+// CardGetNumber ()
+//
+// Returns the index number of the given adapter address from the
+// AdapterAddresses table.
+// Return -1, if the address is not found in the table.
+//-----------------------------------------------------------------------
+
+USHORT CardGetNumber (PBASE_REGISTER basePort)
+{
+ USHORT i;
+
+ for (i = 0; AdapterAddresses [i] != 0; i++) {
+ if (AdapterAddresses [i] == basePort)
+ return i;
+ }
+
+ return 0xffff;
+}
+
+//-----------------------------------------------------------------------
+//
+// CardGetWorkspaceSize
+//
+//-----------------------------------------------------------------------
+USHORT CardGetWorkspaceSize(void )
+{
+ return sizeof (ADAPTER_INFO);
+}
+
+//------------------------------------------------------------------------
+// CardGetIRQ
+//
+// Returns the nth possible adapter interrupt.
+// Returns 0 when the last possible interrupt has been exceeded.
+//------------------------------------------------------------------------
+
+USHORT CardGetIRQ (USHORT i)
+{
+ return AdapterInterrupts [i];
+}
+
+
+//------------------------------------------------------------------------
+// CardAddress
+//
+// Returns the nth adapter address.
+// Returns 0 when the last address has been exceeded.
+//------------------------------------------------------------------------
+
+PBASE_REGISTER CardAddress (USHORT i)
+{
+ return ((PBASE_REGISTER)AdapterAddresses [i]);
+}
+
+//-----------------------------------------------------------------------
+// End Of File.
+//-----------------------------------------------------------------------
+
+
diff --git a/private/ntos/miniport/trantor/source/ep3c.c b/private/ntos/miniport/trantor/source/ep3c.c
new file mode 100644
index 000000000..d0a960136
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/ep3c.c
@@ -0,0 +1,1418 @@
+//-----------------------------------------------------------------------
+//
+// EP3C.C
+//
+// Trantor EP3C access file.
+//
+// Revisions:
+// 03-31-93 KJB First.
+// 04-09-93 KJB Changed "in edx,al" and "out edx,al" references to
+// use only the dx register: in al,dx.
+// Changed loop instructions to dec ecx, jnz.
+// 04-21-93 KJB Fixed initialization error for os/2: static
+// variables must be initialized.
+// 05-05-93 KJB Disable Checking for EPP port for debug purposes.
+// TEMPORARY.
+// 05-05-93 KJB Added ReadFifoUni/BiDirSlow routines to do P_BUSY
+// checking to allow bytes to get ready.
+// 05-11-93 KJB Added WriteFifoUniDirSlow routine to do P_BUSY
+// checking to allow bytes to get ready.
+// 05-17-93 JAP Made in-line assemble routines conditionally coded.
+// Only #ifdef WINNT will these routines be read in.
+// Otherwise, look in ep3c2.asm.
+// 05-17-93 KJB Fixed some compiler warnings.
+//
+//-----------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+// Local Functions
+
+VOID EP3CSetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control);
+VOID EP3CSetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control);
+
+USHORT EP3CReadBytesFastBiDir(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT EP3CReadBytesFastUniDir(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+VOID EP3CSetRegisterUniDir(PADAPTER_INFO g, UCHAR reg);
+VOID EP3CSetRegisterEPP(PADAPTER_INFO g, UCHAR reg);
+BOOLEAN EP3CCheckAdapterType(PADAPTER_INFO g);
+VOID EP3CSetParallelPortType(PADAPTER_INFO g);
+
+VOID EP3CReadFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
+VOID EP3CReadFifoBiDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
+VOID EP3CReadFifoEPP(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
+VOID EP3CWriteFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
+VOID EP3CWriteFifoEPP(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
+
+// for writes, uni-directional is the same as bi-directional
+
+#define EP3CSetRegisterBiDir EP3CSetRegisterUniDir
+#define EP3CWriteFifoBiDir EP3CWriteFifoUniDir
+#define EP3CWriteDataRegisterBiDir EP3CWriteDataRegisterUniDir
+#define EP3CWriteControlRegisterBiDir EP3CWriteControlRegisterUniDir
+
+/// for control registers, epp is the same as bi-dir
+
+#define EP3CWriteControlRegisterEPP EP3CWriteControlRegisterBiDir
+#define EP3CReadControlRegisterEPP EP3CReadControlRegisterBiDir
+
+// local redefinitions
+
+#define EP3CPortPut(g, reg, value) \
+ (*(g->EP3CWriteControlRegister))(g,reg,value)
+
+#define EP3CPortGet(g, reg, value) \
+ (*(g->EP3CReadControlRegister))(g, value)
+
+//
+// VOID EP3CPortSet
+//
+// Or's bits into an EP3C register.
+//
+VOID EP3CPortSet(PADAPTER_INFO g, UCHAR reg, UCHAR value)
+{
+ UCHAR tmp;
+
+ EP3CPortGet(g,reg,&tmp);
+ tmp |= value;
+ EP3CPortPut(g,reg,tmp);
+}
+
+//
+// VOID EP3CPortClear
+//
+// Clears all bits in the EP3C register with value.
+//
+VOID EP3CPortClear(PADAPTER_INFO g, UCHAR reg, UCHAR value)
+{
+ UCHAR tmp;
+
+ EP3CPortGet(g,reg,&tmp);
+ tmp &= (value ^ 0xff);
+ EP3CPortPut(g,reg,tmp);
+}
+
+//
+// VOID EP3CPortTest
+//
+// Tests bits in value with the EP3C register.
+//
+BOOLEAN EP3CPortTest(PADAPTER_INFO g, UCHAR reg, UCHAR value)
+{
+ UCHAR tmp;
+
+ EP3CPortGet(g,reg,&tmp);
+ return (tmp & value);
+}
+
+//
+// VOID EP3CSetRegisterUniDir(PADAPTER_INFO g, UCHAR reg)
+//
+// Sets the register that will be accessed.
+//
+VOID EP3CSetRegisterUniDir(PADAPTER_INFO g, UCHAR reg)
+{
+ UCHAR tmp;
+
+ // write to adr reg 1
+
+ tmp = (reg & EP3C_ADRS);
+ EP3CPortPut(g,EP3C_AREG1,tmp);
+}
+
+//
+// VOID EP3CSetRegisterEPP(PADAPTER_INFO g, UCHAR reg)
+//
+// Sets the register that will be accessed.
+//
+VOID EP3CSetRegisterEPP(PADAPTER_INFO g, UCHAR reg)
+{
+ ParallelPortPut(g->BaseIoAddress,EPP_AUTO_ADDRESS,reg);
+}
+
+//
+// VOID EP3CWriteControlRegisterUniDir
+//
+// Writes to an adr register of the ep3c using a uni-directional port.
+//
+VOID EP3CWriteControlRegisterUniDir(PADAPTER_INFO g, UCHAR areg,
+ UCHAR value)
+{
+ UCHAR tmp;
+
+ // output the value and register to the parallel data reg
+ tmp = value | areg;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,tmp);
+
+ // write to ep3c
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp & (0xff ^ P_BUFEN);
+ tmp = tmp | P_STB;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+ tmp = tmp | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // negate P_STB & P_SLC, to end write
+
+ tmp = tmp & (0xff ^ (P_STB | P_SLC));
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // note: we leave P_BUFEN asserted.
+}
+
+//
+// VOID EP3CReadControlRegisterBiDir
+//
+// Reads from an adr register of the ep3c using a bi-directional port.
+// NOTE: always read areg1 since areg2 is write-only.
+//
+VOID EP3CReadControlRegisterBiDir(PADAPTER_INFO g, PUCHAR value)
+{
+ UCHAR tmp;
+
+ // negate P_BUFEN and assert P_SLC
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp | P_BUFEN | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // read data register
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,value);
+
+ // negate P_BUFEN and negate P_SLC
+
+ tmp = (tmp & ((P_SLC | P_BUFEN) ^ 0xff));
+// tmp = (tmp & (P_SLC ^ 0xff)) | P_BUFEN;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// VOID EP3CReadControlRegisterUniDir
+//
+// Reads from an adr register of the ep3c using a uni-directional port.
+// NOTE: always read areg1 since areg2 is write-only.
+//
+VOID EP3CReadControlRegisterUniDir(PADAPTER_INFO g, PUCHAR value)
+{
+ UCHAR tmp;
+ UCHAR tmp1;
+
+ // select high nibble
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x80);
+
+ // assert P_BUFEN and assert P_SLC
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp & (P_BUFEN ^ 0xff) | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // read high nibble
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp);
+
+ // compute high nibble
+ tmp = (tmp << 1) & 0xf0;
+
+ // select low nibble
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x00);
+
+ // read low nibble
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp1);
+
+ // compute low nibble
+
+ tmp1 = (tmp1 >> 3) & 0x0f;
+
+ // compute and return byte
+
+ *value = tmp1 | tmp;
+
+ // leave P_BUFEN asserted, negate P_SLC
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp & ((P_BUFEN | P_SLC) ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// VOID EP3CReadDataRegisterUniDir
+//
+// Reads a byte from a register thru the ep3c, using uni-dir mode.
+//
+VOID EP3CReadDataRegisterUniDir(PADAPTER_INFO g,
+ UCHAR reg, PUCHAR byte)
+{
+ UCHAR tmp;
+ UCHAR tmp1;
+
+ // set the register we want to access
+
+ (*(g->EP3CSetRegister))(g, reg);
+
+ // select high nibble
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x80);
+
+ // assert P_BUFEN and assert P_AFX
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp & (P_BUFEN ^ 0xff) | P_AFX;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // read high nibble
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp);
+
+ // compute high nibble
+ tmp = (tmp << 1) & 0xf0;
+
+ // select low nibble
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x00);
+
+ // read low nibble
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp1);
+
+ // compute low nibble
+
+ tmp1 = (tmp1 >> 3) & 0x0f;
+
+ // compute and return byte
+
+ *byte = tmp1 | tmp;
+
+ // leave P_BUFEN asserted, negate P_AFX
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp & ((P_BUFEN | P_AFX) ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+}
+
+//
+// VOID EP3CReadDataRegisterBiDir
+//
+// Reads a byte from a register thru the EP3C, using bi-dir mode.
+//
+VOID EP3CReadDataRegisterBiDir(PADAPTER_INFO g,
+ UCHAR reg, PUCHAR byte)
+{
+ UCHAR tmp;
+
+ // set the register we want to access
+
+ (*(g->EP3CSetRegister))(g, reg);
+
+ // negate P_BUFEN, assert P_AFX
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp | P_BUFEN | P_AFX;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // read the data byte
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,byte);
+
+ // negate P_BUFEN, and P_AFX
+
+ tmp = tmp & ((P_BUFEN | P_AFX) ^ 0xff);
+// tmp = tmp | P_BUFEN & (P_AFX ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// VOID EP3CReadDataRegisterEPP
+//
+// Reads a byte from a register thru the EP3C, using epp mode.
+//
+VOID EP3CReadDataRegisterEPP(PADAPTER_INFO g,
+ UCHAR reg, PUCHAR byte)
+{
+ // set the register we want to access
+
+ (*(g->EP3CSetRegister))(g, reg);
+
+ // read the data byte
+
+ ParallelPortGet(g->BaseIoAddress,EPP_AUTO_DATA,byte);
+
+}
+
+//
+// VOID EP3CWriteDataRegisterUniDir
+//
+// Writes the a register thru the EP3C.
+//
+VOID EP3CWriteDataRegisterUniDir(PADAPTER_INFO g,
+ UCHAR reg, UCHAR byte)
+{
+ UCHAR tmp;
+
+ // set the register we want to access
+
+ (*(g->EP3CSetRegister))(g, reg);
+
+ // output the byte on the data lines
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,byte);
+
+ // assert P_BUFEN and P_STB
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp & (0xff ^ P_BUFEN) | P_STB;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // assert P_AFX
+
+ tmp = tmp | P_AFX;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // negate P_STB & P_AFX, to end write
+
+ tmp = tmp & (0xff ^ (P_STB | P_AFX));
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // negate P_BUFEN
+
+// tmp = tmp | P_BUFEN;
+// ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// VOID EP3CWriteDataRegisterEPP
+//
+// Writes the a register thru the EP3C.
+//
+VOID EP3CWriteDataRegisterEPP(PADAPTER_INFO g,
+ UCHAR reg, UCHAR byte)
+{
+ // set the register we want to access
+
+ (*(g->EP3CSetRegister))(g, reg);
+
+ // output the byte on the data lines
+
+ ParallelPortPut(g->BaseIoAddress,EPP_AUTO_DATA,byte);
+
+}
+
+//
+// VOID EP3CReadFifoEPP
+//
+// Reads bytes for epp parallel port from the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+VOID EP3CReadFifoEPP(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ ScsiPortReadPortBufferUshort (
+ (PUSHORT)&(((PUCHAR)baseIoAddress)[EPP_AUTO_DATA]),
+ (PUSHORT)pbytes, 64);
+}
+
+
+//
+// VOID EP3CWriteFifoEPP
+//
+// Writes bytes thru epp parallel port to the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+
+VOID EP3CWriteFifoEPP(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ ScsiPortWritePortBufferUshort (
+ (PUSHORT)&(((PUCHAR)baseIoAddress)[EPP_AUTO_DATA]),
+ (PUSHORT)pbytes, 64);
+}
+
+//
+// VOID EP3CDisableInterrupt
+//
+// Disables the interrupt.
+//
+
+VOID EP3CDisableInterrupt(PADAPTER_INFO g)
+{
+ // set global flag for EP3CSetPrinterMode
+ g->EnableInterrupt = FALSE;
+
+ // see if the EP3C_IRQEN is asserted, if so clear it
+ if (EP3CPortTest(g,EP3C_AREG1,EP3C_IRQEN)) {
+
+ // clear the interrupts
+ // NOTE: a positive going edge toggles the state of EP3C_IRQEN
+
+ EP3CPortSet(g, EP3C_AREG1, EP3C_IRQEN);
+ EP3CPortClear(g, EP3C_AREG1, EP3C_IRQEN);
+ }
+
+ // finally, we can disable the core interrupts
+ N53C400DisableInterrupt(g);
+}
+
+//
+// VOID EP3CEnableInterrupt
+//
+// Enables the interrupt.
+//
+
+VOID EP3CEnableInterrupt(PADAPTER_INFO g)
+{
+ UCHAR tmp;
+
+ // set global flag for EP3CSetPrinterMode
+
+ g->EnableInterrupt = TRUE;
+
+ // see if the EP3C_IRQEN is not asserted, if so assert it
+
+ EP3CPortGet(g, EP3C_AREG1, &tmp);
+ if (!(tmp & EP3C_IRQEN)) {
+
+ // set the interrupts
+ // NOTE: a positive going edge toggles the state of EP3C_IRQEN
+
+ EP3CPortPut(g, EP3C_AREG1, EP3C_IRQEN);
+ EP3CPortPut(g, EP3C_AREG1, 0);
+ }
+
+ // finally, we can disable the core interrupts
+ N53C400EnableInterrupt(g);
+}
+
+//
+// EP3CSetPrinterMode
+//
+// This routine sets the EP3C to printer pass through mode. This is the
+// default mode and should be set after the brief use of scsi mode.
+//
+VOID EP3CSetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control)
+{
+ UCHAR tmp;
+
+ // restore data register
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,data);
+
+ // restore control register
+ // leave p_init negated, P_BUFEN asserted
+ // also set P_IRQEN based on g->EnableInterrupt
+
+ tmp = control | P_INIT & (P_BUFEN ^ 0xff);
+ if (g->EnableInterrupt) {
+ tmp = tmp | P_IRQEN;
+ } else {
+ tmp = tmp & (P_IRQEN ^ 0xff);
+ }
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// EP3CSetScsiMode
+//
+// This routine sets the EP3C into scsi mode. Now the parallel port can
+// be used to send commands the the n5380. This mode should be set only
+// briefly during when the scsi command is being executed.
+//
+VOID EP3CSetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control)
+{
+ UCHAR tmp;
+ USHORT i;
+
+ // save parallel data
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,data);
+
+ // zero data register
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0);
+
+ // save parallel control
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,control);
+ *control = *control & (P_BUFEN ^ 0xff);
+
+ // store current interrupt state
+
+ g->EnableInterrupt = (*control & P_IRQEN);
+
+ // put our data pattern on the data bus
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0xf7);
+
+ // negate P_SLC, P_BUFEN already asserted
+ tmp = *control;
+ tmp = tmp & (P_SLC ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // assert init
+ tmp = tmp & (P_INIT ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // assert P_SLC
+ tmp = tmp | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // negate P_SLC
+ tmp = tmp & (P_SLC ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // set to the appropriate mode: UNI, BI, etc..
+
+ if (g->ParallelPortType == PT_UNI) {
+ EP3CPortPut(g,(UCHAR)EP3C_AREG2,
+ (UCHAR)(EP3C_UNIDIR | g->Delay) );
+ } else {
+ EP3CPortPut(g,EP3C_AREG2,(UCHAR)(0 | g->Delay));
+ }
+
+ // read in the signature bytes
+
+ for (i=0;i<2;i++) {
+ EP3CPortGet(g, EP3C_AREG1, &g->SignatureBytes[i]);
+ }
+
+}
+
+//
+// EP3CCheckAdapter
+//
+// This routine is used to sense the presense of the EP3C adapter out
+// on the Parallel port. It will only detect the adapter if a device
+// is providing termination power.
+//
+BOOLEAN EP3CCheckAdapter(PADAPTER_INFO g)
+{
+ BOOLEAN rval = FALSE;
+ static CONST UCHAR ParallelPortType = PT_UNI;
+ static CONST UCHAR types[] = { PT_EPP, PT_BI, PT_UNI };
+ USHORT i;
+
+ // default the delay to 2 for now
+ g->Delay = 7;
+
+ if (g->ParallelPortType == PT_UNKNOWN) {
+
+ // try to locate as all types
+
+ for (i=0;i<3;i++) {
+
+ g->ParallelPortType = types[i];
+
+ // do we have a type[i] port?
+
+ if (rval = EP3CCheckAdapterType(g)) {
+
+ break;
+
+ }
+ }
+ } else {
+
+ // try only the parallel port type specified
+
+ rval = EP3CCheckAdapterType(g);
+ }
+
+ return rval;
+}
+
+//
+// VOID EP3CSetParallelType
+//
+// Sets this code to use the type of paralle port given by
+// g->ParallePortType, either PT_UNI, PT_BI, or PT_EPP.
+//
+VOID EP3CSetParallelPortType(PADAPTER_INFO g)
+{
+
+ switch (g->ParallelPortType) {
+ case PT_UNI:
+
+ // set the port type dependent routines
+
+ g->EP3CWriteControlRegister = EP3CWriteControlRegisterUniDir;
+ g->EP3CReadControlRegister = EP3CReadControlRegisterUniDir;
+ g->EP3CReadDataRegister = EP3CReadDataRegisterUniDir;
+ g->EP3CWriteDataRegister = EP3CWriteDataRegisterUniDir;
+ g->EP3CReadFifo = EP3CReadFifoUniDir;
+// g->EP3CReadFifo = EP3CReadFifoUniDirSlow;
+ g->EP3CWriteFifo = EP3CWriteFifoUniDir;
+ g->EP3CSetRegister = EP3CSetRegisterUniDir;
+
+ break;
+ case PT_BI:
+
+ // set the port type dependent routines
+
+ g->EP3CWriteControlRegister = EP3CWriteControlRegisterBiDir;
+ g->EP3CReadControlRegister = EP3CReadControlRegisterBiDir;
+ g->EP3CReadDataRegister = EP3CReadDataRegisterBiDir;
+ g->EP3CWriteDataRegister = EP3CWriteDataRegisterBiDir;
+ g->EP3CReadFifo = EP3CReadFifoBiDir;
+// g->EP3CReadFifo = EP3CReadFifoBiDirSlow;
+ g->EP3CWriteFifo = EP3CWriteFifoBiDir;
+ g->EP3CSetRegister = EP3CSetRegisterBiDir;
+
+ break;
+
+ case PT_EPP:
+ // set the port type dependent routines
+
+ g->EP3CWriteControlRegister = EP3CWriteControlRegisterEPP;
+ g->EP3CReadControlRegister = EP3CReadControlRegisterEPP;
+ g->EP3CReadDataRegister = EP3CReadDataRegisterEPP;
+ g->EP3CWriteDataRegister = EP3CWriteDataRegisterEPP;
+ g->EP3CReadFifo = EP3CReadFifoEPP;
+ g->EP3CWriteFifo = EP3CWriteFifoEPP;
+ g->EP3CSetRegister = EP3CSetRegisterEPP;
+
+ break;
+ }
+}
+
+//
+// BOOLEAN EP3CCheckAdapterType
+//
+// Checks for an adapter on a parallel port of the given type.
+//
+BOOLEAN EP3CCheckAdapterType(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+
+ // if epp type, then try to initialize 386sl code
+ if (g->ParallelPortType == PT_EPP) {
+ if (!SL386EnableEPP()) {
+ return FALSE;
+ }
+ }
+
+ // configure for the correct type of parallel port
+
+ EP3CSetParallelPortType(g);
+
+ // set scsi mode, reads signature bytes.
+
+ EP3CSetScsiMode(g,&data,&control);
+
+ // set parallel port for use by printer
+
+ EP3CSetPrinterMode(g,data,control);
+
+ // compare the signature bytes
+
+ if ((g->SignatureBytes[0] == 0xe8) && (g->SignatureBytes[1] == 0xff) ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//
+// EP3CDoCommand
+//
+// Called by the main loop to start a scsi command. This functions is the
+// main entry point for all cards. It returns an SRB status code as defined
+// in ..\..\inc\srb.h. A status code of RET_STATUS_PENDING means that the
+// request has been sent to the controller and an interrupt is needed to
+// finish the request. When this interrupt occurs CardFinishCommandInterrupt
+// will be called.
+//
+USHORT EP3CDoCommand(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ EP3CSetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiDoCommand(t);
+
+ // put the parallel adapter back to parallel mode
+
+ EP3CSetPrinterMode(g, data, control);
+ return rval;
+}
+
+//
+// EP3CStartCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the EP3C does not support interrupts on its own.
+//
+//
+USHORT EP3CStartCommandInterrupt(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ EP3CSetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiStartCommandInterrupt(t);
+
+ // put the parallel adapter back to parallel mode
+
+ EP3CSetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// EP3CFinishCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the EP3C does not support interrupts on its own.
+//
+//
+USHORT EP3CFinishCommandInterrupt(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ EP3CSetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiFinishCommandInterrupt(t);
+
+ // put the parallel adapter back to parallel mode
+
+ EP3CSetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// EP3CInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the EP3C does not support interrupts on its own.
+//
+BOOLEAN EP3CInterrupt(PADAPTER_INFO g)
+{
+ BOOLEAN rval;
+ UCHAR data;
+ UCHAR control;
+
+ // put the parallel adapter into scsi mode
+
+ EP3CSetScsiMode(g, &data, &control);
+
+ rval = N5380Interrupt(g);
+
+ // put the parallel adapter back to parallel mode
+
+ EP3CSetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// EP3CResetBus
+//
+// Resets the SCSI Bus
+//
+VOID EP3CResetBus(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+
+ // reset the EP3C
+
+ EP3CPortSet(g,EP3C_AREG2,EP3C_RST);
+
+ // put the parallel adapter into scsi mode
+
+ EP3CSetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ N53C400ResetBus(g);
+
+ // put the parallel adapter back to parallel mode
+
+ EP3CSetPrinterMode(g, data, control);
+}
+
+//
+// N53C400PortPut
+//
+// This routine is used by the N53C400.C module to write byte to a 53C400
+// controller. This allows the module to be card independent. Other
+// modules that assume a N53C400 may also use this function.
+//
+VOID N53C400PortPut(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
+{
+ (*(g->EP3CWriteDataRegister))(g, reg, byte);
+}
+
+//
+// N53C400PortGet
+//
+// This routine is used by the N53C400.C module to get a byte from a 53C400
+// controller. This allows the module to be card independent. Other
+// modules that assume a N53C400 may also use this function.
+//
+VOID N53C400PortGet(PADAPTER_INFO g,UCHAR reg,PUCHAR byte)
+{
+ (*(g->EP3CReadDataRegister))(g, reg, byte);
+}
+
+//
+// VOID N53C400PortSet
+//
+// Sets the bit pattern at the given register.
+//
+VOID N53C400PortSet(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
+{
+ UCHAR tmp;
+ (*(g->EP3CReadDataRegister))(g, reg, &tmp);
+ tmp |= byte;
+ (*(g->EP3CWriteDataRegister))(g, reg, tmp);
+}
+
+//
+// VOID N53C400PortClear
+//
+// Clears a bit pattern at the given register.
+//
+VOID N53C400PortClear(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
+{
+ UCHAR tmp;
+
+ (*(g->EP3CReadDataRegister))(g, reg, &tmp);
+ tmp &= (byte ^ 0xff);
+ (*(g->EP3CWriteDataRegister))(g, reg, tmp);
+}
+
+//
+// BOOLEAN N53C400PortTest
+//
+// Tests for a bit pattern on the given register.
+//
+BOOLEAN N53C400PortTest(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
+{
+ UCHAR tmp;
+
+ (*(g->EP3CReadDataRegister))(g, reg, &tmp);
+ return (tmp & byte);
+}
+
+
+//
+// VOID N53C400PortGetBuffer
+//
+// Gets a buffer of 128 bytes from the n53c400. Note, the len here
+// is ignored.
+//
+VOID N53C400PortGetBuffer(PADAPTER_INFO g, UCHAR reg,
+ PUCHAR pbytes, ULONG len)
+{
+ // set the 53c400 register to access
+
+ (*(g->EP3CSetRegister))(g,reg);
+
+ // read the fifo
+
+ (*(g->EP3CReadFifo))(g->BaseIoAddress, pbytes);
+}
+
+//
+// VOID N53C400PortPutBuffer
+//
+// Puts a buffer of 128 bytes from the n53c400. Note, the len here
+// is ignored.
+//
+VOID N53C400PortPutBuffer(PADAPTER_INFO g, UCHAR reg,
+ PUCHAR pbytes, ULONG len)
+{
+ // set the 53c400 register to access
+
+ (*(g->EP3CSetRegister))(g,reg);
+
+ // read the fifo
+
+ (*(g->EP3CWriteFifo))(g->BaseIoAddress, pbytes);
+}
+
+//======================================================================
+// Conditionally-coded routines using in-line assembler.
+//======================================================================
+
+#ifdef WINNT
+
+
+//----------------------------------------------------------------------
+// VOID EP3CReadFifoUniDir
+//
+// Reads bytes for uni-directional parallel port from the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+//----------------------------------------------------------------------
+
+VOID EP3CReadFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi, pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+ loop0:
+ mov al, 0x80
+ out dx,al // select high nibble
+
+ jmp delay0
+ delay0:
+
+ add edx,2 // DX -> ctl reg
+ mov al,P_AFX // assert bufen and afx
+ out dx,al // assert dreg read
+
+ jmp delay1
+ delay1:
+
+ dec edx // DX -> stat reg
+ in al,dx // read high nibble
+
+ jmp delay2
+ delay2:
+
+ mov ah,al
+ shl ah,1
+ and ah,0f0h // AH -> adj high nibble
+ dec edx // DX -> data reg
+ sub al,al
+ out dx,al // select low nibble
+
+ jmp delay3
+ delay3:
+
+ inc edx // DX -> stat reg
+ in al,dx // read low nibble
+
+ shr al,1
+ shr al,1
+ shr al,1
+ and al,0fh // AL = adj low nibble
+ or al,ah // AL = recombined byte
+
+ mov [edi],al // store
+ inc edi // bump buf ptr
+
+ inc edx // DX -> ctl reg
+ xor al,al // negate afx (bufen stays asserted)
+ out dx,al // end read
+
+ jmp delay4
+ delay4:
+
+ sub edx,2 // DX -> data reg
+ dec ecx
+ jnz loop0
+
+ pop edi
+ pop ds
+ }
+}
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CReadFifoUniDirSlow
+//
+// Reads bytes for uni-directional parallel port from the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+// USES FULL HANDSHAKING
+//
+//----------------------------------------------------------------------
+
+VOID EP3CReadFifoUniDirSlow(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi, pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ inc edx // edx - status register
+ mov ecx, 128
+ loop0:
+
+ dec edx // edx - data register
+ mov al, 0x80
+ out dx,al // select high nibble
+
+ jmp delay0
+ delay0:
+
+ add edx,2 // DX -> ctl reg
+ mov al,P_AFX // assert bufen and afx
+ out dx,al // assert dreg read
+
+ // wait till ready, P_BUSY asserted
+ dec edx // edx - status register
+ loop1:
+ in al,dx
+ test al, P_BUSY
+ jnz loop1
+
+ // delay to make sure we get high nibble in
+ jmp delay01
+ delay01:
+ in al,dx
+
+ mov ah,al
+ shl ah,1
+ and ah,0f0h // AH -> adj high nibble
+ dec edx // DX -> data reg
+ sub al,al
+ out dx,al // select low nibble
+
+ jmp delay3
+ delay3:
+
+ inc edx // DX -> stat reg
+ in al,dx // read low nibble
+
+ shr al,1
+ shr al,1
+ shr al,1
+ and al,0fh // AL = adj low nibble
+ or al,ah // AL = recombined byte
+
+ mov [edi],al // store
+ inc edi // bump buf ptr
+
+ inc edx // DX -> ctl reg
+ xor al,al // negate afx (bufen stays asserted)
+ out dx,al // end read
+
+ dec edx // DX -> status register
+ // wait for P_BUSY deasserted
+ loop2:
+ in al,dx
+ test al, P_BUSY
+ jz loop2
+
+ dec ecx
+ jnz loop0
+
+ pop edi
+ pop ds
+ }
+}
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CReadFifoBiDir
+//
+// Reads bytes for bi-directional parallel port from the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+//----------------------------------------------------------------------
+
+VOID EP3CReadFifoBiDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi,pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+ add edx, 2 // edx - control register
+ loop0:
+ mov al, P_BUFEN + P_AFX
+ out dx, al
+
+ jmp delay0
+ delay0:
+
+ sub edx,2 // edx - data register
+
+ in al,dx
+ mov [edi], al
+ inc edi
+
+ add edx,2 // edx - control register
+
+ mov al, P_BUFEN
+ out dx, al
+
+ jmp delay1 // is this needed, there is a loop?
+ delay1:
+
+ dec ecx
+ jnz loop0
+
+ xor al,al // leave control regiser 0'd
+ out dx, al
+
+ pop edi
+ pop ds
+ }
+}
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CReadFifoBiDirSlow
+//
+// Reads bytes for bi-directional parallel port from the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+// USES FULL HANDSHAKING
+//
+//----------------------------------------------------------------------
+
+VOID EP3CReadFifoBiDirSlow(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi,pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+ add edx, 0x02 // edx - control register
+
+ // wait for data to be ready, P_BUSY asserted
+ loop0:
+ mov al, P_BUFEN + P_AFX
+ out dx, al
+
+ dec edx // edx - status register
+ loop1:
+ in al,dx
+ test al, P_BUSY
+ jnz loop1
+
+ dec edx // edx - data register
+
+ in al,dx
+ mov [edi], al
+ inc edi
+
+ add edx,2 // edx - control register
+
+ // end data read cycle
+ mov al, P_BUFEN
+ out dx, al
+
+ dec edx // edx - status register
+
+ // wait for P_BUSY deasserted
+ loop2:
+ in al,dx
+ test al, P_BUSY
+ jz loop2
+
+ inc edx // edx - control register
+
+ dec ecx
+ jnz loop0
+
+ xor al,al // leave control regiser 0'd
+ out dx, al
+
+ pop edi
+ pop ds
+ }
+}
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CWriteFifoUniDir
+//
+// Writes bytes thru uni-directional parallel port to the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+//----------------------------------------------------------------------
+
+VOID EP3CWriteFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi,pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+
+ loop0:
+ mov al,[edi]
+ out dx,al
+ inc edi
+
+ add edx,2 ;DX -> ctl reg
+ mov al,P_STB ;assert bufen, stb
+ out dx,al
+ or al,P_AFX ;assert dreg write
+ out dx,al
+
+ jmp delay0
+ delay0:
+ ;leave bufen asserted
+ mov al,0 ; and negate afx, stb
+ out dx,al ;end write
+
+ jmp delay1
+ delay1:
+
+ sub edx,2 ;DX -> data reg
+ dec ecx
+ jnz loop0
+
+// let's leave control register 0'd for all these fifo routines...
+// add edx,2 ;DX -> ctl reg
+// or al,P_BUFEN ;negate bufen
+// out dx,al
+
+
+ jmp delay2
+ delay2:
+
+ pop edi
+ pop ds
+ }
+}
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CWriteFifoUniDirSlow
+//
+// Writes bytes thru uni-directional parallel port to the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+// USES FULL HANDSHAKING
+//
+//----------------------------------------------------------------------
+
+VOID EP3CWriteFifoUniDirSlow(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi,pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+
+ loop0:
+ mov al,[edi]
+ out dx,al
+ inc edi
+
+ add edx,2 ;DX -> ctl reg
+ mov al,P_STB ;assert bufen, stb
+ out dx,al
+ or al,P_AFX ;assert dreg write
+ out dx,al
+
+ // wait till ready, P_BUSY asserted
+ dec edx // edx - status register
+ loop1:
+ in al,dx
+ test al, P_BUSY
+ jnz loop1
+
+ inc edx // edx - control register
+
+ ;leave bufen asserted
+ mov al,0 ; and negate afx, stb
+ out dx,al ;end write
+
+ dec edx // edx - status register
+
+ // wait for P_BUSY deasserted
+ loop2:
+ in al,dx
+ test al, P_BUSY
+ jz loop2
+
+ dec edx // edx - data register
+
+ dec ecx
+ jnz loop0
+
+// let's leave control register 0'd for all these fifo routines...
+// add edx,2 ;DX -> ctl reg
+// or al,P_BUFEN ;negate bufen
+// out dx,al
+
+ pop edi
+ pop ds
+ }
+}
+
+#endif // #ifdef WINNT
diff --git a/private/ntos/miniport/trantor/source/ep3c2.asm b/private/ntos/miniport/trantor/source/ep3c2.asm
new file mode 100644
index 000000000..b57ac5a89
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/ep3c2.asm
@@ -0,0 +1,526 @@
+ page
+;***********************************************************************
+;
+; (C) Copyright 1992 Trantor Systems, Ltd.
+; All Rights Reserved.
+;
+; This program is an unpublished copyrighted work which is proprietary
+; to Trantor Systems, Ltd. and contains confidential information that
+; is not to be reproduced or disclosed to any other person or entity
+; without prior written consent from Trantor Systems, Ltd. in each
+; and every instance.
+;
+; WARNING: Unauthorized reproduction of this program as well as
+; unauthorized preparation of derivative works based upon the
+; program or distribution of copies by sale, rental, lease or
+; lending are violations of federal copyright laws and state trade
+; secret laws, punishable by civil and criminal penalties.
+;
+;***********************************************************************
+ title EP3C2.ASM
+;-----------------------------------------------------------------------
+;
+; EP3C2.ASM
+;
+; FIFO I/O Routines for the EP3C chip.
+; Assembly coded for speed. These are only some of the routines
+; needed for the EP3C. The rest are in EP3C.C.
+;
+; History
+; -------
+; 05-17-93 JAP First, from ep3c.c
+;
+;-----------------------------------------------------------------------
+
+;-----------------------------------------------------------------------
+; stack frame equates
+;-----------------------------------------------------------------------
+
+ep3c_param2 equ 12
+ep3c_param1 equ 8
+ep3c_retAdrs equ 4
+ep3c_bp equ 0
+
+ep3c_pbytes equ ep3c_param2
+ep3c_baseIoAddress equ ep3c_param1
+
+
+;-----------------------------------------------------------------------
+; Macros
+;-----------------------------------------------------------------------
+
+;-----------------------------------------------------------------------
+; get_params
+;
+; Puts parameters into registers:
+; edx -> baseIoAddress
+; ds:[edi] -> pbytes
+;-----------------------------------------------------------------------
+
+get_params macro
+
+ ifdef MODE_32BIT
+
+ mov edi, dword ptr [ebp].ep3c_pbytes
+ mov edx, dword ptr [ebp].ep3c_baseIoAddress
+
+ else
+
+ mov edi, word ptr ss:[bp].ep3c_pbytes
+ mov ds, word ptr ss:[bp].ep3c_pbytes+2
+ mov edx, word ptr ss:[bp].ep3c_baseIoAddress
+
+ endif ;MODE_32BIT
+
+ endm
+
+
+;-----------------------------------------------------------------------
+; Routines
+;-----------------------------------------------------------------------
+
+;-----------------------------------------------------------------------
+; EP3CReadFifoUniDir
+;
+; VOID EP3CReadFifoUniDir (PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+;
+; Reads bytes for uni-directional parallel port from the 53c400
+; 128 byte buffer. The register must already be set the the
+; 53c400 buffer register.
+;
+;-----------------------------------------------------------------------
+
+EP3CReadFifoUniDir proc far
+
+ push ds
+ push edi
+
+ get_params
+
+ mov ecx, 128
+
+loop0:
+ mov al, 0x80
+ out dx, al ;select high nibble
+ jmp delay0
+
+delay0:
+ add edx,2 ;DX -> ctl reg
+ mov al,P_AFX ;assert bufen and afx
+ out dx,al ;assert dreg read
+ jmp delay1
+
+delay1:
+ dec edx ;DX -> stat reg
+ in al,dx ;read high nibble
+ jmp delay2
+
+delay2:
+ mov ah,al
+ shl ah,1
+ and ah,0f0h ;AH -> adj high nibble
+ dec edx ;DX -> data reg
+ sub al,al
+ out dx,al ;select low nibble
+ jmp delay3
+
+delay3:
+ inc edx ;DX -> stat reg
+ in al,dx ;read low nibble
+
+ shr al,1
+ shr al,1
+ shr al,1
+ and al,0fh ;AL = adj low nibble
+ or al,ah ;AL = recombined byte
+
+ mov [edi],al ;store
+ inc edi ;bump buf ptr
+
+ inc edx ;DX -> ctl reg
+ xor al,al ;negate afx (bufen stays asserted)
+ out dx,al ;end read
+ jmp delay4
+
+delay4:
+ sub edx,2 ;DX -> data reg
+ dec ecx
+ jnz loop0
+
+ pop edi
+ pop ds
+ ret
+
+EP3CReadFifoUniDir endp
+
+;-----------------------------------------------------------------------
+;
+; EP3CReadFifoUniDirSlow
+;
+; VOID EP3CReadFifoUniDirSlow (PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+;
+; Reads bytes for uni-directional parallel port from the 53c400
+; 128 byte buffer. The register must already be set the the
+; 53c400 buffer register.
+;
+; USES FULL HANDSHAKING
+;
+;-----------------------------------------------------------------------
+
+EP3CReadFifoUniDirSlow proc far
+
+ push ds
+ push edi
+
+ get_params
+
+ inc edx // edx - status register
+ mov ecx, 128
+
+loop0:
+ dec edx // edx - data register
+ mov al, 0x80
+ out dx,al // select high nibble
+ jmp delay0
+
+delay0:
+ add edx, 2 // DX -> ctl reg
+ mov al, P_AFX // assert bufen and afx
+ out dx, al // assert dreg read
+
+; wait till ready, P_BUSY asserted
+
+ dec edx // edx - status register
+
+loop1:
+ in al,dx
+ test al, P_BUSY
+ jnz loop1
+
+; delay to make sure we get high nibble in
+
+ jmp delay01
+
+delay01:
+ in al,dx
+
+ mov ah,al
+ shl ah,1
+ and ah,0f0h // AH -> adj high nibble
+ dec edx // DX -> data reg
+ sub al,al
+ out dx,al // select low nibble
+
+ jmp delay3
+
+delay3:
+ inc edx // DX -> stat reg
+ in al,dx // read low nibble
+
+ shr al,1
+ shr al,1
+ shr al,1
+ and al,0fh // AL = adj low nibble
+ or al,ah // AL = recombined byte
+
+ mov [edi],al // store
+ inc edi // bump buf ptr
+
+ inc edx // DX -> ctl reg
+ xor al,al // negate afx (bufen stays asserted)
+ out dx,al // end read
+
+ dec edx // DX -> status register
+
+; wait for P_BUSY deasserted
+
+loop2:
+ in al,dx
+ test al, P_BUSY
+ jz loop2
+
+ dec ecx
+ jnz loop0
+
+ pop edi
+ pop ds
+ ret
+
+EP3CReadFifoUniDirSlow endp
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CReadFifoBiDir
+//
+// Reads bytes for bi-directional parallel port from the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+//----------------------------------------------------------------------
+
+VOID EP3CReadFifoBiDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi,pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+ add edx, 2 // edx - control register
+ loop0:
+ mov al, P_BUFEN + P_AFX
+ out dx, al
+
+ jmp delay0
+ delay0:
+
+ sub edx,2 // edx - data register
+
+ in al,dx
+ mov [edi], al
+ inc edi
+
+ add edx,2 // edx - control register
+
+ mov al, P_BUFEN
+ out dx, al
+
+ jmp delay1 // is this needed, there is a loop?
+ delay1:
+
+ dec ecx
+ jnz loop0
+
+ xor al,al // leave control regiser 0'd
+ out dx, al
+
+ pop edi
+ pop ds
+ }
+}
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CReadFifoBiDirSlow
+//
+// Reads bytes for bi-directional parallel port from the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+// USES FULL HANDSHAKING
+//
+//----------------------------------------------------------------------
+
+VOID EP3CReadFifoBiDirSlow(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi,pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+ add edx, 0x02 // edx - control register
+
+ // wait for data to be ready, P_BUSY asserted
+ loop0:
+ mov al, P_BUFEN + P_AFX
+ out dx, al
+
+ dec edx // edx - status register
+ loop1:
+ in al,dx
+ test al, P_BUSY
+ jnz loop1
+
+ dec edx // edx - data register
+
+ in al,dx
+ mov [edi], al
+ inc edi
+
+ add edx,2 // edx - control register
+
+ // end data read cycle
+ mov al, P_BUFEN
+ out dx, al
+
+ dec edx // edx - status register
+
+ // wait for P_BUSY deasserted
+ loop2:
+ in al,dx
+ test al, P_BUSY
+ jz loop2
+
+ inc edx // edx - control register
+
+ dec ecx
+ jnz loop0
+
+ xor al,al // leave control regiser 0'd
+ out dx, al
+
+ pop edi
+ pop ds
+ }
+}
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CWriteFifoUniDir
+//
+// Writes bytes thru uni-directional parallel port to the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+//----------------------------------------------------------------------
+
+VOID EP3CWriteFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi,pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+
+ loop0:
+ mov al,[edi]
+ out dx,al
+ inc edi
+
+ add edx,2 ;DX -> ctl reg
+ mov al,P_STB ;assert bufen, stb
+ out dx,al
+ or al,P_AFX ;assert dreg write
+ out dx,al
+
+ jmp delay0
+ delay0:
+ ;leave bufen asserted
+ mov al,0 ; and negate afx, stb
+ out dx,al ;end write
+
+ jmp delay1
+ delay1:
+
+ sub edx,2 ;DX -> data reg
+ dec ecx
+ jnz loop0
+
+// let's leave control register 0'd for all these fifo routines...
+// add edx,2 ;DX -> ctl reg
+// or al,P_BUFEN ;negate bufen
+// out dx,al
+
+
+ jmp delay2
+ delay2:
+
+ pop edi
+ pop ds
+ }
+}
+
+
+//----------------------------------------------------------------------
+//
+// VOID EP3CWriteFifoUniDirSlow
+//
+// Writes bytes thru uni-directional parallel port to the 53c400
+// 128 byte buffer. The register must already be set the the
+// 53c400 buffer register.
+//
+// USES FULL HANDSHAKING
+//
+//----------------------------------------------------------------------
+
+VOID EP3CWriteFifoUniDirSlow(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
+{
+ _asm {
+ push ds
+ push edi
+
+#ifdef MODE_32BIT
+ mov edi,pbytes
+ mov edx, baseIoAddress
+#else
+ mov edi, word ptr pbytes
+ mov ds, word ptr pbytes+2
+ mov edx, word ptr baseIoAddress
+#endif // MODE_32BIT
+ mov ecx, 128
+
+ loop0:
+ mov al,[edi]
+ out dx,al
+ inc edi
+
+ add edx,2 ;DX -> ctl reg
+ mov al,P_STB ;assert bufen, stb
+ out dx,al
+ or al,P_AFX ;assert dreg write
+ out dx,al
+
+ // wait till ready, P_BUSY asserted
+ dec edx // edx - status register
+ loop1:
+ in al,dx
+ test al, P_BUSY
+ jnz loop1
+
+ inc edx // edx - control register
+
+ ;leave bufen asserted
+ mov al,0 ; and negate afx, stb
+ out dx,al ;end write
+
+ dec edx // edx - status register
+
+ // wait for P_BUSY deasserted
+ loop2:
+ in al,dx
+ test al, P_BUSY
+ jz loop2
+
+ dec edx // edx - data register
+
+ dec ecx
+ jnz loop0
+
+// let's leave control register 0'd for all these fifo routines...
+// add edx,2 ;DX -> ctl reg
+// or al,P_BUFEN ;negate bufen
+// out dx,al
+
+ pop edi
+ pop ds
+ }
+}
+
+
+ \ No newline at end of file
diff --git a/private/ntos/miniport/trantor/source/findpas.c b/private/ntos/miniport/trantor/source/findpas.c
new file mode 100644
index 000000000..7b60bdb8c
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/findpas.c
@@ -0,0 +1,303 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ findpas.c
+
+Abstract:
+
+ This module contains code configuration code MediaVision's Pro audio
+ spectrum. The card is run in Sound Blaster compatibiltiy mode.
+
+ Support is provided for volume setting and line input and
+ microphone mix level setting.
+
+ The card is located by searching. No user configuration is supported.
+
+Author:
+
+ Adapted from work by Robin Speed (RobinSp) 17-Oct-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include CARDTXXX_H
+#include "findpas.h"
+
+
+
+//--------------========================---------------------------
+//---------====< GLOBAL DATA SECTION >====-------------------------
+//--------------========================---------------------------
+
+// The board signature is the first value in the PAS 16 wakeup sequence
+// BC is the factory default. A board jumpered to recognize the BD signature
+// will not respond to a BC init command.
+
+UCHAR SignatureTable[4]={0xBC,0xBD,0xBE,0xBF};
+
+//
+// MPU stuff here until we work out what we want
+//
+
+#define MPU_ADDR 0x330
+
+#define MPU_IRQ 2
+#define MPU_EMUL_IRQ EMUL_IRQ_2
+
+
+//
+// Local routines
+//
+
+
+BOOLEAN
+VerifyProHardware(
+ PFOUNDINFO pFI,
+ ULONG port);
+
+BOOLEAN
+WakeUpAtAddress(
+ PFOUNDINFO pFoundInfo,
+ ULONG wPort);
+
+; /*\
+;---|*|------====< DWORD GetProTableRead() >====------
+;---|*|
+;---|*| Detects which version of the Pro AudioSpectrum is installed
+;---|*|
+;---|*| Entry Conditions:
+;---|*| Pointer to Profile Structure. If the caller wants to specify
+;---|*| the preferred base address for cards not yet init'd, they
+;---|*| are passed in this structure. The NumFound field indicates
+;---|*| the number of location requests and the board address elements
+;---|*| indicate the locations.
+;---|*|
+;---|*| Also passed in pointer to port (the one we found in the registry
+;---|*| if any
+;---|*|
+;---|*| Exit Conditions:
+;---|*| Returns number of cards found
+;---|*| ProFile structure has been updated.
+;---|*|
+; \*/
+
+
+int
+FindPasHardware(
+ PFOUNDINFO pFoundInfo
+)
+ // PSB_CONFIG_DATA ConfigData )
+{
+
+ if (WakeUpAtAddress(pFoundInfo, pFoundInfo->ProPort)) {
+
+ return 1;
+ }
+
+ return 0;
+}
+
+; /*\
+;---|*|------====< int VerifyProHardware() >====------
+;---|*|
+;---|*| Detects which version of the Pro AudioSpectrum is installed
+;---|*|
+;---|*| Entry Conditions:
+;---|*| pFI - found info pointer -- has PROBase mapped I/O space.
+;---|*| port - I/O port location to search -- not mapped.
+;---|*|
+;---|*| Exit Conditions:
+;---|*| Returns TRUE if ProAudio found.
+;---|*| Returns FALSE if not found.
+;---|*|
+; \*/
+
+
+BOOLEAN
+VerifyProHardware(
+ PFOUNDINFO pFI,
+ ULONG port)
+{
+ UCHAR bData, bTemp;
+
+ DebugPrint((DEBUG_LEVEL,"VerifyProHardware (proport %X,probase %X, port %X)\n",pFI->ProPort,pFI->PROBase,port));
+ pFI->TranslateCode = port ^ DEFAULT_BASE;
+
+ bData=PASX_IN (pFI, INTERRUPT_CTRL_REG);
+
+ if (bData==0xFF) { // 0xFF usually means nothing there
+ goto VerifyFailed;
+ }
+ pFI->wBoardRev= (bData >>5); // board rev is 3 topmost bits
+
+ switch (pFI->wBoardRev) {
+#ifndef WINNT
+ // winnt does not want support for old cards, this code recognizes
+ // some sound blasters
+ case PAS_VERSION_1:
+#endif
+ //case PAS_PLUS: // same boardrev as PAS_SIXTEEN
+ case PAS_STUDIO:
+ case PAS_SIXTEEN:
+ case PAS_CDPC:
+ case 4: // Memphis
+ break;
+
+ default:
+ goto VerifyFailed; // unknown hardware type
+ }
+
+ PASX_OUT(pFI, INTERRUPT_CTRL_REG, bData ^ 0xE0); // try changing version bits
+ bTemp=PASX_IN (pFI, INTERRUPT_CTRL_REG); // they should be read only
+
+ if ((bTemp & (D7+D6+D5)) != (bData & (D7+D6+D5))) {
+ PASX_OUT(pFI, INTERRUPT_CTRL_REG, bData); // Excuse me, stranger.
+ goto VerifyFailed;
+ }
+
+ if (pFI->wBoardRev==PAS_VERSION_1) {
+
+ pFI->Caps.CapsBits.CDInterfaceType=SCSI_TYPE;
+
+ //
+ // test for Enhanced SCSI mod (U48)
+ //
+
+ PASX_OUT(pFI, ENHANCED_SCSI_DETECT_REG, 0 ); // write to try changing version bits
+ ScsiPortStallExecution(10); // wait 10 us
+ bTemp=PASX_IN ( pFI, ENHANCED_SCSI_DETECT_REG ); // they should be read only
+
+ switch (bTemp & 1) { // bit0==1 means old SCSI PAL
+ case 0:
+ pFI->Caps.CapsBits.EnhancedSCSI=TRUE;
+ // allow to fall thru
+
+ case 1:
+ goto ProVerified;
+ }
+ } else {
+ // if PAS hardware installed, the reset bit can never be on
+
+ bTemp=PASX_IN (pFI, SYSTEM_CONFIG_1); // get PAS config register
+ if (bTemp & D7) { // D7 is reset bit
+ goto VerifyFailed;
+ }
+
+ bTemp=PASX_IN (pFI, SLAVE_MODE_READ);
+
+ if (bTemp & SLAVE_MODE_OPL3) {
+ pFI->Caps.CapsBits.OPL_3=TRUE;
+ }
+
+ if (bTemp & SLAVE_MODE_16) {
+ pFI->Caps.CapsBits.DAC16=TRUE;
+ pFI->Caps.CapsBits.DualDAC=TRUE;
+
+ // if 16-bit DAC, and not a CDPC, it has a 508 chip.
+ // Note: PAS 16 w/ VGA will have Mixer 508 also.
+
+ if (pFI->wBoardRev != PAS_CDPC) {
+ pFI->Caps.CapsBits.Mixer_508=TRUE;
+ }
+ }
+
+ pFI->Caps.CapsBits.CDInterfaceType=(bTemp & (D1+D0));
+
+ if (pFI->Caps.CapsBits.CDInterfaceType==SCSI_TYPE) {
+ pFI->Caps.CapsBits.SCSI_IO_16=TRUE;
+ }
+
+ pFI->Caps.CapsBits.Slot16=TRUE;
+ pFI->Caps.CapsBits.SoundBlaster=TRUE;
+
+ bTemp=PASX_IN (pFI, MASTER_MODE_READ); // get slave bits
+ if ((bTemp & D0)==0) {
+ pFI->Caps.CapsBits.MCA=TRUE;
+ }
+
+ if (bTemp & D2) {
+ pFI->Caps.CapsBits.CDPC=TRUE;
+ }
+
+ pFI->wChipRev=PASX_IN (pFI, CHIP_REV);
+ }
+
+ProVerified:
+
+ DebugPrint((DEBUG_LEVEL,"\n\nFound PRO hardware at %X\n", port));
+ pFI->ProPort=port; // found at this port
+ return TRUE;
+
+////////////////////////////////
+
+VerifyFailed:
+ pFI->wBoardRev=0; // found at this port
+ pFI->Caps.dwCaps=0; // No Board, No Caps
+ return FALSE;
+}
+
+; /*\
+;---|*|------====< int WakeUpAtAddress(WORD wPort) >====------
+;---|*|
+;---|*| Tries to wake up sleeping relocatable hardware at a specified
+;---|*| address. Does not check for hardware already in that location
+;---|*| If it does wake up a card, it does the minimum amount of
+;---|*| initialization to enable the hardware.
+;---|*|
+;---|*| Entry Conditions:
+;---|*| wPort= Base I/O address to wake card up at.
+;---|*|
+;---|*| Exit Conditions:
+;---|*| Returns TRUE if ProAudio hardware found.
+;---|*| Returns FALSE if not.
+;---|*|
+; \*/
+BOOLEAN
+WakeUpAtAddress(
+ PFOUNDINFO pFoundInfo,
+ ULONG wPort)
+{
+ int i,j;
+
+ DebugPrint((DEBUG_LEVEL,"WakeUpAtAddress (proport %X,probase %X, port %X)\n",pFoundInfo->ProPort,pFoundInfo->PROBase,wPort));
+ for (i = 0; i < sizeof(SignatureTable) / sizeof(SignatureTable[0]); i++) {
+ for (j = 0; j < 20; j++) {
+ WRITE_PORT_UCHAR(pFoundInfo->PROBase + PAS_2_WAKE_UP_REG, SignatureTable[i]);
+ ScsiPortStallExecution(1);
+ WRITE_PORT_UCHAR(pFoundInfo->PROBase + PAS_2_WAKE_UP_REG, (UCHAR)((wPort >> 2) & 0xFF));
+ ScsiPortStallExecution(1);
+ }
+
+ if (VerifyProHardware(pFoundInfo, wPort)) {
+
+ //
+ // Found one - wTranslateCode translates to the board's
+ // correct port.
+ //
+
+ pFoundInfo->Caps.CapsBits.Did_HW_Init=TRUE;
+
+ if (pFoundInfo->wBoardRev > PAS_VERSION_1 ) {
+ /* Only enable FM feature if we're going to sit at
+ the right address */
+
+ UCHAR Features = PCM_FEATURE_ENABLE | MIXER_FEATURE_ENABLE |
+ SB_FEATURE_ENABLE | FM_FEATURE_ENABLE;
+
+ PASX_OUT(pFoundInfo, FEATURE_ENABLE, Features);
+ }
+
+ return (TRUE);
+ }
+ }
+ return (FALSE); // not found
+}
+
diff --git a/private/ntos/miniport/trantor/source/mv101.c b/private/ntos/miniport/trantor/source/mv101.c
new file mode 100644
index 000000000..549106fd9
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/mv101.c
@@ -0,0 +1,617 @@
+//----------------------------------------------------------------------
+//
+// MV101.C
+//
+// Trantor MV101 access file.
+//
+// These routines are independent of the card the MV101 logic is on. The
+// cardxxxx.h file must define the following routines:
+//
+// MV101PortPut
+// MV101PortGet
+// MV101PortSet
+// MV101PortClear
+// MV101PortTest
+//
+// These routines could be defined by some other include file instead of
+// cardxxxx.h, as the pc9010 defines the needed n5380xxxxxxxx routines.
+//
+// Revisions:
+// 02-25-93 KJB First.
+// 03-05-93 KJB Added call to N5380DisableDmaWrite.
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-11-93 KJB Changed to use new N5380.H names.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
+// 05-13-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters. Auto Request Sense is
+// now supported.
+// 05-13-93 KJB Merged Microsoft Bug fixes to card detection.
+// 05-14-93 KJB Remove all WINNT specific #ifdef i386 references.
+// 05-17-93 KJB Added ErrorLogging capabilities (used by WINNT).
+//
+//----------------------------------------------------------------------
+
+#include CARDTXXX_H
+#include "findpas.h"
+
+//
+// local functions
+//
+
+VOID MV101ResetDmaTimeout (PADAPTER_INFO g);
+VOID MV101EnableDmaWrite (PADAPTER_INFO g);
+VOID MV101EnableDmaRead (PADAPTER_INFO g);
+USHORT MV101WaitXfrReady (PADAPTER_INFO g, ULONG usec);
+
+//
+// local redefines
+//
+#define MV101DisableDmaRead N5380DisableDmaRead
+#define MV101DisableDmaWrite N5380DisableDmaWrite
+
+//
+// N5380PortPut
+//
+// This routine is used by the N5380.C module to write byte to a 5380
+// controller. This allows the module to be card independent. Other
+// modules that assume a N5380 may also use this function.
+//
+
+VOID N5380PortPut (PADAPTER_INFO g, UCHAR reg, UCHAR byte)
+{
+ if (reg<4) {
+ PortIOPut((PUCHAR)g->BaseIoAddress+MV101_5380_1+reg,byte);
+ } else {
+ PortIOPut((PUCHAR)g->BaseIoAddress+MV101_5380_2+reg-4,byte);
+ }
+}
+
+//
+// N5380PortGet
+//
+// This routine is used by the N5380.C module to get a byte from a 5380
+// controller. This allows the module to be card independent. Other
+// modules that assume a N5380 may also use this function.
+//
+
+VOID N5380PortGet (PADAPTER_INFO g, UCHAR reg, PUCHAR byte)
+{
+ if (reg<4) {
+ PortIOGet ((PUCHAR)g->BaseIoAddress+MV101_5380_1+reg, byte);
+ } else {
+ PortIOGet ((PUCHAR)g->BaseIoAddress+MV101_5380_2+reg-4,byte);
+ }
+}
+
+//
+// MV101CheckAdapter
+//
+// This routine sees if there is an adapter at this address. If so,
+// then this adapter is initialized.
+//
+BOOLEAN MV101CheckAdapter (PADAPTER_INFO g)
+{
+ FOUNDINFO fi;
+
+ //
+ // FindPasHardware does it's own mapping of port bases.
+ // Set the base to zero and indicate which port is currently being
+ // polled.
+ //
+
+ fi.PROBase = 0;
+ fi.ProPort = (ULONG) g->BaseIoAddress;
+
+ if (!FindPasHardware(&fi)) {
+ return FALSE;
+ }
+
+ // for old boards, we use bit 1 for drq mask during dma xfers
+ if (fi.wBoardRev == PAS_VERSION_1) {
+ g->DRQMask = 0x01;
+ } else {
+ g->DRQMask = 0x80;
+ }
+
+ // is there an adapter here?
+ if (N5380CheckAdapter (g)) {
+ // found a 5380, initialize special dma hardware for
+ // dma fast read and writes.
+
+ MV101PortPut (g,MV101_SYSTEM_CONFIG4,0x49);
+ MV101PortPut (g,MV101_TIMEOUT_COUNTER,0x30);
+ MV101PortPut (g,MV101_TIMEOUT_STATUS,0x01);
+ MV101PortPut (g,MV101_WAIT_STATE,0x01);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+//
+// MV101WaitXfrReady
+//
+// This routine waits till the DRQ flag goes up.
+//
+USHORT MV101WaitXfrReady (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i=0;i<TIMEOUT_QUICK;i++) {
+
+ // wait for card to be ready
+
+ if (MV101PortTest(g, MV101_DRQ_PORT, g->DRQMask)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i=0; i < usec; i++) {
+
+ // wait for card to be ready
+
+ if (MV101PortTest (g, MV101_DRQ_PORT, g->DRQMask)) {
+ return 0;
+ }
+
+ // see if bus free
+
+ if (!N5380PortTest (g, N5380_CURRENT_STATUS, CS_BSY)) {
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_UNEXPECTED_BUS_FREE, 100);
+
+ return RET_STATUS_UNEXPECTED_BUS_FREE;
+ }
+
+ // since we have taken some time... check for phase change
+
+ if (!N5380PortTest (g, N5380_DMA_STATUS, DS_PHASE_MATCH)) {
+ return RET_STATUS_DATA_OVERRUN;
+ }
+
+ // wait for card to be ready
+
+ ScsiPortStallExecution(1);
+ }
+
+ DebugPrint ((DEBUG_LEVEL,"Error - MV101WaitXfrReady\n"));
+
+ // return with an error, non-zero indicates timeout
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 102);
+
+ return RET_STATUS_TIMEOUT;
+}
+
+
+//
+// MV101ResetDmaTimeout
+//
+// Resets the dma timout bit.
+//
+
+VOID MV101ResetDmaTimeout (PADAPTER_INFO g)
+{
+ MV101PortPut (g, MV101_TIMEOUT_STATUS, 0x01);
+}
+
+
+//
+// MV101EnableDmaRead
+//
+// Enables the DMA read operation for the T128.
+//
+
+VOID MV101EnableDmaRead (PADAPTER_INFO g)
+{
+ // start dma on the 5380
+
+ N5380EnableDmaRead(g);
+
+ // toggle the t120 timeout bit to clear any timeout
+
+ MV101ResetDmaTimeout(g);
+}
+
+
+//
+// MV101EnableDmaWrite
+//
+// Enables the DMA write operation for the T128.
+//
+
+VOID MV101EnableDmaWrite (PADAPTER_INFO g)
+{
+ // start dma on the 5380
+
+ N5380EnableDmaWrite (g);
+
+ // toggle the t120 timeout bit to clear any timeout
+
+ MV101ResetDmaTimeout (g);
+}
+
+
+//
+// MV101SetInterruptLevel
+//
+// The Media Vision MV101s need to be programmed for interrupts.
+// In particular, one needs to set the interrupt level into a register.
+//
+
+VOID MV101SetInterruptLevel (PADAPTER_INFO g, UCHAR level)
+{
+ // int from drive active high
+
+ MV101PortSet (g, MV101_SYSTEM_CONFIG4, 0x04);
+
+ // enable interrupts for the card
+
+ MV101PortSet (g, MV101_SYSTEM_CONFIG4, 0x20);
+
+ // set the interrupt level in IO port config register 3
+
+ MV101PortClear(g,MV101_IO_PORT_CONFIG3,0xf0);
+
+ if (level < 8) {
+ MV101PortSet (g, MV101_IO_PORT_CONFIG3,
+ (UCHAR)((level-1)<<4));
+ }
+ else {
+ MV101PortSet (g, MV101_IO_PORT_CONFIG3,
+ (UCHAR)((7+level-10)<<4));
+ }
+}
+
+
+//
+// MV101EnableInterrupt
+//
+// Enables the interrupt on the card and on the 5380.
+//
+
+VOID MV101EnableInterrupt (PADAPTER_INFO g)
+{
+ // interrupt reset for tmv1 card
+
+ MV101PortSet (g, MV101_TIMEOUT_STATUS, 0x01);
+
+ // enable interrupts on the 5380
+
+ N5380EnableInterrupt (g);
+}
+
+
+//
+// MV101DisableInterrupt
+//
+// Disables the interrupt on the card and on the 5380.
+//
+
+VOID MV101DisableInterrupt (PADAPTER_INFO g)
+{
+ // interrupt reset for tmv1 card
+
+ MV101PortSet (g, MV101_TIMEOUT_STATUS, 0x01);
+
+ // disable the signal from the 5380
+
+ N5380DisableInterrupt (g);
+}
+
+
+//
+// MV101ReadBytesFast
+//
+// This routine is used by the ScsiFnc routines to read bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiReadBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+USHORT MV101ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // for small transfers, use slow loop (inquiry and other stuff)
+
+ if (len < 512) {
+ rval = ScsiReadBytesSlow (g, pbytes, len,
+ pActualLen, phase);
+ return rval;
+ }
+
+ // start dma for this card
+
+ MV101EnableDmaRead (g);
+
+ // wait for buffer to be ready
+
+ if (rval = MV101WaitXfrReady (g,TIMEOUT_REQUEST)) {
+ goto done;
+ }
+
+ // due to the speed of i/o instructions in 486 protected mode,
+ // we can afford to do all the drq checking. There is no need for
+ // the 'blind mode' rep insb transfers. These have been tried and
+ // the result is "20 FF FF FF 20 FF FF 41", indicating that we are
+ // two to three times faster than the card, hence we can afford to
+ // poll the card.
+ {
+ PUCHAR dma_port = (PUCHAR)g->BaseIoAddress + MV101_DMA_PORT;
+ PUCHAR drq_port = (PUCHAR)g->BaseIoAddress + MV101_DRQ_PORT;
+ ULONG xfer_count = len;
+ UCHAR drq_mask = g->DRQMask;
+
+ _asm {
+ pushf
+ push esi
+ push edi
+ push es
+ cld
+ mov ah,drq_mask
+#ifdef MODE_32BIT
+ mov edx,dma_port
+ mov esi,drq_port
+ mov edi,pbytes
+ mov ecx,len
+#else
+ mov edx,word ptr dma_port
+ mov esi,word ptr drq_port
+ mov edi,word ptr pbytes
+ mov ecx,word ptr len
+ mov es,word ptr pbytes+2
+#endif
+ loop1:
+ xchg edx,esi // dx drq_port
+ in al,dx
+ test al,ah
+ jnz ready
+ in al,dx
+ test al,ah
+ jnz ready
+ in al,dx
+ test al,ah
+ jnz ready
+
+ push ecx
+ mov ecx,TIMEOUT_READWRITE_LOOP
+ loop3:
+ mov ebx,0x10000
+ loop2:
+ in al,dx
+ test al,ah
+ jnz ready1
+ in al,dx
+ test al,ah
+ jnz ready1
+
+ // check for phase mismatch
+
+ sub dx, MV101_DRQ_PORT - MV101_5380_2 // dx = N5380_CURRENT_STATUS
+ in al,dx
+ test al,CS_REQ
+ jz no_req
+ add dx, (N5380_DMA_STATUS - N5380_CURRENT_STATUS) // dx = N5380_DMA_STATUS
+ in al,dx
+ test al,DS_PHASE_MATCH
+ jz phase_error
+ sub dx, N5380_DMA_STATUS - N5380_CURRENT_STATUS // dx = N5380_CURRENT_STATUS
+ no_req:
+ add dx, MV101_DRQ_PORT - MV101_5380_2 // dx = MV101_DRQ
+
+ dec ebx
+ jnz loop2
+ dec ecx
+ jnz loop3
+ pop ecx
+ mov rval,RET_STATUS_TIMEOUT
+ jmp short timeout
+ phase_error:
+ pop ecx
+ mov rval,RET_STATUS_DATA_OVERRUN
+ jmp short timeout
+ ready1:
+ pop ecx
+ // jmp ready
+
+ ready:
+ xchg edx,esi // dx dma_port
+ insb
+ dec ecx
+ jnz loop1
+ timeout:
+ pop es
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ pop edi
+ pop esi
+ popf
+ }
+
+ // compute actual xfer len
+ *pActualLen = len - xfer_count;
+ }
+
+done:
+ // disable dma
+
+ MV101DisableDmaRead (g);
+
+ // check for errors...
+
+ if (rval == RET_STATUS_TIMEOUT) {
+ TrantorLogError (g->BaseIoAddress, rval, 103);
+ }
+
+ return rval;
+}
+
+
+//
+// MV101WriteBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiReadBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+
+USHORT MV101WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // for small transfers, use slow loop (inquiry and other stuff)
+
+ if (len < 512) {
+ rval = ScsiWriteBytesSlow (g, pbytes, len,
+ pActualLen, phase);
+ return rval;
+ }
+
+ // start dma for this card
+
+ MV101EnableDmaWrite (g);
+
+ // wait for buffer to be ready
+
+ if (rval = MV101WaitXfrReady (g, TIMEOUT_REQUEST)) {
+ goto done;
+ }
+
+ // due to the speed of i/o instructions in 486 protected mode,
+ // we can afford to do all the drq checking. There is no need for
+ // the 'blind mode' rep insb transfers. These have been tried and
+ // the result is "20 FF FF FF 20 FF FF 41", indicating that we are
+ // two to three times faster than the card, hence we can afford to
+ // poll the card.
+ {
+ PUCHAR dma_port = (PUCHAR)g->BaseIoAddress + MV101_DMA_PORT;
+ PUCHAR drq_port = (PUCHAR)g->BaseIoAddress + MV101_DRQ_PORT;
+ ULONG xfer_count = len;
+ UCHAR drq_mask = g->DRQMask;
+ _asm {
+ pushf
+ push esi
+ push edi
+ push ds
+ cld
+ mov ah,drq_mask
+#ifdef MODE_32BIT
+ mov edx,dma_port
+ mov edi,drq_port
+ mov esi,pbytes
+ mov ecx,len
+#else
+ mov edx,word ptr dma_port
+ mov edi,word ptr drq_port
+ mov esi,word ptr pbytes
+ mov ecx,word ptr len
+ mov ds, word ptr pbytes+2
+#endif
+ loop1:
+ xchg edx,edi // edx drq_port
+ in al,dx
+ test al,ah
+ jnz ready
+ in al,dx
+ test al,ah
+ jnz ready
+ in al,dx
+ test al,ah
+ jnz ready
+
+ push ecx
+ mov ecx,TIMEOUT_READWRITE_LOOP
+ loop3:
+ mov ebx,0x10000
+ loop2:
+ in al,dx
+ test al,ah
+ jnz ready1
+ in al,dx
+ test al,ah
+ jnz ready1
+
+ // check for phase mismatch
+
+ sub dx, MV101_DRQ_PORT - MV101_5380_2 // dx = N5380_CURRENT_STATUS
+ in al,dx
+ test al,CS_REQ
+ jz no_req
+ add dx, N5380_DMA_STATUS - N5380_CURRENT_STATUS // dx = N5380_DMA_STATUS
+ in al,dx
+ test al,DS_PHASE_MATCH
+ jz phase_error
+ sub dx, N5380_DMA_STATUS - N5380_CURRENT_STATUS // dx = N5380_CURRENT_STATUS
+ no_req:
+ add dx, MV101_DRQ_PORT - MV101_5380_2 // dx = MV101_DRQ_PORT
+
+ dec ebx
+ jnz loop2
+ dec ecx
+ jnz loop3
+ pop ecx
+ mov rval,RET_STATUS_TIMEOUT
+ jmp short timeout
+ phase_error:
+ pop ecx
+ mov rval,RET_STATUS_DATA_OVERRUN
+ jmp short timeout
+ ready1:
+ pop ecx
+ // jmp ready
+
+ ready:
+ xchg edx,edi // edx dma_port
+ outsb
+ dec ecx
+ jnz loop1
+ timeout:
+ pop ds
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ pop edi
+ pop esi
+ popf
+ }
+
+ // compute actual xfer len
+ *pActualLen = len - xfer_count;
+ }
+
+done:
+ // disable dma
+
+ MV101DisableDmaWrite (g);
+
+ // check for errors...
+
+ if (rval == RET_STATUS_TIMEOUT) {
+ TrantorLogError (g->BaseIoAddress, rval, 104);
+ }
+
+ return rval;
+}
diff --git a/private/ntos/miniport/trantor/source/n5380.c b/private/ntos/miniport/trantor/source/n5380.c
new file mode 100644
index 000000000..011d7ca16
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/n5380.c
@@ -0,0 +1,970 @@
+//-----------------------------------------------------------------------
+//
+// N5380.C
+//
+// N5380 access file.
+//
+// These routines are independent of the card the N5380 is on. The
+// cardxxxx.h file must define the following routines:
+//
+// N5380PortPut
+// N5380PortGet
+//
+// These routines could be defined by some other include file instead of
+// cardxxxx.h, as the n53c400 defines the needed n5380xxxxxxxx routines.
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 03-02-93 KJB/JAP Added N5380WaitLastByteSent.
+// 03-02-93 JAP Cleaned comments.
+// 03-02-93 KJB Fixed Names-- baseIoAddress back.
+// 03-05-93 KJB Added N5380DisableDmaWrite routine to check for
+// last byte sent. N5380DisableDma name changed to
+// N5380DisableDmaRead.
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-11-93 KJB Changes code to reflect new 5380 names.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-23-93 KJB Changed for new functional interface.
+// 03-24-93 KJB Added some debug code.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+// 05-17-93 KJB Added ErrorLogging capabilities (used by WINNT).
+//
+//-----------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+//-----------------------------------------------------------------------
+//
+// N5380CheckAdapter
+//
+// This routine checks for the presense of a 5380.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN N5380CheckAdapter (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+ USHORT rval;
+
+ // NOTE: May want to reset the bus or the adapter at some point
+ //
+ // CardResetBus(g);
+
+ // set the phase to NULL
+
+ if (rval = N5380SetPhase (g,PHASE_NULL)) {
+ return FALSE;
+ }
+
+ // check to see that the 5380 data register behaves as expected
+
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, IC_DATA_BUS);
+
+ // check for 0x55 write/read in data register
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, 0x55);
+ ScsiPortStallExecution (1);
+ N5380PortGet (g, N5380_CURRENT_DATA, &tmp);
+
+ if (tmp != 0x55) {
+ return FALSE;
+ }
+
+ // check for 0xaa write/read in data register
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, 0xaa);
+ ScsiPortStallExecution (1);
+ N5380PortGet (g, N5380_CURRENT_DATA, &tmp);
+
+ if (tmp != 0xaa) {
+ return FALSE;
+ }
+
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, 0);
+ ScsiPortStallExecution (1);
+ N5380PortGet (g, N5380_CURRENT_DATA, &tmp);
+
+ // data now should not match ....
+
+ if (tmp == 0xaa) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380Select
+//
+// This routine selects a device through the 5380.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380Select (PADAPTER_INFO g, UCHAR target, UCHAR lun)
+{
+ USHORT rval;
+
+ // set the phase to NULL
+
+ if (rval = N5380SetPhase (g, PHASE_NULL)) {
+ return rval;
+ }
+
+ // wait for bsy to go away if someone else is using bus
+
+ if (rval = N5380WaitNoBusy (g, TIMEOUT_BUSY)) {
+ return rval;
+ }
+
+ // assert our id and the target id on the bus
+
+ N5380PortPut (g, N5380_OUTPUT_DATA,
+ (UCHAR)((1 << HOST_ID) | (1 << target)));
+
+ // assert the data on the bus and assert select
+
+ N5380PortSet (g, N5380_INITIATOR_COMMAND,
+ IC_SEL | IC_DATA_BUS);
+
+ // wait for bsy to be asserted
+
+ if (rval = N5380WaitBusy (g, 250)) {
+
+ // clear the data bus
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, 0);
+
+ // clear select and IC_DATA
+
+ N5380PortClear (g, N5380_INITIATOR_COMMAND,
+ IC_SEL | IC_DATA_BUS);
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_SELECTION_TIMEOUT, 10);
+
+ return RET_STATUS_SELECTION_TIMEOUT;
+ }
+
+ // clear the data bus
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, 0);
+
+ // assert the data on the bus, clear select , IC_DATA already set
+
+ N5380PortClear (g, N5380_INITIATOR_COMMAND, IC_SEL);
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380WaitBusy
+//
+// This routine waits for the busy line to be asserted.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380WaitBusy (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ if (N5380PortTest (g, N5380_CURRENT_STATUS, CS_BSY)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for ( i = 0; i < usec; i++) {
+ if (N5380PortTest (g, N5380_CURRENT_STATUS, CS_BSY)) {
+ return 0;
+ }
+ ScsiPortStallExecution (1);
+ }
+
+ // return with an error, non-zero indicates timeout
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 11);
+
+ return RET_STATUS_TIMEOUT;
+}
+
+ #if 0
+//-----------------------------------------------------------------------
+//
+// N5380SelectArbitration
+//
+// This routine selects a device using arbitration.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380SelectArbitration (PADAPTER_INFO g, UCHAR target, UCHAR lun)
+{
+ USHORT rval;
+
+ // set the phase to NULL
+
+ if (rval = N5380SetPhase (g, PHASE_NULL)) {
+ return rval;
+ }
+
+ // put our id bit on the bus
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, (UCHAR)(1 << HOST_ID));
+
+ // begin arbitration
+
+ N5380PortSet (g, N5380_MODE, MR_ARBITRATE);
+
+ // wait for bsy to go away if someone else is using bus
+
+ if (rval = N5380WaitArbitration (g, TIMEOUT_BUSY)) {
+ goto done;
+ }
+
+ // did we win?
+
+ if (N5380PortTest (g, N5380_INITIATOR_COMMAND,
+ IC_LOST_ARBITRATION)) {
+ rval = RET_STATUS_BUSY;
+ TrantorLogError (g->BaseIoAddress, rval, 12);
+ goto done;
+ }
+
+ // we have won, we are device 7, the highest, no one could beat us
+ // assert our id and the target id on the bus
+
+ N5380PortPut (g, N5380_OUTPUT_DATA,
+ (UCHAR)((1 << HOST_ID) | (1 << target)));
+
+ // assert the data on the bus and assert select
+
+ N5380PortSet (g, N5380_INITIATOR_COMMAND,
+ IC_SEL | IC_DATA);
+
+ // clear arb bit
+
+ N5380PortClear (g, N5380_MODE, MR_ARBITRATE);
+
+ // wait for bsy to be asserted
+
+ if (rval = N5380WaitBusy (g, 250)) {
+
+ // clear the data bus
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, 0);
+
+ // clear select and IC_DATA
+
+ N5380PortClear (g, N5380_INITIATOR_COMMAND,
+ IC_SEL | IC_DATA_BUS);
+
+ rval = RET_STATUS_SELECTION_TIMEOUT;
+
+ TrantorLogError (g->BaseIoAddress, rval, 13);
+
+ goto done;
+ }
+
+ // clear the data bus
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, 0);
+
+ // assert the data on the bus, clear select , IC_DATA already set
+
+ N5380PortClear (g, N5380_INITIATOR_COMMAND, IC_SEL);
+
+ // Could go to command phase now, and clear spurrious interrupts...
+ // This is what the T160 does in our assembly code...
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380WaitArbitration
+//
+// This routine waits for the arbitration to finish.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380WaitArbitration (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ if (!N5380PortTest (g, N5380_INITIATOR_COMMAND,
+ IC_ARBITRATION_IN_PROGRESS)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < usec; i++) {
+ if (!N5380PortTest (g, N5380_INITIATOR_COMMAND,
+ IC_ARBITRATION_IN_PROGRESS)) {
+ return 0;
+ }
+ ScsiPortStallExecution (1);
+ }
+
+ // return with an error, non-zero indicates timeout
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 14);
+
+ return RET_STATUS_TIMEOUT;
+}
+
+ #endif
+
+
+//-----------------------------------------------------------------------
+//
+// N5380WaitNoBusy
+//
+// This routine waits for the Busy line to be deasserted.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380WaitNoBusy (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ if (!N5380PortTest (g, N5380_CURRENT_STATUS, CS_BSY)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < usec; i++) {
+ if (!N5380PortTest (g, N5380_CURRENT_STATUS, CS_BSY)) {
+ return 0;
+ }
+ ScsiPortStallExecution (1);
+ }
+
+ // return with an error, non-zero indicates timeout
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 15);
+
+ return RET_STATUS_TIMEOUT;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380WaitRequest
+//
+// This routine waits for request to be asserted.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380WaitRequest (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ if (N5380PortTest (g, N5380_CURRENT_STATUS, CS_REQ)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for ( i = 0; i < usec; i++) {
+ if (N5380PortTest (g, N5380_CURRENT_STATUS, CS_REQ)) {
+ return 0;
+ }
+ if (!N5380PortTest (g, N5380_CURRENT_STATUS, CS_BSY)) {
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_UNEXPECTED_BUS_FREE,16);
+
+ return RET_STATUS_UNEXPECTED_BUS_FREE;
+ }
+ ScsiPortStallExecution (1);
+ }
+
+ // return with an error, non-zero indicates timeout
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 17);
+
+ return RET_STATUS_TIMEOUT;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380WaitLastByteSent
+//
+// This routine waits for last byte of dma transfer to be sent.
+//
+// Note: Not all 5380 chips have this feature.
+// This routine should only be used when you are certain
+// that the chips have this feature (e.g. with the n53c400).
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380WaitLastByteSent (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ if (N5380PortTest (g, N5380_TARGET_COMMAND,
+ TC_LAST_BYTE_SENT)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < usec; i++) {
+ if (N5380PortTest (g, N5380_TARGET_COMMAND,
+ TC_LAST_BYTE_SENT)) {
+ return 0;
+ }
+ ScsiPortStallExecution (1);
+ }
+
+ // return with an error, non-zero indicates timeout
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 18);
+
+ return RET_STATUS_TIMEOUT;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380WaitNoRequest
+//
+// This routine waits for request to be deasserted.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380WaitNoRequest (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ if (!N5380PortTest (g, N5380_CURRENT_STATUS, CS_REQ)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < usec; i++) {
+ if (!N5380PortTest (g, N5380_CURRENT_STATUS, CS_REQ)) {
+ return 0;
+ }
+ ScsiPortStallExecution (1);
+ }
+
+ // return with an error, non-zero indicates timeout
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 19);
+
+ return RET_STATUS_TIMEOUT;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380GetPhase
+//
+// This routine returns the current scsi bus phase.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380GetPhase (PADAPTER_INFO g, PUCHAR phase)
+{
+ UCHAR tmp;
+ USHORT rval;
+
+ // wait for request to be asserted
+
+ if (rval = N5380WaitRequest (g, TIMEOUT_REQUEST)) {
+ return rval;
+ }
+
+ // get current phase
+
+ N5380PortGet (g, N5380_CURRENT_STATUS, &tmp);
+
+ // return the phase
+
+ *phase = (tmp >> 2) & 0x7;
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380SetPhase
+//
+// This routine sets the 5380's expected bus phase in the target command
+// register.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380SetPhase (PADAPTER_INFO g, UCHAR phase)
+{
+ UCHAR tmp;
+
+ // phase must correspond the the bits of the target command register
+
+ N5380PortPut (g, N5380_TARGET_COMMAND, phase);
+
+ N5380PortGet (g, N5380_MODE, &tmp);
+
+ // set the assert data bus bit to the right direction
+
+ if (phase & TC_IO) {
+
+ // IO is set
+
+ if (tmp & MR_TARGET_MODE) {
+
+ // we are in target mode always set the assert data bit
+
+ N5380PortSet (g, N5380_INITIATOR_COMMAND,
+ IC_DATA_BUS);
+ }
+ else {
+
+ // we are in initiator mode clear the data enable bit
+
+ N5380PortClear (g, N5380_INITIATOR_COMMAND,
+ IC_DATA_BUS);
+ }
+ }
+ else {
+
+ // IO is not set
+
+ if (tmp & MR_TARGET_MODE) {
+
+ // we are in initiator mode always set the assert data bit
+
+ N5380PortClear (g, N5380_INITIATOR_COMMAND,
+ IC_DATA_BUS);
+ }
+ else {
+
+ // we are in target mode clear the data assert bit
+
+ N5380PortSet (g, N5380_INITIATOR_COMMAND,
+ IC_DATA_BUS);
+ }
+ }
+
+ // no errors can occur from this function
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380PutByte
+//
+// This routine writes a byte to the scsi bus using the req/ack protocol.
+// To use this routine the phase should be set correctly using N5380SetPhase.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380PutByte(PADAPTER_INFO g, ULONG usec, UCHAR byte)
+{
+ USHORT rval;
+
+ // put data byte to data register
+
+ N5380PortPut (g, N5380_OUTPUT_DATA, byte);
+
+ // wait for request to be asserted
+
+ if (rval = N5380ToggleAck (g, usec)) {
+ return rval;
+ }
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380GetByte
+//
+// This routine reads a byte from the scsi bus using the req/ack protocol.
+// To use this routine the phase should be set correctly using N5380SetPhase.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380GetByte (PADAPTER_INFO g, ULONG usec, PUCHAR byte)
+{
+ USHORT rval;
+
+ // get data byte from data register
+
+ N5380PortGet (g, N5380_CURRENT_DATA, byte);
+
+ // wait for request to be asserted
+
+ if (rval = N5380ToggleAck (g, usec)) {
+ return rval;
+ }
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380ToggleAck
+//
+// This routine performs the req/ack handshake. It asserted ack, waits
+// for request to be deasserted and then clears ack.
+//
+//-----------------------------------------------------------------------
+
+USHORT N5380ToggleAck (PADAPTER_INFO g, ULONG usec)
+{
+ USHORT rval;
+ UCHAR tmp;
+
+ // assert ack
+
+ N5380PortGet (g, N5380_INITIATOR_COMMAND, &tmp);
+ tmp = tmp | IC_ACK;
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, tmp);
+
+ // wait for request to be disappear
+
+ if (rval = N5380WaitNoRequest (g, usec)) {
+ return rval;
+ }
+
+ // clear ack
+
+ N5380PortGet (g, N5380_INITIATOR_COMMAND, &tmp);
+ tmp = tmp & (IC_ACK^0xff);
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, tmp);
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380ResetBus
+//
+// This routine performs a Scsi Bus reset.
+//
+//-----------------------------------------------------------------------
+
+VOID N5380ResetBus (PADAPTER_INFO g)
+{
+ // reset the scsi bus
+
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, IC_RST);
+
+ // leave signal asserted for a little while...
+
+ ScsiPortStallExecution (SCSI_RESET_TIME);
+
+ // Clear reset
+
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, 0);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380EnableDmaWrite
+//
+// This routine does the needed 5380 setup and initiates a dma write.
+//
+//-----------------------------------------------------------------------
+
+VOID N5380EnableDmaWrite (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+
+ // clear any interrupt condition on the 5380
+
+ N5380PortGet (g, N5380_RESET_INTERRUPT, &tmp);
+
+ // set the dma bit of 5380
+
+ N5380PortSet (g, N5380_MODE, MR_DMA_MODE);
+
+ // start the dma on the 5380
+
+ N5380PortPut (g, N5380_START_DMA_SEND, 1);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380EnableDmaRead
+//
+// This routine does the needed 5380 setup and initiates a dma read.
+//
+//-----------------------------------------------------------------------
+
+VOID N5380EnableDmaRead (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+
+ // clear any interrupt condition on the 5380
+
+ N5380PortGet (g, N5380_RESET_INTERRUPT, &tmp);
+
+ // set the dma bit of 5380
+
+ N5380PortSet (g, N5380_MODE, MR_DMA_MODE);
+
+ // start the dma on the 5380
+
+ N5380PortPut (g, N5380_START_INITIATOR_RECEIVE, 1);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380DisableDmaRead
+//
+// This routine disables dma for a read on the 5380.
+//
+//-----------------------------------------------------------------------
+
+VOID N5380DisableDmaRead (PADAPTER_INFO g)
+{
+ // Clear the dma bit of 5380
+
+ N5380PortClear (g, N5380_MODE, MR_DMA_MODE);
+}
+
+//-----------------------------------------------------------------------
+//
+// N5380DisableDmaWrite
+//
+// This routine disables dma on the 5380 for a write command, it will
+// wait until the last byte is sent.
+//
+//-----------------------------------------------------------------------
+
+VOID N5380DisableDmaWrite (PADAPTER_INFO g)
+{
+ USHORT i;
+ UCHAR ack_count;
+
+ // for write commands...
+ // wait till last byte has been sent, don't assume the 5380
+ // has a last byte sent bit in the target command register,
+ // not all 5380s have these
+
+ // will need 3 samples with ack, without request
+ ack_count = 3;
+ for (i=0;i<1000;i++) {
+
+ if (N5380PortTest(g,N5380_CURRENT_STATUS,CS_REQ)) {
+
+ // will need 3 samples with ack, without request
+ ack_count = 3;
+
+ // if request, do we have a phase mismatch?
+
+ if (!N5380PortTest(g,N5380_DMA_STATUS,
+ DS_PHASE_MATCH)) {
+
+ // yes, then we have gone onto the next phase, end of dma ok
+
+ break;
+ }
+
+ } else {
+
+ if (N5380PortTest(g,N5380_DMA_STATUS,DS_ACK)) {
+
+ // ack and no request, decrement our end of sample counter
+ ack_count--;
+
+ if (!ack_count) {
+
+ // sampled 3 times without request or ack.. we're done
+ break;
+ }
+ }
+ }
+ }
+
+ // Clear the dma bit of 5380
+
+ N5380PortClear (g, N5380_MODE, MR_DMA_MODE);
+}
+
+//-----------------------------------------------------------------------
+//
+// N5380Interrupt
+//
+// This routine checks to see if the 5380 has asserted its interrupts line.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN N5380Interrupt (PADAPTER_INFO g)
+{
+ return (N5380PortTest (g, N5380_DMA_STATUS,
+ DS_INTERRUPT_REQUEST));
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380DisableInterrupt
+//
+// This routine clears any pending 5380 interrupt condition.
+//
+//-----------------------------------------------------------------------
+
+VOID N5380DisableInterrupt (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+
+ // clear DMA mode
+
+ N5380PortClear (g, N5380_MODE, MR_DMA_MODE);
+
+ // clear any interrupt condition on the 5380
+
+ N5380PortGet (g, N5380_RESET_INTERRUPT, &tmp);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380PortSet
+//
+// Sets a mask in a 5380 register.
+//
+//-----------------------------------------------------------------------
+
+VOID N5380PortSet (PADAPTER_INFO g, UCHAR reg, UCHAR byte)
+{
+ UCHAR tmp;
+
+ N5380PortGet (g, reg, &tmp);
+ tmp |= byte;
+ N5380PortPut (g, reg, tmp);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380PortClear
+//
+// Clears the given bit mask in a 5380 register.
+//
+//-----------------------------------------------------------------------
+
+VOID N5380PortClear (PADAPTER_INFO g, UCHAR reg, UCHAR byte)
+{
+ UCHAR tmp;
+
+ N5380PortGet (g, reg, &tmp);
+ tmp &= (byte^0xff);
+ N5380PortPut (g, reg, tmp);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380PortTest
+//
+// Tests a bit mask in a 5380 register.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN N5380PortTest (PADAPTER_INFO g, UCHAR reg, UCHAR mask)
+{
+ UCHAR tmp;
+
+ N5380PortGet (g, reg, &tmp);
+ return (tmp & mask);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N5380DebugDump
+//
+// Dumps registers 0-5 to the debug terminal.
+//
+//-----------------------------------------------------------------------
+#ifdef WINNT
+VOID N5380DebugDump (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+ USHORT i;
+
+ DebugPrint((DEBUG_LEVEL, "5380 registers:"));
+ for (i = 0; i < 6; i++) {
+ N5380PortGet (g, (UCHAR)i, &tmp);
+ DebugPrint((DEBUG_LEVEL, " %02x", tmp));
+ }
+ DebugPrint((DEBUG_LEVEL, "\n"));
+}
+#else
+#ifdef DOS
+VOID N5380DebugDump (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+ int i;
+
+ printf("5380 registers:");
+ for (i = 0; i < 6; i++) {
+ N5380PortGet (g, (UCHAR)i, &tmp);
+ printf (" %02x", tmp);
+ }
+ printf ("\n");
+}
+#else
+VOID N5380DebugDump (PADAPTER_INFO g)
+{
+}
+#endif
+#endif
+
+//-----------------------------------------------------------------------
+// End Of File.
+//-----------------------------------------------------------------------
+
diff --git a/private/ntos/miniport/trantor/source/n53c400.c b/private/ntos/miniport/trantor/source/n53c400.c
new file mode 100644
index 000000000..30cf94bd0
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/n53c400.c
@@ -0,0 +1,525 @@
+//-----------------------------------------------------------------------
+//
+// File: N53C400.C
+//
+// N53C400 access file.
+//
+// These routines are independent of the card the N53C400 is on. The
+// cardxxxx.h file must define the following routines:
+//
+// N53C400PortPut
+// N53C400PortGet
+// N53C400PortSet
+// N53C400PortClear
+// N53C400PortTest
+// N53C400PortGetBuffer
+// N53C400PortPutBuffer
+//
+// These routines could be defined by some other include file instead of
+// cardxxxx.h, as the pc9010 defines the needed n5380xxxxxxxx routines.
+//
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 02-19-93 KJB Added support for data underrun read & write.
+// transfer only 2 128 bytes fifos at a time
+// might want to change this back if dataunderrun ok.
+// 03-01-93 KJB Added N53C400CheckAdapter to check specifically for
+// N53C400 and perform a chip reset on the 53C400 before
+// checking.
+// 03-02-93 KJB/JAP Phase checking for data phase moved to scsifnc.c.
+// Wait for last byte sent in write bytes.
+// 03-02-93 JAP Cleaned comments.
+// 03-02-93 KJB Fixed Names-- baseIoAddress back.
+// 03-03-93 JAP Cleaned comments again, reverting func declarations.
+// 03-05-93 JAP Changed N53C400DisableInterrupt() and N53C400EnableInterrupt
+// to mirror what is done in ASM code.
+// 03-07-93 KJB WriteBytesFast now returns the correct error code
+// when error occurs during slow write.
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-11-93 KJB Changes code to reflect new 5380 names.
+// 03-17-93 JAP Removed unreference lablellings.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+// 05-17-93 KJB Added ErrorLogging capabilities (used by WINNT).
+//
+//-----------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+//-----------------------------------------------------------------------
+//
+// Local prototypes
+//
+//-----------------------------------------------------------------------
+
+USHORT N53C400Wait5380Access (PADAPTER_INFO g, ULONG usec);
+USHORT N53C400WaitHostBufferReady (PADAPTER_INFO g, ULONG usec);
+
+
+//-----------------------------------------------------------------------
+//
+// Routines
+//
+//-----------------------------------------------------------------------
+
+//-----------------------------------------------------------------------
+//
+// N53C400CheckAdapter
+//
+// This routine checks for the presense of a 53C400.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN N53C400CheckAdapter (PADAPTER_INFO g)
+{
+ USHORT rval;
+
+ // Reset the N53C400 chip.
+ // WARNING -- Could be destructive to other cards @ this port
+
+ N53C400PortPut (g, N53C400_CONTROL, CR_RST);
+
+ // check by testing the 5380
+
+ rval = N5380CheckAdapter (g);
+
+ return (BOOLEAN) rval;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N53C400WaitHostBufferReady
+//
+// This routine waits until the 53c400's 128 byte queue is ready with
+// or for data.
+//
+//-----------------------------------------------------------------------
+
+USHORT N53C400WaitHostBufferReady (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+ USHORT rval;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ if (!N53C400PortTest (g, N53C400_STATUS, SR_HBFR_RDY)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < usec; i++) {
+ if (!N53C400PortTest (g, N53C400_STATUS, SR_HBFR_RDY)) {
+ return 0;
+ }
+
+ // if we suddenly have access, then phase mismatch and over/underrun
+
+ if (N53C400PortTest (g, N53C400_STATUS, SR_ACCESS)) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ DebugPrint((DEBUG_LEVEL,"Error - 0 - ScsiWaitHostBufferReady\n"));
+ goto error;
+ }
+
+ ScsiPortStallExecution(1);
+ }
+
+ // reset the n53c400 in the case of a timeout
+
+ N53C400PortPut (g, N53C400_CONTROL, CR_RST);
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 30);
+
+ rval = RET_STATUS_TIMEOUT;
+
+error:
+ DebugPrint((DEBUG_LEVEL,"Error - 1 - ScsiWaitHostBufferReady\n"));
+
+ // return with an error, non-zero indicates timeout
+
+ return rval;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N53C400Wait5380Access
+//
+// Waits until 5380 access is allowed.
+//
+//-----------------------------------------------------------------------
+
+USHORT N53C400Wait5380Access (PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ if (N53C400PortTest (g, N53C400_STATUS, SR_ACCESS)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < usec; i++) {
+ if (N53C400PortTest (g, N53C400_STATUS, SR_ACCESS)) {
+ return 0;
+ }
+ ScsiPortStallExecution(1);
+ }
+
+ DebugPrint((DEBUG_LEVEL,"Error - ScsiWait5380Access\n"));
+
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 31);
+
+ // return with an error, non-zero indicates timeout
+
+ return RET_STATUS_TIMEOUT;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N53C400WriteyBytesFast
+//
+// Write the bytes from a n53c400 as fast as possible.
+//
+//-----------------------------------------------------------------------
+
+USHORT N53C400WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ ULONG i;
+ USHORT rval = 0;
+ ULONG remainder;
+ ULONG cnt;
+ ULONG blocks;
+ ULONG total_blocks;
+ UCHAR tmp;
+
+ remainder = len % 128;
+ total_blocks = cnt = len / 128;
+
+ // are there any 128 byte blocks to be received
+
+ while (cnt) {
+
+ // send up to 256 128 bytes blocks at a time
+
+ blocks = (cnt > 256) ? 256 : cnt;
+ cnt -= blocks;
+
+ // clear any interrupt condition on the 5380
+
+ N5380PortGet (g, N5380_RESET_INTERRUPT, &tmp);
+
+ // Clear the 53c400 dir bit.
+ // Don't preserve any bits in this register.
+
+ N53C400PortPut (g, N53C400_CONTROL, 0);
+
+ // set the dma bit of 5380, and enable end of dma int
+
+ N5380PortSet (g, N5380_MODE, MR_DMA_MODE |
+ MR_ENABLE_EODMA_INTERRUPT);
+
+ // start the dma on the 5380
+
+ N5380PortPut (g, N5380_START_DMA_SEND, 1);
+
+ // write the count of 128 byte blocks
+
+ N53C400PortPut (g, N53C400_COUNTER, (UCHAR)blocks);
+
+ for (i = 0; i < blocks; i++) {
+
+ // wait for host buffer ready
+
+ if (rval = N53C400WaitHostBufferReady (g, TIMEOUT_REQUEST)) {
+
+ DebugPrint((DEBUG_LEVEL,"Error - 0 - N53C400WriteBytesFast\n"));
+
+ // calculate # of bytes transferred
+ // not including this one
+
+ *pActualLen = (total_blocks - (cnt+blocks-i)) * 128;
+
+ goto error_clear_dma;
+ }
+
+ N53C400PortPutBuffer (g, N53C400_HOST_BFR, pbytes, 128);
+ pbytes += 128;
+ }
+
+ // wait for access to 5380
+
+ if (rval = N53C400Wait5380Access (g, TIMEOUT_REQUEST)) {
+
+ // if timeout, do reset
+
+ N53C400PortPut (g, N53C400_CONTROL, CR_RST);
+ }
+
+ // wait for last byte to be sent
+
+ if (rval = N5380WaitLastByteSent (g, TIMEOUT_REQUEST)) {
+ goto error_clear_dma;
+ }
+
+ // clear dma mode
+
+ N5380PortClear (g, N5380_MODE, MR_DMA_MODE |
+ MR_ENABLE_EODMA_INTERRUPT);
+ N5380DisableInterrupt (g);
+ }
+
+ // calculate # of bytes transferred
+
+ *pActualLen = (total_blocks - cnt) * 128;
+
+ // If xfr count was not a multiple of 128, write remainder slowly.
+
+ if (remainder) {
+
+ ULONG bytes_xferred;
+
+ rval = ScsiWriteBytesSlow (g, pbytes, remainder, &bytes_xferred,
+ phase);
+
+ *pActualLen += bytes_xferred;
+ }
+
+done:
+ return rval;
+
+error_clear_dma:
+
+ // clear dma mode
+
+ N5380PortClear(g,N5380_MODE, MR_DMA_MODE |
+ MR_ENABLE_EODMA_INTERRUPT);
+ N5380DisableInterrupt(g);
+
+ goto done;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N53C400ReadyBytesFast
+//
+// Read the bytes from a n53c400 as fast as possible.
+//
+//-----------------------------------------------------------------------
+
+USHORT N53C400ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ ULONG i;
+ USHORT rval = 0;
+ ULONG remainder;
+ ULONG cnt;
+ ULONG blocks;
+ ULONG total_blocks;
+ UCHAR tmp;
+
+ // For uneven transfers (here not a multiple of 256),
+ // assume we could have an underrun. Read bytes slow to prevent it...
+
+ if ((len % 256)) {
+ rval = ScsiReadBytesSlow (g, pbytes, len, pActualLen, phase);
+ goto done;
+ }
+
+ remainder = len % 128;
+ total_blocks = cnt = len / 128;
+
+ // are there any 128 byte blocks to be received
+
+ while (cnt) {
+
+ blocks = (cnt > 256) ? 256 : cnt;
+ cnt -= blocks;
+
+ // clear any interrupt condition on the 5380
+
+ N5380PortGet (g, N5380_RESET_INTERRUPT, &tmp);
+
+ // set the 53c400 dir bit
+ // don't preserve any bits in this register...
+
+ N53C400PortPut (g, N53C400_CONTROL, CR_DIR);
+
+ // set the dma bit of 5380, enable end of dma int
+
+ N5380PortSet (g, N5380_MODE, MR_DMA_MODE |
+ MR_ENABLE_EODMA_INTERRUPT);
+
+ // start the dma on the 5380
+
+ N5380PortPut (g, N5380_START_INITIATOR_RECEIVE, 1);
+
+ // write the count of 128 byte blocks
+
+ N53C400PortPut (g, N53C400_COUNTER, (UCHAR)blocks);
+
+ for (i = 0; i < blocks; i++) {
+
+ // wait for host buffer ready
+
+ if (rval = N53C400WaitHostBufferReady (g, TIMEOUT_REQUEST)) {
+
+ // WHAT DO YOU DO when the transfer ends early and the n5380
+ // has some of the bytes in its buffers? HELP!!!
+
+ DebugPrint((DEBUG_LEVEL,"Error - 0 - N53C400ReadBytesFast\n"));
+
+ N53C400PortGetBuffer (g, N53C400_HOST_BFR, pbytes, 128);
+
+ // clear dma mode
+
+ N5380PortClear (g, N5380_MODE, MR_DMA_MODE |
+ MR_ENABLE_EODMA_INTERRUPT);
+ N5380DisableInterrupt (g);
+
+ // calculate # of bytes transferred, not including this one
+
+ *pActualLen = (total_blocks - (cnt+blocks-i)) * 128;
+
+ goto done;
+ }
+
+ N53C400PortGetBuffer (g, N53C400_HOST_BFR, pbytes, 128);
+ pbytes += 128;
+ }
+
+ // wait for access to 5380
+
+ if (rval = N53C400Wait5380Access (g, TIMEOUT_REQUEST)) {
+
+ // if timeout, do reset
+
+ N53C400PortPut (g, N53C400_CONTROL, CR_RST);
+ }
+
+ // clear dma mode
+
+ N5380PortClear (g, N5380_MODE, MR_DMA_MODE |
+ MR_ENABLE_EODMA_INTERRUPT);
+ N5380DisableInterrupt (g);
+ }
+
+ // calculate # of bytes transferred
+
+ *pActualLen = (total_blocks - cnt) * 128;
+
+ // If xfr count was not a multiple of 128, read remainder slowly
+
+ if (remainder) {
+
+ ULONG bytes_xferred;
+
+ ScsiReadBytesSlow (g,pbytes, remainder, &bytes_xferred,
+ phase);
+
+ *pActualLen += bytes_xferred;
+ }
+
+done:
+
+ return rval;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N53C400DisableInterrupt
+//
+// Disable interrupts on the N53C400
+//
+//-----------------------------------------------------------------------
+
+VOID N53C400DisableInterrupt (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+
+ // disable interrupt in the 53c400 for 5380 ints
+
+ N53C400PortGet (g, N53C400_CONTROL, &tmp);
+ tmp &= (CR_DIR | CR_BFR_INT | CR_SH_INT);
+ N53C400PortPut (g, N53C400_CONTROL, tmp);
+
+ // disable the interrupt on the 5380
+
+ N5380DisableInterrupt (g);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N53C400EnableInterrupt
+//
+// Enable interrupts on the N53C400
+//
+//-----------------------------------------------------------------------
+
+VOID N53C400EnableInterrupt (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+
+ // set the dma bit of 5380 so we can get phase mismatch ints
+
+ N5380EnableInterrupt (g);
+
+ // enable interrupt in the 53c400 for 5380 interrupts
+
+ N53C400PortGet (g, N53C400_CONTROL, &tmp);
+ tmp &= (CR_DIR | CR_BFR_INT | CR_5380_INT | CR_SH_INT);
+ tmp |= CR_5380_INT;
+ N53C400PortPut (g, N53C400_CONTROL, tmp);
+}
+
+
+//-----------------------------------------------------------------------
+//
+// N53C400ResetBus
+//
+// Reset the SCSI bus
+//
+//-----------------------------------------------------------------------
+
+VOID N53C400ResetBus (PADAPTER_INFO g)
+{
+ // reset the 53c400
+
+ N53C400PortPut (g, N53C400_CONTROL, CR_RST);
+
+ // disable interrupts
+
+ N53C400DisableInterrupt (g);
+
+ // reset the scsi bus
+
+ N5380ResetBus (g);
+}
+
+
+//-----------------------------------------------------------------------
+// End Of File.
+//-----------------------------------------------------------------------
+
diff --git a/private/ntos/miniport/trantor/source/p3c.c b/private/ntos/miniport/trantor/source/p3c.c
new file mode 100644
index 000000000..275330e5c
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/p3c.c
@@ -0,0 +1,1069 @@
+//-----------------------------------------------------------------------
+//
+// P3C.C
+//
+// Trantor P3C access file.
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 02-25-93 KJB Reorganized, supports dataunderrun with long delay
+// for under run on large xfers. Can we fix this?
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-11-93 KJB Changed to use N5380Enable/DisableDmaRead/Write
+// routines.
+// 03-12-93 KJB Now supports polling thru CardInterrupt and
+// StartCommandInterrupt/FinishCommandInterrupt.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-22-93 KJB Added support for scatter gather: P3CDoIo.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+// 03-26-93 KJB Uni and bi directional read ports.
+// 04-05-93 KJB Removed assembly loop instruction to work with
+// winnt compiler. Removed unused variables.
+// 05-14-93 KJB Remove all WINNT specific #ifdef i386 references.
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+// 05-17-93 KJB Fixed bugs where the wrong parameter was being
+// passed in EP3CDo/Start/FinishCommandInterrupt.
+//
+//-----------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+// Local Functions
+
+VOID P3CPutControl(PADAPTER_INFO g,UCHAR mode, UCHAR reg);
+VOID P3CSetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control);
+VOID P3CSetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control);
+
+USHORT P3CReadBytesFastBiDir(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+USHORT P3CReadBytesFastUniDir(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase);
+BOOLEAN P3CCheckAdapterBiDir(PADAPTER_INFO g);
+BOOLEAN P3CCheckAdapterUniDir(PADAPTER_INFO g);
+
+
+//
+// P3CPutControl
+//
+// This routine writes the p3c mode and the n5380 register number to the
+// P3C.
+//
+VOID P3CPutControl(PADAPTER_INFO g,UCHAR mode, UCHAR reg)
+{
+
+ UCHAR tmp;
+
+ // output the mode and 5380 register to the parallel data reg
+ tmp = (mode & (PC_ADRS ^ 0xff)) | reg;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,tmp);
+
+ //
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = tmp & (0xff ^ P_BUFEN);
+ tmp = tmp | P_STB;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ tmp = tmp & (0xff ^ P_STB);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// P3CSetPrinterMode
+//
+// This routine sets the P3C to printer pass through mode. This is the
+// default mode and should be set after the brief use of scsi mode.
+//
+VOID P3CSetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control)
+{
+ UCHAR tmp;
+
+ // to prevent glitching, put P3C into read sig nibble mode
+ P3CPutControl(g,PCCC_MODE_RSIG_NIBBLE,0);
+
+ // restore data register
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,data);
+
+ // restore control register
+ // leave p_init negated
+ tmp = control | P_INIT;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// P3CSetScsiMode
+//
+// This routine sets the P3C into scsi mode. Now the parallel port can
+// be used to send commands the the n5380. This mode should be set only
+// briefly during when the scsi command is being executed.
+//
+VOID P3CSetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control)
+{
+ UCHAR tmp;
+
+ // save parallel data
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,data);
+
+ // zero data register
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0);
+
+ // save parallel control
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,control);
+ *control = *control & (P_BUFEN ^ 0xff);
+
+ // if in peripheral mode, get out to avoid glitch
+ tmp = *control | P_INIT;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // set ID pattern to data register
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0xfe);
+
+ // clear slc and init on control
+ tmp = tmp & ((P_SLC | P_INIT) ^0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // assert slc
+ tmp = tmp | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // clear all bits in control
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
+}
+
+//
+// P3CCheckAdapter
+//
+// This routine is used to sense the presense of the P3C adapter out
+// on the Parallel port. It will only detect the adapter if a device
+// is providing termination power.
+//
+BOOLEAN P3CCheckAdapter(PADAPTER_INFO g)
+{
+ BOOLEAN rval = FALSE;
+
+ if (g->ParallelPortType == PT_UNKNOWN) {
+ // do we have a bi-directional port?
+
+ if (P3CCheckAdapterBiDir(g)) {
+
+ // yes, bi-directional port with a p3c
+
+ g->ParallelPortType = PT_BI;
+ rval = TRUE;
+
+ } else {
+
+ // well, not bi-directional, but perhaps uni-directional?
+
+ if (P3CCheckAdapterUniDir(g)) {
+
+ // yes, uni-directional parallel port with P3C connected
+
+ g->ParallelPortType = PT_UNI;
+ rval = TRUE;
+ }
+ }
+ } else {
+ // we are to try the specific type given
+
+ if (g->ParallelPortType == PT_BI) {
+
+ // check only bi-directional
+
+ rval = P3CCheckAdapterBiDir(g);
+
+ } else {
+
+ if (g->ParallelPortType == PT_BI) {
+
+ // check only uni-directional
+
+ rval = P3CCheckAdapterUniDir(g);
+
+ } else {
+
+ // it is some other type we don't support
+
+ rval = FALSE;
+ }
+ }
+ }
+
+
+ return rval;
+}
+
+//
+// BOOLEAN P3CCheckAdapterUniDir(PADAPTER_INFO g)
+//
+// Checks for an adapter on a uni-directional parallel port.
+//
+BOOLEAN P3CCheckAdapterUniDir(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+ UCHAR tmp;
+ UCHAR sig0,sig1;
+ UCHAR sig_byte[3];
+ USHORT i;
+
+ // set scsi mode
+ P3CSetScsiMode(g,&data,&control);
+
+ // set read sig nibble mode
+ P3CPutControl(g,PCCC_MODE_RSIG_NIBBLE,0);
+
+ // zero data reg to get max contention during read signature
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0);
+
+ for (i=0;i<3;i++) {
+ // Assert SLC
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = (tmp & (P_BUFEN ^ 0xff)) | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // read in the status reg, it has the low nibble
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&sig0);
+
+ // Deassert SLC
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = (tmp & (P_BUFEN ^ 0xff)) & (P_SLC ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // note: there must be a delay here for timing
+
+ // Assert SLC
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = (tmp & (P_BUFEN ^ 0xff)) | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // read in the status reg, it has the high nibble
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&sig1);
+
+ // Deassert SLC
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp = (tmp & (P_BUFEN ^ 0xff)) & (P_SLC ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ sig_byte[i] = ((sig0 >> 3) & 0xf) | ((sig1 << 1) & 0xf0);
+ }
+
+ // set parallel port for use by printer
+
+ P3CSetPrinterMode(g,data,control);
+
+ // compare the signature bytes
+ if ((sig_byte[0] == 0x6c) && (sig_byte[1] == 0x55) &&
+ (sig_byte[2] == 0xaa)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//
+// BOOLEAN P3CCheckAdapterBiDir(PADAPTER_INFO g)
+//
+// Checks for an adapter on a bi-directional parallel port
+//
+//
+BOOLEAN P3CCheckAdapterBiDir(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+ UCHAR tmp;
+ UCHAR sig_byte[3];
+ USHORT i;
+
+ // set scsi mode
+ P3CSetScsiMode(g,&data,&control);
+
+ // set parallel port for BI-DIR if ps2
+ // NOTE: this is destructive to NCR machines
+ // also, I don't know details about how this wakes up the
+ // ps/2's, it was copied directly from the t348.asm code.
+
+#ifndef MACHINE_NCR
+ PortIOPut((PVOID)0x94,0x7f);
+ PortIOGet((PVOID)0x102,&tmp);
+ tmp = tmp & 0x7f;
+ PortIOPut((PVOID)0x102,tmp);
+ PortIOPut((PVOID)0x94,0xff);
+#endif
+
+ // set read sig byte mode
+
+ P3CPutControl(g,PCCC_MODE_RSIG_BYTE,0);
+
+ // control register used to ack bytes
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
+ tmp |= P_BUFEN;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ for (i=0;i<3;i++) {
+
+ // clock next byte in...
+ // Assert SLC
+ tmp = tmp | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // read in the byte
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,&sig_byte[i]);
+
+ // Deassert SLC
+ tmp &= (P_SLC ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // note: there must be a delay here for timing, C will provide it
+
+ // Assert SLC
+ tmp |= P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // now upper nibble is on status register
+
+ // Deassert SLC
+ tmp &= (P_SLC ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // ready to clock next byte in...
+ }
+
+ // set parallel port for use by printer
+
+ P3CSetPrinterMode(g,data,control);
+
+ // compare the signature bytes
+ if ((sig_byte[0] == 0x6c) && (sig_byte[1] == 0x55) &&
+ (sig_byte[2] == 0xaa)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//
+// P3CDoCommand
+//
+// Called by the main loop to start a scsi command. This functions is the
+// main entry point for all cards. It returns an SRB status code as defined
+// in ..\..\inc\srb.h. A status code of RET_STATUS_PENDING means that the
+// request has been sent to the controller and an interrupt is needed to
+// finish the request. When this interrupt occurs CardFinishCommandInterrupt
+// will be called.
+//
+USHORT P3CDoCommand(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ P3CSetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiDoCommand(t);
+
+ // put the parallel adapter back to parallel mode
+
+ P3CSetPrinterMode(g, data, control);
+ return rval;
+}
+
+//
+// P3CStartCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the P3C does not support interrupts on its own.
+//
+//
+USHORT P3CStartCommandInterrupt(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ P3CSetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiStartCommandInterrupt(t);
+
+ // put the parallel adapter back to parallel mode
+
+ P3CSetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// P3CFinishCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the P3C does not support interrupts on its own.
+//
+//
+USHORT P3CFinishCommandInterrupt(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ P3CSetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiFinishCommandInterrupt(t);
+
+ // put the parallel adapter back to parallel mode
+
+ P3CSetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// P3CInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the P3C does not support interrupts on its own.
+//
+BOOLEAN P3CInterrupt(PADAPTER_INFO g)
+{
+ BOOLEAN rval;
+ UCHAR data;
+ UCHAR control;
+
+ // put the parallel adapter into scsi mode
+
+ P3CSetScsiMode(g, &data, &control);
+
+ rval = N5380Interrupt(g);
+
+ // put the parallel adapter back to parallel mode
+
+ P3CSetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// P3CResetBus
+//
+// Resets the SCSI Bus
+//
+VOID P3CResetBus(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+
+ // put the parallel adapter into scsi mode
+
+ P3CSetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ N5380ResetBus(g);
+
+ // put the parallel adapter back to parallel mode
+
+ P3CSetPrinterMode(g, data, control);
+}
+
+//
+// P3CWriteBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiWriteBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+USHORT P3CWriteBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+ UCHAR control;
+ UCHAR tmp;
+
+ // use slow mode for odd xfers (inquiry type commands) and audio
+ if (len % 512) {
+ return ScsiWriteBytesSlow(g, pbytes, len,
+ pActualLen, phase);
+ }
+
+ // enable dma on 5380
+ N5380EnableDmaWrite(g);
+
+ // put the P3C into write dma mode
+ P3CPutControl(g,PCCC_MODE_WDMA,0);
+
+ // start control reg off zero'ed, enable dma write mode
+ control = 0;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
+
+ {
+ ULONG xfer_count = len;
+ UCHAR control;
+ PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
+
+ control = 0;
+ _asm {
+ push esi
+ push ds
+#ifdef MODE_32BIT
+ mov edx,baseIoAddress
+ mov esi,pbytes
+ mov ecx,len
+#else
+ mov dx, word ptr baseIoAddress
+ mov si, word ptr pbytes
+ mov cx, word ptr len
+ mov ds, word ptr pbytes+2
+#endif // MODE_32BIT
+ mov bl,control // mask for control reg
+ mov bh,P_AFX // strobe mask
+ add dx,2 // dx points to control reg
+ get_bytes:
+ dec dx // dx points to status register
+ in al,dx
+ test al,P_BUSY
+ jz big_wait
+ ready:
+ dec dx // dx points to parallel data reg
+ mov al,[esi]
+ out dx,al
+
+ add dx,2 // dx points to control reg
+ xor bl,bh
+ mov al,bl
+ out dx,al // give strobe, clock next data byte
+
+ inc esi
+ dec ecx
+ jnz get_bytes
+ }
+ goto done_asm;
+ _asm {
+big_wait:
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ // wait for a while before going to a bigger timeout
+ push ecx
+ push ebx
+ mov ebx,TIMEOUT_READWRITE_LOOP
+ loop0:
+ mov ecx,0x10000
+ loop1:
+ in al,dx
+ test al,P_BUSY
+ jnz ready1
+ in al,dx
+ test al,P_BUSY
+ jnz ready1
+ dec ecx
+ jnz loop1
+ dec ebx
+ jnz loop0
+ pop ebx
+ pop ecx
+ jmp short error
+ ready1:
+ pop ebx
+ pop ecx
+ jmp short ready
+ error:
+ mov rval,RET_STATUS_TIMEOUT
+ done_asm:
+ pop ds
+ pop esi
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ }
+
+ // compute actual xfer len
+
+ *pActualLen = len - xfer_count;
+ }
+
+ // clear the dma mode of 5380
+ N5380DisableDmaWrite(g);
+
+ // if data underrun, return the under/over run error message
+
+ if (rval) {
+
+ // phase mismatch means data under/over run
+
+ N5380GetPhase(g,&tmp);
+
+ if (tmp == PHASE_STATUS) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ }
+ }
+
+ return rval;
+}
+
+//
+// P3CReadBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiReadBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+#pragma optimize("",off)
+USHORT P3CReadBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // use slow mode for odd xfers (inquiry type commands) and audio
+ if (len % 512) {
+ return ScsiReadBytesSlow(g, pbytes, len,
+ pActualLen, phase);
+ }
+
+ N5380EnableDmaRead(g);
+
+ // call the correct read fast routine based on the type of port
+
+ if (g->ParallelPortType == PT_BI) {
+ rval = P3CReadBytesFastBiDir(g, pbytes, len,
+ pActualLen, phase);
+ } else {
+ rval = P3CReadBytesFastUniDir(g, pbytes, len,
+ pActualLen, phase);
+ }
+
+ // clear the dma mode
+ N5380DisableDmaRead(g);
+
+ // if data underrun, return the under/over run error message
+
+ if (rval) {
+ UCHAR tmp;
+
+ // phase mismatch means data under/over run
+
+ N5380GetPhase(g,&tmp);
+
+ if (tmp == PHASE_STATUS) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ }
+ }
+
+ return rval;
+}
+
+//
+// USHORT P3CReadBytesFastBiDir(PADAPTER_INFO g, PUCHAR pbytes,
+//
+// Reads bytes fast on a bi-directional parallel port.
+//
+USHORT P3CReadBytesFastBiDir(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // put the P3C into read dma mode
+
+ P3CPutControl(g,PCCC_MODE_RDMA_BYTE,0);
+
+ // start control reg with P_SLC and P_BUFEN
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,P_SLC | P_BUFEN);
+
+ // for inline assembly, we don't have to save eax-edx registers
+ {
+ ULONG xfer_count = len;
+ UCHAR control;
+ PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
+
+ // keep track of control register
+ control = P_SLC | P_BUFEN;
+
+ _asm {
+ push esi
+ push ds
+#ifdef MODE_32BIT
+ mov edx,baseIoAddress
+ mov esi,pbytes
+ mov ecx,len
+#else
+ mov dx, word ptr baseIoAddress
+ mov si, word ptr pbytes
+ mov cx, word ptr len
+ mov ds, word ptr pbytes+2
+#endif // MODE_32BIT
+ mov bl,control // mask for control reg
+ mov bh,P_AFX // strobe mask
+ add dx,2 // dx points to control register
+ get_bytes:
+ dec dx // dx points to status register
+ in al,dx
+ test al,P_BUSY
+ jz big_wait
+
+ ready:
+ dec dx // dx points to data register
+
+ // get next byte
+ in al,dx
+ mov [esi],al
+
+ // toggle strobe and select high nibble
+ add dx,2 // dx points to control register
+ xor bl,bh
+ mov al,bl
+ out dx,al // strobe to ack byte
+
+ // loop
+ inc esi
+ dec ecx
+ jnz get_bytes
+ }
+ goto done_asm;
+ _asm {
+big_wait:
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ // wait for a while before going to a bigger timeout
+ push ecx
+ push ebx
+ mov ebx,TIMEOUT_READWRITE_LOOP
+ loop0:
+ mov ecx,0x10000
+ loop1:
+ in al,dx
+ test al,P_BUSY
+ jnz ready1
+ in al,dx
+ test al,P_BUSY
+ jnz ready1
+
+ dec ecx
+ jnz loop1
+ dec ebx
+ jnz loop0
+ pop ebx
+ pop ecx
+ jmp short error
+ ready1:
+ pop ebx
+ pop ecx
+ }
+ goto ready;
+ _asm {
+ error:
+ mov rval,RET_STATUS_TIMEOUT
+ done_asm:
+ pop ds
+ pop esi
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ }
+
+ // compute actual xfer len
+
+ *pActualLen = len - xfer_count;
+ }
+
+ // zero control register, disable read dma mode
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
+
+ return rval;
+}
+
+//
+// USHORT P3CReadBytesFastUniDir(PADAPTER_INFO g, PUCHAR pbytes,
+//
+// Reads bytes fast on a uni-directional parallel port.
+//
+USHORT P3CReadBytesFastUniDir(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+ UCHAR data;
+
+ // put the P3C into read dma mode
+ P3CPutControl(g,PCCC_MODE_RDMA_NIBBLE,0);
+
+ // start data reg to select high nibble
+ data = 0x80;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,data);
+ data = 0;
+
+ // start control reg with P_SLC
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,P_SLC);
+
+ // for inline assembly, we don't have to save eax-edx registers
+ {
+ ULONG xfer_count = len;
+ PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
+
+ _asm {
+ push esi
+ push ds
+#ifdef MODE_32BIT
+ mov edx,baseIoAddress
+ mov esi,pbytes
+ mov ecx,len
+#else
+ mov dx, word ptr baseIoAddress
+ mov si, word ptr pbytes
+ mov cx, word ptr len
+ mov ds, word ptr pbytes+2
+#endif // MODE_32BIT
+ mov bl,data
+ get_bytes:
+ inc dx // dx points to status register
+ in al,dx
+ test al,P_BUSY
+ jz big_wait
+
+ // save the high nibble
+ ready:
+ mov ah,al
+
+ // select lower nibble
+ dec dx // dx points to data register
+ mov al,bl
+ out dx,al
+
+ // calculate high nibble
+ shl ah,1
+ and ah,0f0h
+
+ // get lower nibble
+ inc dx // dx points to status register
+ in al,dx
+ mov bh,al
+
+ // toggle strobe and select high nibble
+ dec dx // dx points to data register
+ xor bl,0x40
+ mov al,bl
+ or al,80h
+ out dx,al
+
+//
+// We need some delay here for the t348 to respond to the strobe
+// and lower the p_busy line. This loop serves the purpose and
+// allows us to break out early in some cases. I have tried this
+// with cx = 1 and this is not enough time. cx = 2 is enough, but
+// for faster 486's or 586's this may need to be boosted higher.
+//
+// Note: the jmp $+2 that has been in our 348 code for DOS runs
+// significantly faster on the 486, and out instructions are also
+// much faster in protected mode! This totally threw off the timing
+// of our DOS code.
+// -KJB
+//
+#if 0
+ push cx
+ mov cx,100
+ inc dx // dx points to status register
+loop1:
+ in al,dx
+ test al,P_BUSY
+ jz out1
+ dec cx
+ jnz loop1
+out1:
+ pop cx
+ dec dx // dx points to data register
+#endif
+
+ // compute low nibble and the whole byte
+ shr bh,1
+ shr bh,1
+ shr bh,1
+ and bh,0fh
+ or ah,bh
+ mov al,ah
+
+
+ // store data and loop
+ mov [esi],al
+ inc esi
+ dec ecx
+ jnz get_bytes
+ }
+ goto done_asm;
+ _asm {
+big_wait:
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ in al,dx
+ test al,P_BUSY
+ jnz ready
+
+ // wait for a while before going to a bigger timeout
+ push ecx
+ push ebx
+ mov ebx,TIMEOUT_READWRITE_LOOP
+ loop0:
+ mov ecx,0x10000
+ loop1:
+ in al,dx
+ test al,P_BUSY
+ jnz ready1
+ in al,dx
+ test al,P_BUSY
+ jnz ready1
+
+ dec ecx
+ jnz loop1
+ dec ebx
+ jnz loop0
+ pop ebx
+ pop ecx
+ jmp short error
+ ready1:
+ pop ebx
+ pop ecx
+ }
+ goto ready;
+ _asm {
+ error:
+ mov rval,RET_STATUS_TIMEOUT
+ done_asm:
+ pop ds
+ pop esi
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ }
+
+ // compute actual xfer len
+
+ *pActualLen = len - xfer_count;
+ }
+
+ // zero control register, disable read dma mode
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
+
+ return rval;
+}
+#pragma optimize("",on)
+
+//
+// N5380PortPut
+//
+// This routine is used by the N5380.C module to write byte to a 5380
+// controller. This allows the module to be card independent. Other
+// modules that assume a N5380 may also use this function.
+//
+VOID N5380PortPut(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
+{
+
+ P3CPutControl(g,PCCC_MODE_WPER,reg);
+
+ // write the byte
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,byte);
+
+ // toggle the data_ready line
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,P_SLC);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
+}
+
+//
+// N5380PortGet
+//
+// This routine is used by the N5380.C module to get a byte from a 5380
+// controller. This allows the module to be card independent. Other
+// modules that assume a N5380 may also use this function.
+//
+VOID N5380PortGet(PADAPTER_INFO g,UCHAR reg,PUCHAR byte)
+{
+ UCHAR tmp,tmp1;
+
+ P3CPutControl(g,PCCC_MODE_RPER_NIBBLE,reg);
+
+ // assert slc
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,P_SLC);
+
+ // select high nibble
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x80);
+
+ // read high nibble
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp);
+
+ // compute high nibble
+ tmp = (tmp << 1) & 0xf0;
+
+ // select low nibble
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x00);
+
+ // read low nibble
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp1);
+
+ // compute low nibble
+ tmp1 = (tmp1 >> 3) & 0x0f;
+
+ // compute and return byte
+ *byte = tmp1 | tmp;
+
+ // clear slc
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
+}
diff --git a/private/ntos/miniport/trantor/source/parallel.c b/private/ntos/miniport/trantor/source/parallel.c
new file mode 100644
index 000000000..f88c8ad2e
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/parallel.c
@@ -0,0 +1,86 @@
+#ifdef i386
+//--------------------------------------------------------------------
+//
+// PARALLEL.C
+//
+// Parallel port access file.
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+//--------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+//
+// ParallelWaitBusy
+//
+// This routine waits until the busy line is 1.
+//
+
+USHORT ParallelWaitBusy (PBASE_REGISTER baseIoAddress, ULONG usec, PUCHAR data)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ ParallelPortGet (baseIoAddress, PARALLEL_STATUS, data);
+ if (*data & P_BUSY) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < usec; i++) {
+ ParallelPortGet (baseIoAddress, PARALLEL_STATUS, data);
+ if (*data & P_BUSY) {
+ return 0;
+ }
+ ScsiPortStallExecution (1);
+ }
+
+ // return with an error, non-zero indicates timeout
+
+ return RET_STATUS_TIMEOUT;
+}
+
+
+//
+// ParallelWaitNoBusy
+//
+// This routine waits until the busy line is 0.
+//
+
+USHORT ParallelWaitNoBusy (PBASE_REGISTER baseIoAddress, ULONG usec, PUCHAR data)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+ ParallelPortGet (baseIoAddress, PARALLEL_STATUS, data);
+ if (!(*data & P_BUSY)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < usec; i++) {
+ ParallelPortGet (baseIoAddress, PARALLEL_STATUS, data);
+ if (!(*data & P_BUSY)) {
+ return 0;
+ }
+ ScsiPortStallExecution (1);
+ }
+
+ // return with an error, non-zero indicates timeout
+
+ return RET_STATUS_TIMEOUT;
+}
+
+
+#endif
diff --git a/private/ntos/miniport/trantor/source/pc9010.c b/private/ntos/miniport/trantor/source/pc9010.c
new file mode 100644
index 000000000..85fc41a0e
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/pc9010.c
@@ -0,0 +1,851 @@
+//---------------------------------------------------------------------
+//
+// File: PC9010.C
+//
+// PC9010 access file.
+//
+// These routines are independent of the card the PC9010 is on. The
+// cardxxxx.h file must define the following routines:
+//
+// PC9010PortPut
+// PC9010PortGet
+// PC9010PortSet
+// PC9010PortClear
+// PC9010PortTest
+//
+// PC9010PortGetWord
+// PC9010PortGetBufferWord
+// PC9010PortPutWord
+// PC9010PortPutBufferWord
+//
+// These routines could be defined by some other include file instead of
+// cardxxxx.h, as the pc9010 defines the needed N5380xxxxxxxx routines.
+//
+// NOTES:
+// 8 bit mode is not supported now.
+// When data overrun occurs, the wrong number of bytes sent is returned
+// this occurs only during writes to a scsi device and the device
+// does not accept all bytes sent. The fifo of the pc9010 fills
+// and we don't know how many of the bytes have been transfered
+// across the bus...
+//
+// Revisions:
+// 02-24-92 KJB First, does not support 8 bit mode, since we will
+// not be shipping any 8 bit adapters!
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-11-92 KJB Changed to use new N5380.H names.
+// 03-26-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
+// 05-17-93 KJB Fixed warning message.
+//
+//---------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+
+// switch setting on PC9010 for 16 bit transfers
+// warning specific to T160 right now...
+
+#define TRANSFER_MODE_16BIT 0x2
+
+//
+// Local Routines
+//
+USHORT PC9010ReadBytes8Bit(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen);
+USHORT PC9010ReadBytes16Bit(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen);
+USHORT PC9010WriteBytes8Bit(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen);
+USHORT PC9010WriteBytes16Bit(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen);
+VOID PC9010FifoDataTransferSetup(PADAPTER_INFO g,
+ BOOLEAN *mode_16bit);
+USHORT PC9010WaitTillFifoReady(PADAPTER_INFO g,
+ BOOLEAN (*ReadyRoutine)(PADAPTER_INFO g) );
+BOOLEAN PC9010Read16ReadyRoutine(PADAPTER_INFO g);
+BOOLEAN PC9010Write16ReadyRoutine(PADAPTER_INFO g);
+BOOLEAN PC9010FifoEmptyRoutine(PADAPTER_INFO g);
+
+
+//
+// Redefined Routines
+//
+
+#define PC9010WaitTillFifoEmpty(g) \
+ PC9010WaitTillFifoReady(g, PC9010FifoEmptyRoutine);
+
+//
+// PC9010CheckAdapter
+//
+// This routine checks for the presense of a pc9010.
+//
+
+BOOLEAN PC9010CheckAdapter (PADAPTER_INFO g)
+{
+ UCHAR tmp;
+
+ // try to clear the config bit of the control register
+
+ PC9010PortClear (g, PC9010_CONTROL, CTR_CONFIG);
+
+ if (PC9010PortTest (g, PC9010_CONTROL, CTR_CONFIG)) {
+ goto not_pc9010;
+ }
+
+ // try to set the config bit of the control register
+
+ PC9010PortSet (g, PC9010_CONTROL, CTR_CONFIG);
+
+ if (!PC9010PortTest (g, PC9010_CONTROL, CTR_CONFIG)) {
+ goto not_pc9010;
+ }
+
+ // the config bit is set, now read the configuration info
+
+ PC9010PortGet (g, PC9010_CONFIG, &tmp);
+
+ if (tmp != PC9010_JEDEC_ID) {
+ goto not_pc9010;
+ }
+
+ // this next byte sould be # of continuation chars, = 0
+
+ PC9010PortGet (g, PC9010_CONFIG, &tmp);
+
+ if (tmp) {
+ goto not_pc9010;
+ }
+
+ // now we will assume we have a pc9010
+
+ // initialize registers to 0
+
+ PC9010PortPut (g, PC9010_CONTROL, 0);
+ N5380PortPut (g, N5380_INITIATOR_COMMAND, 0);
+ N5380PortPut (g, N5380_MODE, 0);
+
+ return TRUE;
+
+not_pc9010:
+
+ // the pc9010 was not found
+
+ return FALSE;
+}
+
+
+//
+// PC9010WaitTillFifoReady
+//
+// Waits until fifo is ready to transfer something, checks for phase
+// change and will timeout.
+//
+// The procedural parameter, ReadyRoutine, allows this routine to
+// function for all modes: read, write, 16 and 8 bit modes.
+//
+
+USHORT PC9010WaitTillFifoReady (PADAPTER_INFO g,
+ BOOLEAN (*ReadyRoutine)(PADAPTER_INFO g))
+{
+ ULONG i;
+ USHORT rval = 0;
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+
+ // is the fifo ready?
+
+ if ((*ReadyRoutine)(g)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < TIMEOUT_REQUEST; i++) {
+
+ // is the fifo ready?
+
+ if ((*ReadyRoutine)(g)) {
+ return 0;
+ }
+
+ // check for phase mismatch
+
+ // disable the fifo, temporarily
+
+ PC9010PortClear (g, PC9010_CONTROL, CTR_FEN);
+
+ // note: the PC9010 will take 3 machine clocks to recognize this,
+ // the C code will provide these with no problem!
+
+ while (PC9010PortTest (g, PC9010_CONTROL, CTR_FEN));
+
+ // check for request and phase mismatch
+
+ if (N5380PortTest (g, N5380_CURRENT_STATUS, CS_REQ) &&
+ !N5380PortTest (g, N5380_DMA_STATUS, DS_PHASE_MATCH)) {
+
+ // phase mismatch, means data under/overrun
+
+ rval = RET_STATUS_DATA_OVERRUN;
+ DebugPrint((DEBUG_LEVEL,"Error - 0 - PC9010WaitTillFifoReady\n"));
+ goto error;
+ }
+
+ // re-enable the fifo
+
+ PC9010PortSet (g, PC9010_CONTROL, CTR_FEN);
+
+ ScsiPortStallExecution (1);
+ }
+
+ rval = RET_STATUS_TIMEOUT;
+
+error:
+ DebugPrint((DEBUG_LEVEL,"Error - 1 - PC9010WaitTillFifoReady\n"));
+
+ // return with an error
+
+ return rval;
+}
+
+
+#if 0
+// We can use the other routine
+
+//
+// PC9010WaitTillFifoEmpty
+//
+// Waits until fifo is empty to transfer something.
+//
+USHORT PC9010WaitTillFifoEmpty (PADAPTER_INFO g)
+{
+ ULONG i;
+ USHORT rval = 0;
+ UCHAR tmp;
+
+ // see if the flag comes back quickly
+
+ for (i = 0; i < TIMEOUT_QUICK; i++) {
+
+ // is the fifo empty?
+
+ if (PC9010PortTest (g, PC9010_FIFO_STATUS, FSR_FEMP)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+
+ for (i = 0; i < TIMEOUT_REQUEST; i++) {
+
+ // is the fifo empty?
+
+ if (PC9010PortTest (g, PC9010_FIFO_STATUS, FSR_FEMP)) {
+ return 0;
+ }
+
+ ScsiPortStallExecution (1);
+ }
+
+ rval = RET_STATUS_TIMEOUT;
+
+error:
+ DebugPrint((DEBUG_LEVEL,"Error - 1 - PC9010WaitTillFifoEmpty\n"));
+
+ // return with an error
+
+ return rval;
+}
+#endif
+
+
+//
+// PC9010FifoEmptyRoutine
+//
+// Check to see if the fifo is ready to read 16 bits.
+//
+
+BOOLEAN PC9010FifoEmptyRoutine (PADAPTER_INFO g)
+{
+ // if both lanes of fifo are not empty then return true
+
+ return (PC9010PortTest (g, PC9010_FIFO_STATUS, FSR_FEMP));
+}
+
+
+//
+// PC9010Read16ReadyRoutine
+//
+// Check to see if the fifo is ready to read 16 bits.
+//
+
+BOOLEAN PC9010Read16ReadyRoutine (PADAPTER_INFO g)
+{
+ // if both lanes of fifo are not empty then return true
+
+ return (!PC9010PortTest (g, PC9010_FIFO_STATUS,
+ FSR_FLEMP | FSR_FHEMP));
+}
+
+//
+// PC9010FifoDataTransferSetup
+//
+// Setup the PC9010 chip for data transfer, either read or write.
+//
+
+VOID PC9010FifoDataTransferSetup (PADAPTER_INFO g,
+ BOOLEAN *mode_16bit)
+{
+ USHORT rval = 0;
+ UCHAR tmp;
+
+ // disable the fifo
+
+ PC9010PortClear (g, PC9010_CONTROL, CTR_FEN);
+
+ // reset the fifo
+
+ PC9010PortSet (g, PC9010_CONTROL, CTR_FRST);
+
+ // clear reset, config, swsel, dir , selecting low switch bank
+
+ PC9010PortClear (g, PC9010_CONTROL,
+ CTR_FRST | CTR_CONFIG | CTR_SWSEL | CTR_FDIR);
+
+ // check for 16 bit mode, switch 2 = 0
+ // note: this is specific to a trantor card: the t160...
+
+ PC9010PortGet (g, PC9010_CONFIG, &tmp);
+ *mode_16bit = !(tmp & TRANSFER_MODE_16BIT);
+
+ // set the 16 bit mode or 8 bit for the fifo
+
+ if (*mode_16bit) {
+ PC9010PortSet (g, PC9010_CONTROL, CTR_F16);
+ }
+ else {
+ PC9010PortClear (g, PC9010_CONTROL, CTR_F16);
+ }
+}
+
+
+//
+// PC9010ReadBytes8Bit
+//
+// Reads bytes for the PC9010 in 8 bit mode.
+//
+
+USHORT PC9010ReadBytes8Bit (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen)
+{
+ return RET_STATUS_ERROR;
+}
+
+
+//
+// PC9010ReadBytes16Bit
+//
+// Reads bytes for the PC9010 in 16 bit mode.
+//
+
+USHORT PC9010ReadBytes16Bit (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen)
+{
+ PUCHAR pBuffer = pbytes;
+ PUCHAR pBufferEnd = &pBuffer[len];
+ USHORT rval = 0;
+ USHORT tmpw;
+
+ // 16 bit read loop
+
+ while (pBuffer != pBufferEnd) {
+
+ // can we do a big transfer?
+
+ if (PC9010PortTest (g, PC9010_FIFO_STATUS, FSR_FFUL)) {
+
+ PC9010PortGetBufferWord (g, PC9010_FIFO, pBuffer, 64);
+ pBuffer += 128;
+
+ }
+ else {
+
+ // is either fifo lane empty
+
+ if (PC9010PortTest (g, PC9010_FIFO_STATUS,
+ FSR_FLEMP | FSR_FHEMP)) {
+
+ // At least one half of the FIFO is empty. While waiting to
+ // read more data, monitor the 5380 to check for SCSI bus phase
+ // change (data underrun) or other errors.
+
+ // NOTE: The lo half of the FIFO may contain data. If we're only
+ // waiting for one more byte, transfer it immediately and exit.
+ // If the FIFO is completely empty (if low FIFO empty, high FIFO
+ // is also empty, since data goes into low FIFO first), or we're
+ // waiting for more than 1 additional byte then it's necessary to
+ // check for SCSI errors.
+
+ if (!PC9010PortTest (g, PC9010_FIFO_STATUS,
+ FSR_FLEMP) && pBuffer == pBufferEnd-1) {
+
+ // the low lane has a byte, and it is the last byte of
+ // the transfer
+
+ // read a word and discard the high byte
+
+ PC9010PortGetWord (g, PC9010_FIFO, &tmpw);
+ *pBuffer = (UCHAR)tmpw;
+ pBuffer += 1;
+
+ }
+ else {
+
+ // could be a byte in fifo, but
+ // there are no words in the fifo, possible
+ // phase change, or we have to wait
+
+ if (rval = PC9010WaitTillFifoReady(g,
+ PC9010Read16ReadyRoutine)) {
+
+ // there has been a phase change, or timeout
+
+ if (rval == RET_STATUS_TIMEOUT) {
+
+ // for timeouts, just exit...
+
+ goto done_error;
+ }
+
+ // phase change, transfer any data remaining in fifo
+
+ // is either fifo lane empty?
+ if (PC9010PortTest (g, PC9010_FIFO_STATUS,
+ FSR_FLEMP | FSR_FHEMP)) {
+
+ // is the low lane empty?
+
+ if (PC9010PortTest (g, PC9010_FIFO_STATUS,
+ FSR_FLEMP)) {
+
+ // low lane is empty, all bytes have been xferred
+
+ goto done_error;
+ }
+
+ // one byte remaining in low lane, transfer it
+ // read a word and discard the high byte
+
+ PC9010PortGetWord (g, PC9010_FIFO, &tmpw);
+ *pBuffer = (UCHAR)tmpw;
+ pBuffer +=1;
+
+ // that was the last byte ever, exit
+ goto done_error;
+ }
+
+ // there is at least a word in the fifo, fall through,
+ // we will get this phase error again later when
+ // all words have been transferred.
+
+ }
+ }
+ }
+ else {
+
+ // both lanes have at least one byte
+
+ PC9010PortGetWord (g, PC9010_FIFO, pBuffer);
+ pBuffer +=2;
+
+ }
+ }
+ }
+
+done_error:
+
+ // if all bytes have been transferred and a phase change occured,
+ // then there was no over/underrun at all
+
+ if (rval == RET_STATUS_DATA_OVERRUN) {
+ if (pBuffer == pBufferEnd) {
+
+ // all bytes were transferred, no error
+
+ rval = 0;
+ }
+ }
+
+ // store the transfer len
+
+ *pActualLen = pBuffer - pbytes;
+
+ return rval;
+}
+
+
+//
+// PC9010WriteBytes8Bit
+//
+// Writes bytes for the PC9010 in 8 bit mode.
+//
+
+USHORT PC9010WriteBytes8Bit (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen)
+{
+ return RET_STATUS_ERROR;
+}
+
+
+//
+// PC9010WriteBytes16Bit
+//
+// Writes bytes for the PC9010 in 16 bit mode.
+// The len must be an even number of bytes...
+//
+USHORT PC9010WriteBytes16Bit (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen)
+{
+ PUCHAR pBuffer = pbytes;
+ PUCHAR pBufferEnd = &pBuffer[len];
+ USHORT rval = 0;
+
+ // 16 bit read loop
+
+ while (pBuffer != pBufferEnd) {
+
+ // can we do a big transfer?
+
+ if (PC9010PortTest (g, PC9010_FIFO_STATUS, FSR_FEMP)) {
+
+ ULONG count;
+
+ // The FIFO is empty. Fill the FIFO in one burst.
+ //
+ // Transfer the lesser of the fifo size or the remaining number
+ // of bytes.
+ //
+ // Since we're doing word transfers we need to be careful if the
+ // number of remaining bytes is odd and less than the FIFO size.
+ // We handle this by bursting only an even number of bytes. If
+ // there is an odd balance remaining we pick it up later.
+
+ count = pBufferEnd-pBuffer;
+
+ if (count >= PC9010_FIFO_SIZE) {
+
+ // we have at least FIFO_SIZE bytes to send, fill the fifo
+
+ PC9010PortPutBufferWord(g, PC9010_FIFO,
+ pBuffer, 64);
+ pBuffer += PC9010_FIFO_SIZE;
+
+ }
+ else {
+
+ // write only the number of words we have
+ // if we have only one byte, we will get that later
+
+ PC9010PortPutBufferWord (g, PC9010_FIFO,
+ pBuffer, count/2);
+ pBuffer += count;
+ }
+ }
+ else {
+
+ // is either fifo lane full?
+
+ if (!PC9010PortTest (g, PC9010_FIFO_STATUS,
+ FSR_FLFUL | FSR_FHFUL)) {
+
+ // neither lane is full, we can write a word...
+
+ PC9010PortPutWord (g, PC9010_FIFO,
+ *(PUSHORT)pBuffer);
+ pBuffer += 2;
+
+ }
+ else {
+
+ // at least one of the fifo lanes is full, wait until ready
+ // checking for phase mismatch or timeout
+
+ if (rval = PC9010WaitTillFifoReady (g,
+ PC9010Write16ReadyRoutine)) {
+
+ // there has been a phase change, or timeout
+ // just exit...
+
+ goto done_error;
+ }
+ }
+ }
+ }
+
+ // If there has been no error, wait for the FIFO to empty.
+ //
+ // NOTE: The way this is currently coded, a SCSI error could occur
+ // after the last byte is written to the FIFO but before the last
+ // byte is written from the FIFO to the 5380, causing the code to
+ // hang. To solve this problem the 5380 should probably be set for
+ // interrupting on phase change and on loss of BSY. Then, code
+ // can wait for one of those events, the FIFO to empty, or a
+ // time-out. -RCB
+
+ rval = PC9010WaitTillFifoEmpty (g);
+
+done_error:
+
+ // store the transfer len
+
+ *pActualLen = pBuffer - pbytes;
+
+ return rval;
+}
+
+
+//
+// PC9010Write16ReadyRoutine
+//
+// Check to see if the fifo is ready to read 16 bits.
+//
+BOOLEAN PC9010Write16ReadyRoutine (PADAPTER_INFO g)
+{
+ // if both lanes of fifo are not full then return true
+
+ return (!PC9010PortTest (g, PC9010_FIFO_STATUS,
+ FSR_FLFUL | FSR_FHFUL));
+}
+
+
+//
+// PC9010ReadBytesFast
+//
+// Read the bytes from a nPC9010 as fast as possible.
+//
+
+USHORT PC9010ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+ BOOLEAN mode_16bit;
+
+ // TEST CODE!!! to throw off the byte count!!
+// rval = ScsiReadBytesSlow(g,pbytes,1,pActualLen,phase);
+// pbytes++;
+// len--;
+
+ // prepare the PC9010 for data transfer
+
+ PC9010FifoDataTransferSetup(g,&mode_16bit);
+
+ // start internal 5380 for data transfer
+
+ N5380EnableDmaRead (g);
+
+ // enable our fifo now
+
+ PC9010PortSet (g,PC9010_CONTROL,CTR_FEN);
+
+ //-----------------------------------------------------------------------
+ // READ LOOP
+ //
+ // NOTE: In both 8-bit and 16-bit read loops we tacitly assume
+ // that the target will never try to send more bytes than we
+ // have requested. In other words, if there are bytes in the
+ // FIFO, in some conditions we'll transfer the bytes without
+ // checking whether or not the host has actually requested that
+ // many bytes.
+ //
+ //-----------------------------------------------------------------------
+
+ // If the transfer length is longer than the FIFO is deep and
+ // is less than or equal to 2048 bytes, wait briefly for the
+ // FIFO to fill. This behavior is designed to optimize the
+ // performance of short transfers where "byte banging" the
+ // FIFO actually leads to lower performance than waiting for
+ // a burst. If the transfer length is outside this range, or
+ // if the FIFO doesn't fill quickly, go ahead with the transfer
+ // immediately.
+ //
+ // THE REASONING:
+ //
+ // Transfers shorter than the FIFO depth could never fill the
+ // FIFO, so there is no sense waiting for FIFO full.
+ //
+ // On the other end of the range, "byte-banging" typically
+ // occurs for no more than one depth of the FIFO (128 bytes).
+ // So, the time to "byte-bang" 128 bytes starts to become a
+ // very small fraction of the overall transfer time when 2048
+ // bytes (one CD-ROM sector) or more are transferred.
+ //
+ // How long is a brief wait? If we poll the FIFO flags 128
+ // times (one FIFO depth) and the FIFO is still not full, then
+ // the SCSI device is clearly slower than we are. In this case
+ // we might as well start "byte-banging". Fast SCSI devices
+ // will easily fill the FIFO in the time it takes to poll the
+ // FIFO flags that many times.
+
+ if (len > PC9010_FIFO_SIZE && len < 2048) {
+ ULONG i;
+
+ // loop for a while, waiting for fifo to fill
+
+ for (i = 0; i < PC9010_FIFO_SIZE; i++) {
+ if (PC9010PortTest (g, PC9010_FIFO_STATUS, FSR_FFUL)) {
+ break;
+ }
+ }
+ }
+
+ if (mode_16bit) {
+ rval = PC9010ReadBytes16Bit (g, pbytes, len, pActualLen);
+ } else {
+ rval = PC9010ReadBytes8Bit (g, pbytes, len, pActualLen);
+ }
+
+ // disable our fifo, wait for it to register as disabled
+
+ PC9010PortClear (g, PC9010_CONTROL, CTR_FEN);
+ while (PC9010PortTest (g, PC9010_CONTROL, CTR_FEN));
+
+ // disable 5380 dma
+
+ N5380DisableDmaRead (g);
+
+ return rval;
+}
+
+
+//
+// PC9010WriteBytesFast
+//
+// Write the bytes from a nPC9010 as fast as possible.
+//
+
+USHORT PC9010WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+ BOOLEAN mode_16bit;
+ ULONG bytes_left = 0;
+
+ // TEST CODE!!! to throw off the byte count!!
+// rval = ScsiWriteBytesSlow(g,pbytes,1,pActualLen,phase);
+// pbytes++;
+// len--;
+
+ // prepare the PC9010 for data transfer
+
+ PC9010FifoDataTransferSetup (g, &mode_16bit);
+
+ // start internal 5380 for data transfer
+
+ N5380EnableDmaWrite (g);
+
+ // enable our fifo now, setting direction flag
+
+ PC9010PortSet (g, PC9010_CONTROL, CTR_FEN | CTR_FDIR);
+
+ if (mode_16bit) {
+
+ // transfer only an even number of bytes
+ // transfer the odd byte later
+
+ bytes_left = len&1;
+ rval = PC9010WriteBytes16Bit (g, pbytes,
+ len-bytes_left, pActualLen);
+
+ }
+ else {
+
+ rval = PC9010WriteBytes8Bit (g, pbytes, len, pActualLen);
+ }
+
+ // disable our fifo, wait for it to register as disabled
+
+ PC9010PortClear (g, PC9010_CONTROL, CTR_FEN);
+ while (PC9010PortTest (g, PC9010_CONTROL, CTR_FEN));
+
+ // disable 5380 dma
+
+ N5380DisableDmaWrite (g);
+
+ // do we have to transfer one byte?
+
+ if (!rval && bytes_left) {
+ ULONG tmp_len;
+
+ rval = ScsiWriteBytesSlow (g, &pbytes[len-1],
+ bytes_left, &tmp_len, phase);
+
+ *pActualLen += tmp_len;
+ }
+
+ return rval;
+}
+
+
+//
+// PC9010DisableInterrupt
+//
+// Disable interrupts on the PC9010
+//
+
+VOID PC9010DisableInterrupt (PADAPTER_INFO g)
+{
+
+ // disable the interrupt on the 5380
+
+ N5380DisableInterrupt (g);
+
+ // disable interrupt in the PC9010 for 5380 ints
+
+ PC9010PortClear (g, PC9010_CONTROL, CTR_IRQEN);
+}
+
+
+//
+// PC9010EnableInterrupt
+//
+// Enable interrupts from the PC9010
+//
+
+VOID PC9010EnableInterrupt (PADAPTER_INFO g)
+{
+
+ // set the dma bit of 5380 so we can get phase mismatch ints
+
+ N5380EnableInterrupt (g);
+
+ // enable interrupt in the PC9010
+
+ PC9010PortPut (g, PC9010_CONTROL, CTR_IRQEN);
+}
+
+
+//
+// PC9010ResetBus
+//
+// Reset the SCSI bus
+//
+
+VOID PC9010ResetBus (PADAPTER_INFO g)
+{
+ // reset the PC9010
+
+ PC9010PortPut (g, PC9010_CONTROL, CTR_FRST);
+
+ // disable interrupts
+
+ PC9010DisableInterrupt (g);
+
+ // reset the scsi bus
+
+ N5380ResetBus (g);
+}
+
+
diff --git a/private/ntos/miniport/trantor/source/port.c b/private/ntos/miniport/trantor/source/port.c
new file mode 100644
index 000000000..e2246b3c6
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/port.c
@@ -0,0 +1,62 @@
+//----------------------------------------------------------------------
+// File: PORT.C
+//
+// Contains generic port access routines.
+//
+// Revisions:
+// 01-08-93 KJB First.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+//
+//----------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+
+//
+// CardPortSet
+//
+// This routine sets a mask on a certain port. It or's the mask with
+// the value currently at the port. Works only for ports where all bits
+// are readable and writable.
+//
+
+VOID CardPortSet (PUCHAR baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ CardPortGet (baseIoAddress,&tmp);
+ tmp = tmp | mask;
+ CardPortPut (baseIoAddress,tmp);
+}
+
+
+//
+// CardPortClear
+//
+// This routine clears a mask on a certain port. It and's the inverse with
+// the value currently at the port. Works only for ports where all bits
+// are readable and writable.
+//
+VOID CardPortClear (PUCHAR baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ CardPortGet(baseIoAddress,&tmp);
+ tmp = tmp & (0xff ^ mask);
+ CardPortPut(baseIoAddress,tmp);
+}
+
+//
+// CardPortTest
+//
+// This routine clears a mask on a certain port. It and's the mask with
+// the value currently at the port. This result is returned.
+//
+BOOLEAN CardPortTest(PUCHAR baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ CardPortGet(baseIoAddress,&tmp);
+ return (tmp & mask);
+}
+
diff --git a/private/ntos/miniport/trantor/source/portio.c b/private/ntos/miniport/trantor/source/portio.c
new file mode 100644
index 000000000..b4726ad22
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/portio.c
@@ -0,0 +1,87 @@
+//-------------------------------------------------------------------------
+//
+// File: PORTIO.C
+//
+// Contains generic port access routines for I/O cards.
+//
+// Revisions:
+// 02-24-93 KJB First.
+// 03-22-93 KJB Reorged for stub function library.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-05-93 KJB Added functions for word io. Changed PUCHAR to
+// PBASE_REGISTER.
+//
+//-------------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+//
+// PortIOSet
+//
+// This routine sets a mask on a certain port. It or's the mask with
+// the value currently at the port. Works only for ports where all bits
+// are readable and writable.
+//
+VOID PortIOSet(PBASE_REGISTER baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ PortIOGet(baseIoAddress,&tmp);
+ tmp = tmp | mask;
+ PortIOPut(baseIoAddress,tmp);
+}
+VOID PortIOSetWord(PBASE_REGISTER baseIoAddress, USHORT mask)
+{
+ USHORT tmp;
+
+ PortIOGetWord(baseIoAddress,&tmp);
+ tmp = tmp | mask;
+ PortIOPutWord(baseIoAddress,tmp);
+}
+
+//
+// PortIOClear
+//
+// This routine clears a mask on a certain port. It and's the inverse with
+// the value currently at the port. Works only for ports where all bits
+// are readable and writable.
+//
+VOID PortIOClear(PBASE_REGISTER baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ PortIOGet(baseIoAddress,&tmp);
+ tmp = tmp & (0xff ^ mask);
+ PortIOPut(baseIoAddress,tmp);
+}
+VOID PortIOClearWord(PBASE_REGISTER baseIoAddress, USHORT mask)
+{
+ USHORT tmp;
+
+ PortIOGetWord(baseIoAddress,&tmp);
+ tmp = tmp & (0xff ^ mask);
+ PortIOPutWord(baseIoAddress,tmp);
+}
+
+//
+// PortIOTest
+//
+// This routine clears a mask on a certain port. It and's the mask with
+// the value currently at the port. This result is returned.
+//
+BOOLEAN PortIOTest(PBASE_REGISTER baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ PortIOGet(baseIoAddress,&tmp);
+ return (tmp & mask);
+}
+BOOLEAN PortIOTestWord(PBASE_REGISTER baseIoAddress, USHORT theval)
+{
+ USHORT tmpw;
+
+ PortIOGetWord(baseIoAddress, &tmpw);
+ return tmpw & theval;
+}
+
+
diff --git a/private/ntos/miniport/trantor/source/portmem.c b/private/ntos/miniport/trantor/source/portmem.c
new file mode 100644
index 000000000..343f3f12f
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/portmem.c
@@ -0,0 +1,67 @@
+#ifdef i386
+//------------------------------------------------------------------------
+//
+// File: PORTMEM.C
+//
+// Contains generic memory mapped port access routines.
+//
+// Revisions:
+// 01-08-93 KJB First.
+// 02-25-93 KJB Renamed routines from CardPort to PortMem.
+//
+//------------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+//
+// PortMemSet
+//
+// This routine sets a mask on a certain port. It or's the mask with
+// the value currently at the port. Works only for ports where all bits
+// are readable and writable.
+//
+
+VOID PortMemSet (PUCHAR baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ PortMemGet (baseIoAddress, &tmp);
+ tmp = tmp | mask;
+ PortMemPut (baseIoAddress, tmp);
+}
+
+
+//
+// PortMemClear
+//
+// This routine clears a mask on a certain port. It and's the inverse with
+// the value currently at the port. Works only for ports where all bits
+// are readable and writable.
+//
+
+VOID PortMemClear (PUCHAR baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ PortMemGet (baseIoAddress, &tmp);
+ tmp = tmp & (0xff ^ mask);
+ PortMemPut (baseIoAddress, tmp);
+}
+
+
+//
+// PortMemTest
+//
+// This routine clears a mask on a certain port. It and's the mask with
+// the value currently at the port. This result is returned.
+//
+
+BOOLEAN PortMemTest (PUCHAR baseIoAddress, UCHAR mask)
+{
+ UCHAR tmp;
+
+ PortMemGet (baseIoAddress, &tmp);
+ return (tmp & mask);
+}
+
+#endif
diff --git a/private/ntos/miniport/trantor/source/scsifnc.c b/private/ntos/miniport/trantor/source/scsifnc.c
new file mode 100644
index 000000000..422a700d7
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/scsifnc.c
@@ -0,0 +1,586 @@
+//---------------------------------------------------------------------
+//
+// File: SCSIFNC.C
+//
+// N5380 Scsi Functions file. Contains higher level scsi functions.
+//
+// Revisions:
+// 09-01-92 KJB First.
+// 03-02-93 KJB/JAP Wait for phase change before doing i/o.
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-12-93 KJB FinishCommandInterrupt now calls CardDisableInterrupt
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-23-93 KJB Changed for new functional interface.
+// 03-24-93 KJB ScsiStartCommandInterrupt can now return
+// RET_STATUS_MISSED_INTERRUPT, in which case caller
+// should pretend interrupt happened and call
+// FinishCommandInterrupt.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+// 03-31-93 JAP/KJB Added code to handle data overflow:
+// DATAIN: target sends more bytes than we have
+// been asked to receive
+// DATAOUT: target requests more bytes than we have
+// been asked to send
+// 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
+// 04-05-93 KJB Changed DoIo, now it will not return
+// DATA_OVERRUN when there is no data to transfer.
+// 04-09-93 KJB Check for phase mismatch before returning that
+// we missed an interrupt.
+// 05-13-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both the PBASE_REGISTER and the
+// PWORKSPACE parameters. Auto Request Sense is
+// now supported.
+// 05-13-93 KJB Added RequestSenseValid field to TSRB.
+// 05-16-93 KJB Fixed bug: finishcommandinterrupt was returning
+// RET_STATUS_PENDING when length of xfer was 0.
+// Now return RET_STATUS_ERROR when Status != 0.
+//
+//---------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+//
+// Local functions
+//
+void ScsiDoRequestSense(PTSRB t);
+
+//
+// ScsiSendCommand
+//
+// Selects a target and sends a scsi command during command phase.
+//
+
+USHORT ScsiSendCommand (PADAPTER_INFO g, UCHAR target,
+ UCHAR lun, PUCHAR pcmd, UCHAR cmdlen)
+{
+ USHORT rval;
+ ULONG tmp;
+
+ // select the target
+
+ if (rval = N5380Select (g, target, lun)) {
+ if (rval != RET_STATUS_SELECTION_TIMEOUT) {
+ DebugPrint((DEBUG_LEVEL,"ScsiSendCommand-0 Error: %x\n",rval));
+ }
+ return rval;
+ }
+
+ // set the phase to Command
+
+ if (rval = N5380SetPhase (g, PHASE_COMMAND)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiSendCommand-1 Error: %x\n",rval));
+ return rval;
+ }
+
+ // send the command bytes
+
+ if (rval = CardWriteBytesCommand (g, pcmd, (ULONG)cmdlen,
+ &tmp, PHASE_COMMAND)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiSendCommand-2 Error: %x\n",rval));
+ return rval;
+ }
+
+ return 0;
+}
+
+
+//
+// ScsiDoCommand
+//
+// Executes a complete scsi command: all phase sequences without using
+// interrupts.
+//
+
+USHORT ScsiDoCommand (PTSRB t)
+{
+ USHORT rval;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // select the target and send the command bytes
+
+ if (rval = ScsiSendCommand (g, t->Target, t->Lun, t->pCommand,
+ t->CommandLen)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiDoCommand-0 Error: %x\n",rval));
+ goto done;
+ }
+
+ if (rval = ScsiFinishCommandInterrupt (t)) {
+ if (rval!=RET_STATUS_SUCCESS) {
+ DebugPrint((DEBUG_LEVEL,"ScsiDoCommand-1 Error: %x\n",rval));
+ }
+ }
+
+done:
+ t->ReturnCode = rval;
+
+ return rval;
+}
+
+
+//
+// ScsiStartCommandInterrupt
+//
+// Executes a scsi command up to the end of command phase. After this, the
+// interrupt will come in and ScsiFinishCommandInterrupt should be called to
+// complete the data, status, and message phases.
+//
+
+USHORT ScsiStartCommandInterrupt (PTSRB t)
+{
+ USHORT rval;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // select the target and send the command bytes
+
+ if (rval = ScsiSendCommand (g, t->Target, t->Lun, t->pCommand,
+ t->CommandLen)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiStartCommandInterrupt-0 Error: %x\n",rval));
+ goto done;
+ }
+
+ // enable the interrupt
+
+ CardEnableInterrupt (g);
+
+ // if request is already up, we may have missed the interrupt, it is done
+
+ if (N5380PortTest (g, N5380_CURRENT_STATUS, CS_REQ)) {
+
+ // and we are not still in command phase
+
+ if (!N5380PortTest(g, N5380_DMA_STATUS, DS_PHASE_MATCH)) {
+ rval = RET_STATUS_MISSED_INTERRUPT;
+ goto done;
+ }
+ }
+
+ rval = RET_STATUS_PENDING;
+
+done:
+ t->ReturnCode = rval;
+ return rval;
+}
+
+//
+// ScsiFinishComamndInterrupt
+//
+// Called to finish a command that has been started by ScsiStartCommandInterupt.
+// This function completes the data, status, and message phases.
+//
+
+USHORT ScsiFinishCommandInterrupt (PTSRB t)
+{
+ USHORT rval = 0;
+ USHORT rval_stat = 0;
+ PADAPTER_INFO g = t->pWorkspace;
+
+
+ // set actual transfer length to 0
+
+ t->ActualDataLen = 0;
+
+ // set request sense valid flag to FALSE
+
+ t->Flags.RequestSenseValid = FALSE;
+
+ // is there a data phase??
+
+ if (t->DataLen) {
+
+ // read/write the data if there is a data phase
+
+ rval = ScsiDoIo (t);
+
+ }
+
+ // if no errors, return RET_STATUS_SUCCESS.
+
+ if (!rval) {
+ rval = RET_STATUS_SUCCESS;
+ }
+
+ // get the stat and message bytes
+
+ if (rval_stat = ScsiGetStat (g, &t->Status)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiFinishCommandInterrupt-0 Error: %x\n",rval_stat));
+ rval = rval_stat;
+ goto done;
+ }
+
+ // if not any other error, return a general status error to indicate
+ // that the status byte was bad.
+
+ if (!rval_stat) {
+
+ // no errors get status, was there a status check condition?
+
+ if (t->Status == 0x02) {
+
+ if (t->Flags.DoRequestSense) {
+ ScsiDoRequestSense(t);
+ }
+
+ }
+
+ if (t->Status) {
+
+ // return with error when there was a non-zero status
+
+ rval = RET_STATUS_ERROR;
+ }
+
+ }
+
+ if (rval!=RET_STATUS_SUCCESS) {
+ DebugPrint((DEBUG_LEVEL,"ScsiFinishCommandInterrupt-1 Error: %x\n",rval));
+ }
+
+done:
+ // disable the interrupt
+
+ CardDisableInterrupt(g);
+
+ // for now, we never return pending
+
+ t->ReturnCode = rval;
+ return rval;
+}
+
+//
+// ScsiDoRequestSense
+//
+// Do a request sense and store the information in the current tsrb.
+// Works on the stack, does not harm the current tsrb.
+//
+VOID ScsiDoRequestSense(PTSRB t)
+{
+ PADAPTER_INFO g = t->pWorkspace;
+ // allocate on stack ok, since we don't use interrupt for the sense cmd
+ TSRB tsrb;
+ PTSRB t0 = &tsrb;
+ UCHAR pSenseCmd[6];
+ USHORT rval;
+
+ pSenseCmd[0] = 0x03;
+ pSenseCmd[1] = 0x00;
+ pSenseCmd[2] = 0x00;
+ pSenseCmd[3] = 0x00;
+ pSenseCmd[4] = t->SenseDataLen;
+ pSenseCmd[5] = 0x00;
+
+ // copy most of the tsrb information from the current tsrb
+
+ *t0 = *t;
+
+ // get the sense information
+
+ t0->Flags.DoRequestSense = FALSE; // don't request sense info here
+ t0->pCommand = pSenseCmd;
+ t0->CommandLen = 6;
+ t0->Dir = TSRB_DIR_IN;
+ t0->pData = t->pSenseData;
+ t0->DataLen = t->SenseDataLen;
+
+ rval = CardDoCommand(t0); // don't use interrupts
+
+ if (rval == RET_STATUS_SUCCESS) {
+ t->Flags.RequestSenseValid = TRUE;
+ }
+}
+
+//
+// ScsiWriteBytesSlow
+//
+// This functions writes bytes to the scsi bus using the slow req/ack
+// handshake. Faster methods are generally avaiable, but they are dependent
+// on how the card inplements the dma capabilities of the 5380. This
+// is a sure-fire slow method that works. It is great to bring up new cards.
+//
+
+USHORT ScsiWriteBytesSlow (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ ULONG i;
+ USHORT rval = 0;
+ UCHAR tmp;
+
+ for (i=0;i<len;i++) {
+
+ // wait for request to be asserted
+
+ if (rval = N5380GetPhase (g, &tmp)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiWriteBytesSlow-0 Error: %x\n",rval));
+ goto done;
+ }
+
+ // see if phase match
+
+ if (phase != tmp) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ goto done;
+ }
+
+ if (rval = N5380PutByte (g, TIMEOUT_REQUEST, pbytes[i])) {
+ DebugPrint((DEBUG_LEVEL,"ScsiWriteBytesSlow-1 Error: %x\n",rval));
+ goto done;
+ }
+ }
+
+done:
+ *pActualLen = i;
+ return rval;
+}
+
+
+//
+// ScsiReadBytesSlow
+//
+// This functions reads bytes to the scsi bus using the slow req/ack
+// handshake. Faster methods are generally avaiable, but they are dependent
+// on how the card inplements the dma capabilities of the 5380. This
+// is a sure-fire slow method that works. It is great to bring up new cards.
+//
+
+USHORT ScsiReadBytesSlow (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ ULONG i;
+ USHORT rval = 0;
+ UCHAR tmp;
+
+ for (i = 0; i < len; i++) {
+
+ // wait for request to be asserted
+
+ if (rval = N5380GetPhase (g, &tmp)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiReadBytesSlow-0 Error: %x\n",rval));
+ goto done;
+ }
+
+ // see if phase match
+
+ if (phase != tmp) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ goto done;
+ }
+
+ if (rval = N5380GetByte (g, TIMEOUT_REQUEST, &pbytes[i])) {
+ DebugPrint((DEBUG_LEVEL,"ScsiReadBytesSlow-1 Error: %x\n",rval));
+ goto done;
+ }
+ }
+
+done:
+ *pActualLen = i;
+ return rval;
+}
+
+
+//
+// ScsiDoIo
+//
+// This function does the I/O during a data phase.
+//
+
+USHORT ScsiDoIo (PTSRB t)
+{
+ USHORT rval;
+ UCHAR tmp;
+ UCHAR phase;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // wait for next phase, errors in phase will be caught below
+
+ if (rval = N5380GetPhase (g, &tmp)) {
+ goto done;
+ }
+
+ if (t->DataLen && tmp != PHASE_DATAIN && tmp != PHASE_DATAOUT) {
+
+ // phase is not data in/out and we were expecting data, len !=0
+
+ rval = RET_STATUS_DATA_OVERRUN;
+ goto done;
+ }
+
+
+ // phase is now either data in or data out
+
+ if (t->Dir == TSRB_DIR_UNKNOWN) {
+
+ // must be read/write, use phase bits to determine it
+
+ if (tmp == PHASE_DATAOUT) {
+ t->Dir = TSRB_DIR_OUT;
+ }
+ else if (tmp == PHASE_DATAIN) {
+ t->Dir = TSRB_DIR_IN;
+ }
+
+ // else: pass thru, don't transfer any data, must be in status phase
+
+ }
+
+
+ if (t->Dir == TSRB_DIR_OUT) {
+
+ // data write
+
+ // set the phase to data out
+
+ if (rval = N5380SetPhase (g, PHASE_DATAOUT)) {
+ return RET_STATUS_ERROR;
+ }
+
+ // send the bytes
+
+ if (rval = CardWriteBytesFast (g, t->pData, t->DataLen,
+ &t->ActualDataLen, PHASE_DATAOUT)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiDoIo-0 Error: %x\n",rval));
+ return rval;
+ }
+
+ // Check for Data Overflow.
+
+ while ((N5380GetPhase (g,&phase) == 0) &&
+ (phase == PHASE_DATAOUT)) {
+
+ // DATA OVERFLOW:
+ // Target requests more bytes than we have been asked to send.
+ // Send a dummy byte of 0 until we are out of DATAOUT phase.
+
+ ULONG tmpDataLen;
+ UCHAR dummy = 0;
+
+ if (rval = ScsiWriteBytesSlow (g, &dummy, 1,
+ &tmpDataLen, PHASE_DATAOUT)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiDoIo-2 Error: %x\n",rval));
+ return rval;
+ }
+ }
+ }
+
+ else if (t->Dir == TSRB_DIR_IN) {
+
+ // data read
+
+ // set the phase to data in
+
+ if (rval = N5380SetPhase (g, PHASE_DATAIN)) {
+ return RET_STATUS_ERROR;
+ }
+
+ // read the bytes
+
+ if (rval = CardReadBytesFast (g, t->pData, t->DataLen,
+ &t->ActualDataLen, PHASE_DATAIN)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiDoIo-1 Error: %x\n",rval));
+ return rval;
+ }
+
+ // Check for Data Overflow.
+
+ while ((N5380GetPhase(g,&phase) == 0) &&
+ phase == PHASE_DATAIN) {
+
+ // DATA OVERFLOW:
+ // Target sends more bytes than we have been asked to receive.
+ // Swallow up extra bytes until we are out of DATAIN phase.
+
+ ULONG tmpDataLen;
+ UCHAR dummy;
+
+ if (rval = ScsiReadBytesSlow (g, &dummy, 1,
+ &tmpDataLen, PHASE_DATAIN)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiDoIo-3 Error: %x\n",rval));
+ return rval;
+ }
+ }
+ }
+
+done:
+ return rval;
+}
+
+
+//
+// ScsiGetStat
+//
+// This function gets the status and message bytes.
+//
+
+USHORT ScsiGetStat (PADAPTER_INFO g, PUCHAR pstatus)
+{
+ UCHAR tmp;
+ USHORT rval;
+
+ // set the phase to Status Phase
+
+ if (rval = N5380SetPhase (g, PHASE_STATUS)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiGetStat-0 Error: %x\n",rval));
+ return rval;
+ }
+
+ // wait for request to be asserted
+
+ if (rval = N5380GetPhase (g,&tmp)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiGetStat-1 Error: %x\n",rval));
+ return rval;
+ }
+
+ // see if phase match
+
+ if (PHASE_STATUS != tmp) {
+ return RET_STATUS_PHASE_SEQ_FAILURE;
+ }
+
+ // get the status byte
+
+ if (rval = N5380GetByte (g, TIMEOUT_REQUEST, pstatus)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiGetStat-2 Error: %x\n",rval));
+ return rval;
+ }
+
+ // set the phase to Message In Phase
+
+ if (rval = N5380SetPhase (g, PHASE_MSGIN)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiGetStat-3 Error: %x\n",rval));
+ return rval;
+ }
+
+ // wait for request to be asserted
+
+ if (rval = N5380GetPhase (g,&tmp)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiGetStat-4 Error: %x\n",rval));
+ return rval;
+ }
+
+ // see if phase match
+
+ if (PHASE_MSGIN != tmp) {
+ return RET_STATUS_PHASE_SEQ_FAILURE;
+ }
+
+ // get the msg byte, throw it away
+
+ if (rval = N5380GetByte (g, TIMEOUT_REQUEST, &tmp)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiGetStat-5 Error: %x\n",rval));
+ return rval;
+ }
+
+ // set the phase to NULL to up N5380 back to normal
+
+ if (rval = N5380SetPhase (g, PHASE_NULL)) {
+ DebugPrint((DEBUG_LEVEL,"ScsiGetStat-6 Error: %x\n",rval));
+ return rval;
+ }
+
+ return rval;
+}
+
diff --git a/private/ntos/miniport/trantor/source/scsiport.c b/private/ntos/miniport/trantor/source/scsiport.c
new file mode 100644
index 000000000..30be5fc84
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/scsiport.c
@@ -0,0 +1,181 @@
+//------------------------------------------------------------------------
+//
+// SCSIPORT.C
+//
+// DOS Port Access File
+//
+// Contains functions to access I/O and memory ports. Some of these
+// routines may not be called for some cards. IO access routines are
+// called for IO mapped cards, Mem access routines are called for Mem
+// mapped cards.
+//
+// For DOS these are simple assembly functions.
+//
+// Revisions:
+// 01-29-93 KJB First.
+// 03-03-93 KJB Improved comments.
+// 03-22-93 KJB Reorged for stub function library.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+//
+//------------------------------------------------------------------------
+
+
+#include CARDTXXX_H
+
+//
+// ScsiPortReadPortUchar
+//
+// Does an "in" instruction from i/o port p.
+// Returns the value.
+//
+
+UCHAR ScsiPortReadPortUchar (PUCHAR p)
+{
+ UCHAR rval;
+
+ _asm {
+ mov dx,word ptr p
+ in al,dx
+ mov rval,al
+ }
+ return rval;
+}
+
+//
+// ScsiPortWritePortUchar
+//
+// Does an "out" instruction to i/o port p.
+//
+VOID ScsiPortWritePortUchar(PUCHAR p,UCHAR b)
+{
+ _asm {
+ mov dx,word ptr p
+ mov al,b
+ out dx,al
+ }
+}
+
+//
+// ScsiPortReadPortUshort
+//
+// Does an "in" instruction from i/o port p.
+// Returns the value.
+//
+USHORT ScsiPortReadPortUshort(PUSHORT p)
+{
+ USHORT rval;
+
+ _asm {
+ mov dx,word ptr p
+ in ax,dx
+ mov rval,ax
+ }
+ return rval;
+}
+
+//
+// ScsiPortWritePortUshort
+//
+// Does an "out" instruction to i/o port p.
+//
+VOID ScsiPortWritePortUshort(PUSHORT p,USHORT w)
+{
+ _asm {
+ mov dx,word ptr p
+ mov ax,w
+ out dx,ax
+ }
+}
+
+//
+// ScsiPortWritePortBufferUshort
+//
+// Does an "rep outsw" instruction to i/o port p.
+//
+VOID ScsiPortWritePortBufferUshort(PUSHORT p, PUSHORT buffer, ULONG len)
+{
+ _asm {
+ push ds
+ push esi
+ mov dx,word ptr p
+ mov esi,word ptr buffer
+ mov ds,word ptr buffer+2
+ mov cx,word ptr len
+ rep outsw
+ pop esi
+ pop ds
+ }
+}
+
+//
+// ScsiPortReadPortBufferUshort
+//
+// Does an rep "insw" instruction from i/o port p.
+//
+VOID ScsiPortReadPortBufferUshort(PUSHORT p, PUSHORT buffer, ULONG len)
+{
+ _asm {
+ push es
+ push edi
+ mov dx,word ptr p
+ mov di,word ptr buffer
+ mov es,word ptr buffer+2
+ mov cx,word ptr len
+ rep insw
+ pop edi
+ pop es
+ }
+}
+
+//
+// ScsiPortReadPortRegisterUchar
+//
+// Reads a memory mapped i/o address.
+// Returns the value.
+//
+UCHAR ScsiPortReadRegisterUchar(PUCHAR p)
+{
+ UCHAR rval;
+
+ _asm {
+ push es
+ mov bx,word ptr p
+ mov es,word ptr p+2
+ mov al,es:[bx]
+ mov rval, al
+ pop es
+ }
+ return rval;
+}
+
+//
+// ScsiPortWritePortRegisterUchar
+//
+// Writes a value to a memory mapped i/o address.
+//
+VOID ScsiPortWriteRegisterUchar(PUCHAR p,UCHAR b)
+{
+ _asm {
+ push es
+ mov bx,word ptr p
+ mov es,word ptr p+2
+ mov al, b
+ mov es:[bx],al
+ pop es
+ }
+}
+
+//
+// ScsiPortStallExecution
+//
+// Stalls executeion for time micro seconds. Should be processor,
+// independent, but for now we will do just a loop.
+//
+VOID ScsiPortStallExecution(ULONG time)
+{
+ ULONG i;
+
+ if (time>1) {
+ for (i=0;i<time;i++);
+ }
+}
diff --git a/private/ntos/miniport/trantor/source/sl386.c b/private/ntos/miniport/trantor/source/sl386.c
new file mode 100644
index 000000000..249cd634e
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/sl386.c
@@ -0,0 +1,285 @@
+//-----------------------------------------------------------------------
+//
+// SL386.C
+//
+// Trantor SL386 access file.
+//
+// Revisions:
+// 04-07-93 KJB First.
+//
+//-----------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+//
+// Local Routines
+//
+
+BOOLEAN SL386EnableConfig(VOID );
+VOID SL386DisableConfig(VOID );
+
+//
+// Local Definitions
+//
+
+#define CLEAR_INTERRUPT_FLAG() \
+ _asm { \
+ pushf \
+ } \
+ _asm {cli}
+
+#define RESTORE_INTERRUPT_FLAG() \
+ _asm { \
+ popf \
+ }
+
+//-----------------------------------------------------------------------
+//
+// 80386SL EPP OVERVIEW
+//
+// The "fast" (EPP) parallel port mode of the 80386SL processor
+// is enabled through the following steps:
+//
+// Enable 386SL Special Features:
+//
+// Disable interrupts.
+// Unlock CPUPWRMODE register.
+// Set CPUCNFG Lock bit in CPUPWRMODE register.
+// Unlock 386SL configuration register space.
+// Write index of CFGR2 to CFGINDEX register.
+// Set SFIO_EN bit in CFGR2 (write to CFGDATA register).
+// Enable special features by dummy write to SFS_ENABLE.
+// Disable 386SL configuration space (write 0fah to
+// CFGINDEX and 01h to CFGDATA).
+// Enable interrupts.
+//
+// Select "fast" mode for parallel port:
+//
+// Disable interrupts.
+// Write index of FPP_CNTL to SFS_INDEX register.
+// Set FAST_MODE and EXT_MODE bits in FPP_CNTL
+// (write to SFS_DATA register).
+// Enable interrupts.
+//
+// Disable 386SL Special Features:
+//
+// Disable special features by dummy write to SFS_DISABLE.
+//
+//
+// Notes:
+//
+// When setting the parallel port to "fast" mode the port address
+// is controlled by the FPP_CNTL register. It is probably a good
+// idea to read the currently selected port address from the
+// PPCONTROL register and using that address the first time the
+// parallel port is set to fast mode.
+//
+// When setting the FAST_MODE bit it is not necessary to set the
+// EXT_MODE bit (FPP_CNTL register). EXT_MODE need only be set if
+// software needs to perform non-EPP byte read cycles in addition
+// to normal EPP cycles.
+//
+//-----------------------------------------------------------------------
+
+//-----------------------------------------------------------------------
+//
+// SL386EnableEPP
+//
+// Attempts to enable the "fast" (EPP) parallel port on the
+// 386SL.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN SL386EnableEPP(VOID )
+{
+ // The following translation table is used to convert PPCONFIG
+ // values (LPTSL1,LPTSL0) to FPP_CNTL values.
+
+ static CONST UCHAR fpp_xlate[] = {
+ FPP_FM + FPP_EM + FPP_CTL_LPT1,
+ FPP_FM + FPP_EM + FPP_CTL_LPT2,
+ FPP_FM + FPP_EM + FPP_CTL_LPT2,
+ FPP_CTL_DIS
+ };
+
+ UCHAR fpp_cntl;
+ UCHAR cfgr2;
+ UCHAR tmpb;
+ BOOLEAN rval;
+
+ CLEAR_INTERRUPT_FLAG();
+
+ //-----------------------------------------------------------------------
+ // Enable 386SL special features.
+ //-----------------------------------------------------------------------
+
+ if (!SL386EnableConfig()) {
+ rval = FALSE;
+ goto done;
+ }
+
+ // select CFGR2
+ PortIOPut((PBASE_REGISTER)SL_CFG_INDEX,SL_CFGR2);
+ PortIOGet((PBASE_REGISTER)SL_CFG_DATA,&tmpb);
+ cfgr2 = tmpb; // save CFGR2 value
+ tmpb |= C2_SFIO + C2_PS2; // set SFIO_EN
+ PortIOPut((PBASE_REGISTER)SL_CFG_DATA,tmpb);
+ PortIOPut((PBASE_REGISTER)SL_SFS_ENABLE,tmpb); // dummy write to SFS_ENABLE
+
+ SL386DisableConfig();
+
+ //-----------------------------------------------------------------------
+ // Read PPCONFIG and translate to FPP_CNTL setting.
+ //-----------------------------------------------------------------------
+
+ PortIOGet((PBASE_REGISTER)SL_PPCONFIG,&tmpb);
+ tmpb &= PPC_SEL;
+ tmpb = tmpb >> PPC_SEL_POS;
+ fpp_cntl = fpp_xlate[tmpb]; // new FPP_CNTL value
+
+ //-----------------------------------------------------------------------
+ // Disable PS/2 style registers.
+ //-----------------------------------------------------------------------
+
+ if (!SL386EnableConfig()) {
+ rval = FALSE;
+ goto done;
+ }
+
+ PortIOPut((PBASE_REGISTER) SL_CFG_INDEX,SL_CFGR2);
+ PortIOClear((PBASE_REGISTER)SL_CFG_DATA,C2_PS2);
+
+ SL386DisableConfig();
+
+ //-----------------------------------------------------------------------
+ // Set "fast" mode in FPP_CNTL register.
+ //-----------------------------------------------------------------------
+
+ PortIOPut((PBASE_REGISTER)SL_SF_INDEX,SL_FPP_CNTL);
+
+ // test current FPP_CNTL value
+ if (PortIOTest((PBASE_REGISTER)SL_SF_DATA,FPP_FM)) {
+ // already in fast mode
+ // make sure that "ext" mode is set
+ PortIOSet((PBASE_REGISTER)SL_SF_DATA,FPP_FM);
+ PortIOGet((PBASE_REGISTER)SL_SF_DATA,&fpp_cntl); // save fpp_cntl value
+ } else {
+ PortIOPut((PBASE_REGISTER)SL_SF_DATA,fpp_cntl);
+ }
+
+ // epp mode now set
+
+ //-----------------------------------------------------------------------
+ // Disable special features.
+ //-----------------------------------------------------------------------
+
+ PortIOPut((PBASE_REGISTER)SL_SFS_DISABLE,0x01); //dummy write to SFS_DISABLE
+
+
+ //-----------------------------------------------------------------------
+ // Restore original CFGR2.
+ //-----------------------------------------------------------------------
+
+
+ if (!SL386EnableConfig()) {
+ rval = FALSE;
+ goto done;
+ }
+
+ // select CFGR2
+ PortIOPut((PBASE_REGISTER)SL_CFG_INDEX,SL_CFGR2);
+ PortIOPut((PBASE_REGISTER)SL_CFG_DATA,cfgr2);
+
+ SL386DisableConfig();
+
+ // Based on bits 4,5 in the FPP_CNTL register, determine the
+ // parallel port I/O base port.
+ // We won't do this now, it is not consistent with modularity of
+ // the code.
+
+ rval = TRUE;
+
+done:
+ RESTORE_INTERRUPT_FLAG();
+ return rval;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// SL386EnableConfig
+//
+// Enables the 386SL configuration space.
+//
+// Note: Caller should disable interrupts before calling this
+// routine.
+//
+// Returns: TRUE if 386SL successfully enabled.
+//
+//-----------------------------------------------------------------------
+
+BOOLEAN SL386EnableConfig(VOID )
+{
+ UCHAR tmpb;
+ USHORT tmpw;
+ BOOLEAN rval;
+
+ // Unlock CPUPWRMODE register.
+ //
+ // byte write 0h to port 23h
+ // byte write 80h to port 22h
+ // word write 0080h to port 22h
+
+ PortIOPut((PBASE_REGISTER)(SL_CPUPWRMODE+1),0x00);
+ PortIOPut((PBASE_REGISTER)SL_CPUPWRMODE,0x80);
+ PortIOPutWord((PBASE_REGISTER)SL_CPUPWRMODE,0x80);
+
+ // Attempt to read the 386SL signature register (30EH, OMCU).
+ // Value should be 43xxh.
+
+ PortIOPutWord((PBASE_REGISTER)SL_CPUPWRMODE,PM_UID_CMCU+PM_UE);
+ PortIOGetWord((PBASE_REGISTER)0x30e,&tmpw);
+ if ((tmpw & 0xff00) != 0x43) {
+ rval = FALSE;
+ goto done;
+ }
+
+ PortIOGetWord((PBASE_REGISTER)SL_CPUPWRMODE,&tmpw);
+ tmpw = tmpw & (0xffff ^ (PM_UID + PM_UE));
+ PortIOPutWord((PBASE_REGISTER)SL_CPUPWRMODE,tmpw);
+
+ // Lock CPUPWRMODE register.
+
+ PortIOGetWord((PBASE_REGISTER)SL_CPUPWRMODE,&tmpw);
+ tmpw = tmpw | PM_CFG_LOCK;
+ PortIOPutWord((PBASE_REGISTER)SL_CPUPWRMODE,tmpw);
+
+ // Enable I/O configuration space.
+
+ PortIOGet((PBASE_REGISTER)SL_CNFG_ENA1,&tmpb);
+ PortIOGet((PBASE_REGISTER)SL_CNFG_ENA2,&tmpb);
+ PortIOGet((PBASE_REGISTER)SL_CNFG_ENA3,&tmpb);
+ PortIOGet((PBASE_REGISTER)SL_CNFG_ENA4,&tmpb);
+
+ // return success if lock status is 0
+ rval = !PortIOTestWord((PBASE_REGISTER)SL_CPUPWRMODE,PM_LS);
+
+done:
+ return rval;
+}
+
+
+//-----------------------------------------------------------------------
+//
+// SL386DisableConfig
+//
+// Disables 386SL configuration space.
+//
+//-----------------------------------------------------------------------
+
+VOID SL386DisableConfig(VOID )
+{
+ PortIOPut((PBASE_REGISTER)SL_CFG_INDEX, SL_IDXLCK);
+ PortIOPut((PBASE_REGISTER)SL_CFG_DATA, SL_IDXLCK_VAL);
+}
+
diff --git a/private/ntos/miniport/trantor/source/t128.c b/private/ntos/miniport/trantor/source/t128.c
new file mode 100644
index 000000000..c9f57c15f
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/t128.c
@@ -0,0 +1,483 @@
+//---------------------------------------------------------------------
+//
+// T128.C
+//
+// T128 Logic Specific File
+//
+// These routines are independent of the card the T128 logic is on. The
+// cardxxxx.h file must define the following routines:
+//
+// T128PortPut
+// T128PortGet
+// T128PortSet
+// T128PortClear
+// T128PortTest
+//
+// These routines could be defined by some other include file instead of
+// cardxxxx.h, as the pc9010 defines the needed n5380xxxxxxxx routines.
+//
+// Revisions:
+// 02-25-93 KJB First.
+// 03-05-93 KJB Added call to N5380DisableDmaWrite.
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-11-92 KJB Changed to use new N5380.H names.
+// 03-25-93 JAP Fixed up typedef and prototype inconsistencies
+// 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+// 05-14-93 KJB Remove all WINNT specific #ifdef i386 references.
+// 05-17-93 KJB Added ErrorLogging capabilities (used by WINNT).
+//
+//---------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+// Local Routines
+
+USHORT T128WaitXfrReady(PADAPTER_INFO g, ULONG usec);
+VOID T128ResetDmaTimeout(PADAPTER_INFO g);
+VOID T128EnableDmaRead(PADAPTER_INFO g);
+VOID T128EnableDmaWrite(PADAPTER_INFO g);
+VOID T128DisableDmaRead(PADAPTER_INFO g);
+VOID T128DisableDmaWrite(PADAPTER_INFO g);
+
+//
+// T128ResetBus
+//
+// Resets the card, and the SCSI bus to a completely known, clean state.
+//
+VOID T128ResetBus(PADAPTER_INFO g)
+{
+
+ // disable interrupts, t228 only
+ T128PortClear(g,T128_CONTROL,CR_INTENB);
+
+ // disable any dma xfer that was occuring
+ T128DisableDmaRead(g);
+
+ // reset the scsi bus
+ N5380ResetBus(g);
+}
+
+//
+// T128EnableInterrupt
+//
+// Enables the interrupt on the card and on the 5380.
+//
+VOID T128EnableInterrupt(PADAPTER_INFO g)
+{
+ // all t128 to send interrupts
+ T128PortSet(g,T128_CONTROL,CR_INTENB);
+
+ // enable interrupts on the 5380
+ N5380EnableInterrupt(g);
+}
+
+//
+// T128DisableInterrupt
+//
+// Disables the interrupt on the card and on the 5380.
+//
+VOID T128DisableInterrupt(PADAPTER_INFO g)
+{
+ // disable the signal from the 5380
+ N5380DisableInterrupt(g);
+
+ // disable the bit from the t128 control register
+ // this has an effect only on the t228
+ T128PortClear(g,T128_CONTROL ,CR_INTENB);
+}
+
+//
+// T128WaitXfrReady
+//
+// This routine waits till the t120 status register says the xfr is ready.
+//
+USHORT T128WaitXfrReady(PADAPTER_INFO g, ULONG usec)
+{
+ ULONG i;
+
+ // see if the flag comes back quickly
+ for (i=0;i<TIMEOUT_QUICK;i++) {
+
+ // wait for card to be ready
+ if (T128PortTest(g, T128_STATUS, SR_XFR_READY)) {
+ return 0;
+ }
+ }
+
+ // ok, it did not come back quickly, we will yield to other processes
+ for (i=0;i<usec;i++) {
+
+ // wait for card to be ready
+ if (T128PortTest(g, T128_STATUS, SR_XFR_READY)) {
+ return 0;
+ }
+
+ // see if bus free
+ if (!N5380PortTest(g,N5380_CURRENT_STATUS,CS_BSY)) {
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_UNEXPECTED_BUS_FREE, 1);
+ return RET_STATUS_UNEXPECTED_BUS_FREE;
+ }
+
+ // since we have taken some time... check for phase change
+ if (!N5380PortTest(g,N5380_DMA_STATUS,DS_PHASE_MATCH)) {
+ return RET_STATUS_DATA_OVERRUN;
+ }
+
+ // wait for card to be ready
+ if (T128PortTest(g, T128_STATUS, SR_TIMEOUT)) {
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 2);
+ return RET_STATUS_TIMEOUT;
+ }
+
+ ScsiPortStallExecution(1);
+ }
+
+ DebugPrint((DEBUG_LEVEL,"Error - T128WaitXfrReady\n"));
+
+ // return with an error, non-zero indicates timeout
+ TrantorLogError (g->BaseIoAddress, RET_STATUS_TIMEOUT, 3);
+ return RET_STATUS_TIMEOUT;
+}
+
+//
+// T128ResetDmaTimeout
+//
+// Resets the t128's dma timout bit.
+//
+VOID T128ResetDmaTimeout(PADAPTER_INFO g)
+{
+ // is the timeout flagged?
+ if (T128PortTest(g, T128_STATUS, SR_TIMEOUT)) {
+
+ // toggle the t120 timeout bit to clear any timeout
+
+ T128PortSet(g, T128_CONTROL, CR_TIMEOUT);
+ T128PortClear(g, T128_CONTROL, CR_TIMEOUT);
+ }
+}
+
+//
+// T128EnableDmaRead
+//
+// Enables the DMA read operation for the T128.
+//
+VOID T128EnableDmaRead(PADAPTER_INFO g)
+{
+ // toggle the t120 timeout bit to clear any timeout
+ T128ResetDmaTimeout(g);
+
+ // start dma on the 5380
+ N5380EnableDmaRead(g);
+}
+
+//
+// T128EnableDmaWrite
+//
+// Enables the DMA write operation for the T128.
+//
+VOID T128EnableDmaWrite(PADAPTER_INFO g)
+{
+ // toggle the t120 timeout bit to clear any timeout
+ T128ResetDmaTimeout(g);
+
+ // start dma on the 5380
+ N5380EnableDmaWrite(g);
+}
+
+//
+// T128DisableDmaRead
+//
+// Clears the current DMA operation for the T128.
+//
+VOID T128DisableDmaRead(PADAPTER_INFO g)
+{
+ // toggle the t120 timeout bit to clear any timeout
+ T128ResetDmaTimeout(g);
+
+ // disable dma on the 5380
+ N5380DisableDmaRead(g);
+}
+
+//
+// T128DisableDmaWrite
+//
+// Clears the current DMA operation for the T128.
+//
+VOID T128DisableDmaWrite(PADAPTER_INFO g)
+{
+ // toggle the t120 timeout bit to clear any timeout
+ T128ResetDmaTimeout(g);
+
+ // disable dma on the 5380
+ N5380DisableDmaWrite(g);
+}
+
+//
+// T128ReadBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiReadBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+USHORT T128ReadBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // for small transfers, use slow method
+ if (len<0x200) {
+ rval = ScsiReadBytesSlow(g, pbytes, len,
+ pActualLen, phase);
+ return rval;
+ }
+
+ // start dma for this card
+ T128EnableDmaRead(g);
+
+ {
+ PVOID t128_data = (PUCHAR)g->BaseIoAddress + T128_DATA;
+ ULONG xfer_count = len;
+
+ // we have a 16 bit VGA problem
+ // must only move from even addresses
+
+ _asm {
+ pushf
+ push eax
+ push ebx
+ push ecx
+ push edx
+ push esi
+ push edi
+ push ds
+ push es
+#ifdef MODE_32BIT
+ mov esi,t128_data
+ mov edi,pbytes
+ mov ecx,len
+#else
+ mov esi, word ptr t128_data
+ mov edi, word ptr pbytes
+ mov ds, word ptr t128_data+2
+ mov es, word ptr pbytes+2
+ mov cx, word ptr len
+#endif // MODE_32BIT
+ cld
+ get_bytes:
+ test [esi-0x1e0],SR_XFR_READY
+ jz big_wait
+ ready:
+ movsb
+ dec esi
+ dec ecx
+ jnz get_bytes
+ }
+
+ goto done_asm;
+big_wait:
+ _asm {
+ test [esi-0x1e0],SR_XFR_READY
+ jnz ready
+ test [esi-0x1e0],SR_XFR_READY
+ jnz ready
+ test [esi-0x1e0],SR_XFR_READY
+ jnz ready
+ test [esi-0x1e0],SR_XFR_READY
+ jnz ready
+
+ mov eax,TIMEOUT_READWRITE_LOOP
+ loop1:
+ mov ebx,0x10000
+ loop2:
+ test [esi-0x1e0],SR_XFR_READY
+ jnz ready
+ test [esi-(8-N5380_CURRENT_STATUS)*0x20],CS_REQ
+ jz no_req
+ test [esi-(8-N5380_DMA_STATUS)*0x20],DS_PHASE_MATCH
+ jz phase_error
+ no_req:
+
+ dec ebx
+ jnz loop2
+ dec eax
+ jnz loop1
+ mov rval,RET_STATUS_TIMEOUT
+ jmp short done_asm
+ phase_error:
+ mov rval,RET_STATUS_DATA_OVERRUN
+ done_asm:
+ pop es
+ pop ds
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ popf
+
+ }
+
+ // compute actual xfer len
+ *pActualLen = len - xfer_count;
+ }
+
+ // disable dma
+
+ T128DisableDmaRead(g);
+
+ // some error checking...
+
+ if (rval == RET_STATUS_TIMEOUT) {
+ TrantorLogError (g->BaseIoAddress, rval, 4);
+ }
+
+ return rval;
+}
+
+//
+// T128WriteBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiWriteBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+USHORT T128WriteBytesFast(PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // for small transfers, use slow method
+
+ if (len<0x200) {
+ rval = ScsiWriteBytesSlow(g, pbytes, len,
+ pActualLen, phase);
+ return rval;
+ }
+
+ // start dma for this card
+
+ T128EnableDmaWrite(g);
+
+ {
+ PVOID t128_data = (PUCHAR)g->BaseIoAddress + T128_DATA;
+ ULONG xfer_count = len;
+
+ // we have a 16 bit VGA problem
+ // must only move from even addresses
+
+ _asm {
+ pushf
+ push eax
+ push ebx
+ push ecx
+ push edx
+ push esi
+ push edi
+ push ds
+ push es
+#ifdef MODE_32BIT
+ mov edi,t128_data
+ mov esi,pbytes
+ mov ecx,len
+#define segment_override ds
+#else
+ mov edi, word ptr t128_data
+ mov esi, word ptr pbytes
+ mov es, word ptr t128_data+2
+ mov ds, word ptr pbytes+2
+ mov cx, word ptr len
+#define segment_override es
+#endif // MODE_32BIT
+ cld
+ get_bytes:
+ test segment_override:[edi-0x1e0],SR_XFR_READY
+ jz big_wait
+ ready:
+ movsb
+ dec edi
+ dec ecx
+ jnz get_bytes
+ }
+ goto done_asm;
+ _asm {
+ big_wait:
+ test segment_override:[edi-0x1e0],SR_XFR_READY
+ jnz ready
+ test segment_override:[edi-0x1e0],SR_XFR_READY
+ jnz ready
+ test segment_override:[edi-0x1e0],SR_XFR_READY
+ jnz ready
+ test segment_override:[edi-0x1e0],SR_XFR_READY
+ jnz ready
+
+ mov eax,TIMEOUT_READWRITE_LOOP
+ loop1:
+ mov ebx,0x10000
+ loop2:
+ test segment_override:[edi-0x1e0],SR_XFR_READY
+ jnz ready
+ test segment_override:[edi-(8-N5380_CURRENT_STATUS)*0x20],CS_REQ
+ jz no_req
+ test segment_override:[edi-(8-N5380_DMA_STATUS)*0x20],DS_PHASE_MATCH
+ jz phase_error
+ no_req:
+
+ dec ebx
+ jnz loop2
+ dec eax
+ jnz loop1
+ mov rval,RET_STATUS_TIMEOUT
+ jmp done_asm
+ phase_error:
+ mov rval,RET_STATUS_DATA_OVERRUN
+ done_asm:
+ pop es
+ pop ds
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ pop edi
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ popf
+ }
+
+ // compute actual xfer len
+ *pActualLen = len - xfer_count;
+ }
+
+ // disable dma
+
+ T128DisableDmaWrite(g);
+
+ // some error checking...
+
+ if (rval == RET_STATUS_TIMEOUT) {
+ TrantorLogError (g->BaseIoAddress, rval, 5);
+ }
+
+ return rval;
+}
diff --git a/private/ntos/miniport/trantor/source/t338.c b/private/ntos/miniport/trantor/source/t338.c
new file mode 100644
index 000000000..e36bf3c12
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/t338.c
@@ -0,0 +1,763 @@
+//---------------------------------------------------------------------
+//
+// T338.C
+//
+// Trantor T338 Logic Module. Contains functions to access the T338
+// adapter.
+//
+// Revisions:
+// 02-01-93 KJB First.
+// 02-23-93 KJB Reorganized, supports dataunderrun with long delay
+// for under run on large xfers. Can we fix this?
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-11-93 KJB Changed to use N5380Enable/DisableDmaRead/Write
+// routines.
+// 03-12-93 KJB Now supports polling thru CardInterrupt and
+// StartCommandInterrupt/FinishCommandInterrupt.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-22-93 KJB Added support for scatter gather: T338DoIo.
+// 03-24-93 KJB Fixed SetScsiMode so it does not reset the n5380!
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+// 05-14-93 KJB Remove all WINNT specific #ifdef i386 references.
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+// 05-16-93 KJB Fixed parameter bugs introduced while doing the
+// PWORKSPACE changes.
+// 05-17-93 KJB Fixed compiler warnings.
+//
+//---------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+// Local Functions
+
+VOID T338PutControl(PADAPTER_INFO g,UCHAR mode, UCHAR reg);
+VOID T338SetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control);
+VOID T338SetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control);
+
+//
+// T338PutControl
+//
+// Puts a control byte to the T338 style adapter. This sets the mode
+// to IOR or IOW and the address byte of the N5380 register.
+//
+VOID T338PutControl(PADAPTER_INFO g,UCHAR mode, UCHAR reg)
+{
+ UCHAR tmp;
+
+ // the following bits are active low: IOW, IOR, MR
+
+ tmp = reg | (mode ^ (T338_MR | T338_IOW | T338_IOR));
+
+ // put the control byte on the data lines
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,tmp);
+
+ // assert slc to indicate byte is there
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,P_SLC);
+
+ // clear slc
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
+}
+
+//
+// T338SetPrinterMode
+//
+// This routine sets the T338 to printer pass through mode. This is the
+// default mode and should be set after the brief use of scsi mode.
+//
+VOID T338SetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control)
+{
+ UCHAR tmp;
+
+ // do we have to disable interrupts?
+
+ // negate all control signals...
+
+ T338PutControl(g,0,0);
+
+ // restore data register
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,data);
+
+ // leave p_init negated (1)
+
+ tmp = control | P_INIT;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// T338SetScsiMode
+//
+// This routine sets the T338 into scsi mode. Now the parallel port can
+// be used to send commands the the n5380. This mode should be set only
+// briefly during when the scsi command is being executed.
+//
+VOID T338SetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control)
+{
+ UCHAR tmp;
+
+ // save parallel data
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,data);
+
+ // zero data register
+ // note: the signals IOW,IOR,MR are active low, so assert them..
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,
+ T338_MR | T338_IOW | T338_IOR);
+
+ // save parallel control
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,control);
+ *control = *control & (P_BUFEN ^ 0xff);
+
+ // clear p_init and set p_slc
+
+ tmp = (*control & (P_INIT ^ 0xff) ) | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // clear p_init and set p_slc
+
+ tmp = (*control & (P_INIT ^ 0xff) ) | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // clear slc, leave p_init asserted (0)
+
+ tmp = tmp & (P_SLC ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// T338CheckAdapter
+//
+// This routine is used to sense the presense of the T338 adapter out
+// on the Parallel port. It will only detect the adapter if a device
+// is providing termination power.
+//
+BOOLEAN T338CheckAdapter(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+ BOOLEAN rval;
+
+ // set scsi mode
+
+ T338SetScsiMode(g,&data,&control);
+
+ // reset the 5380
+
+ T338PutControl(g,T338_MR,0);
+ T338PutControl(g,0,0);
+
+ // check to see if a 5380 is there
+
+ rval = N5380CheckAdapter(g);
+
+ // set parallel port for use by printer
+
+ T338SetPrinterMode(g,data,control);
+
+ return rval;
+}
+
+//
+// T338DoCommand
+//
+// Called by the main loop to start a scsi command. This functions is the
+// main entry point for all cards. It returns an SRB status code as defined
+// in ..\..\inc\srb.h. A status code of RET_STATUS_PENDING means that the
+// request has been sent to the controller and an interrupt is needed to
+// finish the request. When this interrupt occurs CardFinishCommandInterrupt
+// will be called.
+//
+USHORT T338DoCommand(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ T338SetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiDoCommand(t);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// T338StartCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the T338 does not support interrupts on its own.
+//
+//
+USHORT T338StartCommandInterrupt(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ T338SetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiStartCommandInterrupt(t);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// T338FinishCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the T338 does not support interrupts on its own.
+//
+//
+USHORT T338FinishCommandInterrupt(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the T338 into ScsiMode
+
+ T338SetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiFinishCommandInterrupt(t);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// T338StartCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the T338 does not support interrupts on its own.
+//
+BOOLEAN T338Interrupt(PADAPTER_INFO g)
+{
+ BOOLEAN rval;
+ UCHAR data;
+ UCHAR control;
+
+ // put the parallel adapter into scsi mode
+
+ T338SetScsiMode(g, &data, &control);
+
+ rval = N5380Interrupt(g);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+//
+// T338ResetBus
+//
+// Resets the SCSI Bus
+//
+VOID T338ResetBus(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+
+ // put the parallel adapter into scsi mode
+
+ T338SetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ N5380ResetBus(g);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+}
+
+//
+// T338WriteBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiWriteBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+USHORT T338WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // use slow mode for odd xfers (inquiry type commands) & audio
+
+ if (len % 512) {
+ return ScsiWriteBytesSlow (g, pbytes, len,
+ pActualLen, phase);
+ }
+
+ // start dma mode
+
+ N5380EnableDmaWrite (g);
+
+ // put the T338 into write dma mode
+
+ T338PutControl (g,T338_IOW,0);
+
+ {
+ ULONG xfer_count = len;
+ PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
+
+ _asm {
+ push esi
+ push ds
+#ifdef MODE_32BIT
+ mov edx,baseIoAddress
+ mov esi,pbytes
+ mov ecx,len
+#else
+ mov dx, word ptr baseIoAddress
+ mov si, word ptr pbytes
+ mov cx, word ptr len
+ mov ds, word ptr pbytes+2
+#endif // MODE_32BIT
+
+ add dx,2 // dx points to control reg
+
+ get_bytes:
+ dec dx // dx points to status register
+ in al,dx
+ test al,P_BUSY
+ jnz big_wait
+
+ ready:
+ dec dx // dx points to parallel data reg
+ mov al,[esi]
+ out dx,al
+
+ // assert DACK
+
+ add dx,2 // dx points to control reg
+ mov al, P_AFX
+ out dx,al
+
+ // deassert DACK
+
+ mov al,0
+ out dx,al
+
+ inc esi
+ dec ecx
+ jnz get_bytes
+ }
+ goto done_asm;
+ _asm {
+big_wait:
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ // wait for a while before going to a bigger timeout
+ push ecx
+ push ebx
+ mov ebx,TIMEOUT_READWRITE_LOOP
+ loop0:
+ mov ecx,0x10000
+ loop1:
+ in al,dx
+ test al,P_BUSY
+ jz ready1
+ in al,dx
+ test al,P_BUSY
+ jz ready1
+
+ dec ecx
+ jnz loop1
+ dec ebx
+ jnz loop0
+ pop ebx
+ pop ecx
+ jmp short error
+ ready1:
+ pop ebx
+ pop ecx
+ jmp short ready
+ error:
+ mov rval,RET_STATUS_TIMEOUT
+ done_asm:
+ pop ds
+ pop esi
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ }
+
+ // compute actual xfer len
+
+ *pActualLen = len - xfer_count;
+ }
+
+ // clear the dma bit of 5380
+
+ N5380DisableDmaWrite (g);
+
+ // if data underrun, return the under/over run error message
+
+ if (rval) {
+ UCHAR tmp;
+
+ // phase mismatch means data under/over run
+
+ N5380GetPhase (g,&tmp);
+
+ if (tmp == PHASE_STATUS) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ }
+ }
+
+ return rval;
+}
+
+//
+// T338ReadBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiReadBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+#pragma optimize("",off)
+USHORT T338ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // use slow mode for small xfers (inquiry type commands) and audio
+
+ if (len % 512) {
+ return ScsiReadBytesSlow (g, pbytes, len,
+ pActualLen, phase);
+ }
+
+ // start dma read
+
+ N5380EnableDmaRead (g);
+
+ // put the t338 into read mode
+
+ T338PutControl (g,T338_IOR,0);
+
+ // to be fast, for 386 machines, this must be coded in assembly
+ // for inline assembly, we don't have to save eax-edx registers
+ {
+ ULONG xfer_count = len;
+ PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
+
+ _asm {
+ push esi
+ push ds
+#ifdef MODE_32BIT
+ mov edx, baseIoAddress
+ mov esi,pbytes
+ mov ecx,len
+#else
+ mov dx, word ptr baseIoAddress
+ mov si, word ptr pbytes
+ mov cx, word ptr len
+ mov ds, word ptr pbytes+2
+#endif // MODE_32BIT
+ inc dx // dx points to status register
+
+ get_bytes:
+ in al,dx
+ test al,P_BUSY
+ jnz big_wait
+
+ ready:
+
+ // assert DACK, the P_AFX bit
+
+ inc dx // dx points to control register
+ mov al,P_AFX
+ out dx,al
+
+ // select high nibble
+
+ sub dx,2 // dx points to data register
+ mov al,0x80
+ out dx,al
+
+ // get high nibble
+
+ inc dx // dx points to status register
+ in al,dx
+ mov ah,al
+
+ // select lower nibble
+
+ dec dx // dx points to data register
+ xor al,al
+ out dx,al
+
+ // calculate high nibble
+
+ shl ah,1
+ and ah,0f0h
+
+ // get lower nibble
+
+ inc dx // dx points to status register
+ in al,dx
+ mov bh,al
+
+ // deassert DACK, clear P_AFX
+
+ inc dx // dx points to control register
+ xor al,al
+ out dx,al
+
+ dec dx // dx points to status register
+
+ // compute low nibble and the whole byte
+
+ shr bh,1
+ shr bh,1
+ shr bh,1
+ and bh,0fh
+ or ah,bh
+ mov al,ah
+
+
+ // store data and loop
+
+ mov [esi],al
+ inc esi
+ dec ecx
+ jnz get_bytes
+ }
+ goto done_asm;
+ _asm {
+big_wait:
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ // wait for a while before going to a bigger timeout
+ push ecx
+ push ebx
+ mov ebx,TIMEOUT_READWRITE_LOOP
+ loop0:
+ mov ecx,0x10000
+ loop1:
+ in al,dx
+ test al,P_BUSY
+ jz ready1
+ in al,dx
+ test al,P_BUSY
+ jz ready1
+
+ dec ecx
+ jnz loop1
+ dec ebx
+ jnz loop0
+ pop ebx
+ pop ecx
+ jmp short error
+ ready1:
+ pop ebx
+ pop ecx
+ }
+ goto ready;
+ _asm {
+ error:
+ mov rval,RET_STATUS_TIMEOUT
+ done_asm:
+ pop ds
+ pop esi
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ }
+
+ // compute actual xfer len
+
+ *pActualLen = len - xfer_count;
+ }
+
+ // zero control register, disable read dma mode
+ ParallelPortPut (g->BaseIoAddress,PARALLEL_CONTROL,0);
+
+ // clear the dma read mode
+ N5380DisableDmaRead (g);
+
+ // if data underrun, return the under/over run error message
+
+ if (rval) {
+ UCHAR tmp;
+
+ // phase mismatch means data under/over run
+
+ N5380GetPhase (g,&tmp);
+
+ if (tmp == PHASE_STATUS) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ }
+ }
+
+ return rval;
+}
+
+#pragma optimize("",on)
+
+//
+// N5380PortPut
+//
+// This routine is used by the N5380.C module to write byte to a 5380
+// controller. This allows the module to be card independent. Other
+// modules that assume a N5380 may also use this function.
+//
+VOID N5380PortPut (PADAPTER_INFO g,UCHAR reg,UCHAR byte)
+{
+
+ // set T338 logic into data write mode
+
+ T338PutControl (g, T338_IOW, reg);
+
+ // write the byte
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_DATA, byte);
+
+ // toggle the strobe line
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, P_STB);
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, 0);
+
+ // clear data write mode
+
+ T338PutControl (g, 0, 0);
+}
+
+
+//
+// N5380PortGet
+//
+// This routine is used by the N5380.C module to get a byte from a 5380
+// controller. This allows the module to be card independent. Other
+// modules that assume a N5380 may also use this function.
+//
+
+VOID N5380PortGet (PADAPTER_INFO g, UCHAR reg, PUCHAR byte)
+{
+ UCHAR tmp,tmp1;
+
+ // set T338 logic to read mode
+
+ T338PutControl (g, T338_IOR, reg);
+
+ // select high nibble
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_DATA, 0x80);
+
+ // assert stb
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, P_STB);
+
+ // read high nibble
+
+ ParallelPortGet (g->BaseIoAddress, PARALLEL_STATUS, &tmp);
+
+ // compute high nibble
+
+ tmp = (tmp << 1) & 0xf0;
+
+ // select low nibble
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_DATA, 0x00);
+
+ // read low nibble
+
+ ParallelPortGet (g->BaseIoAddress, PARALLEL_STATUS, &tmp1);
+
+ // compute low nibble
+
+ tmp1 = (tmp1 >> 3) & 0x0f;
+
+ // compute and return byte
+
+ *byte = tmp1 | tmp;
+
+ // clear slc
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, 0);
+
+ // clear data read mode
+
+ T338PutControl (g, 0, 0);
+}
+
+
diff --git a/private/ntos/miniport/trantor/winnt/dirs b/private/ntos/miniport/trantor/winnt/dirs
new file mode 100644
index 000000000..a8bf898ff
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/dirs
@@ -0,0 +1,27 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=t128 \
+ t13b \
+ tmv1
+
+
diff --git a/private/ntos/miniport/trantor/winnt/include/osdefs.h b/private/ntos/miniport/trantor/winnt/include/osdefs.h
new file mode 100644
index 000000000..4dd9981e7
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/include/osdefs.h
@@ -0,0 +1,15 @@
+#ifndef _OSDEFS_H
+#define _OSDEFS_H
+
+#define WINNT 1
+#define MODE_32BIT 1
+#define DEBUG_LEVEL 1
+
+#include "miniport.h"
+#include "scsi.h"
+#include "typedefs.h"
+#include "trantor.h"
+#include "status.h"
+
+#endif // _OSDEFS_H
+
diff --git a/private/ntos/miniport/trantor/winnt/source/trantor.c b/private/ntos/miniport/trantor/winnt/source/trantor.c
new file mode 100644
index 000000000..7324d49c6
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/source/trantor.c
@@ -0,0 +1,1556 @@
+/*++
+
+Copyright (c) 1990 Trantor Systems Ltd.
+
+Module Name:
+
+ Trantor.c
+
+Abstract:
+
+ This is the port driver for the Trantor SCSI Adapters.
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+//
+// 09-01-92 KJB First.
+// 01-12-93 KJB Added AddressRange structure to determine resources used.
+// 02-18-93 KJB Merged in Timer support for next NT beta. Now if
+// interrupt jumpers are not set it will still work.
+// 02-18-93 KJB Merged in Null Driver Entry for non 386 platforms. Now
+// a null stub driver will be created for non 386 cpus.
+// 02-24-93 KJB Fixed problem receving SRB Abort requests.
+// 03-04-93 KJB Fixed problem with transfer size > 0xffff.
+// 04-05-93 KJB Added TranslateError code to compile with new lower
+// level models.
+// Changed DebugPrint level from 0 to DEBUG_LEVEL
+// 05-14-93 KJB Merged Trantor code with these Microsoft changes.
+// Changed code to use new lower level driver interface.
+// Now allows a workspace to be passed to lower level
+// driver on a per-card basis. Lower level driver does
+// not need to use any non-constant static variables.
+// A PINIT structure is passed down during CheckAdapter
+// to allow for initialization parameters such as forcing
+// an interrupt level to be used, or a parallel port type.
+// CardParseCommandString function is used to initialize
+// the PINIT structure and allow for special per-card
+// parsing.
+// 05-17-93 KJB Moved call to TrantorDetermineInstalled to after the
+// registry has been parsed.
+//
+--*/
+
+#include "miniport.h"
+#include "scsi.h"
+
+#define WINNT 1
+#include "cardlib.h"
+
+//
+// Local Functions
+//
+USHORT TranslateErrorCode(USHORT rval);
+
+//
+// Local Defines
+//
+#define HOST_ID 0x07
+
+#define DEBUG_LEVEL 3
+
+//
+// For non 386 machines, we won't even build a real driver
+// We will just return an error code indicating that the driver
+// did not load.
+//
+#ifndef i386
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+{
+ return 0xC000000e;
+}
+
+//
+// This is a bit of a hack to get unresolved externals resolved.
+//
+
+VOID
+TrantorLogError(
+ IN PBASE_REGISTER IoAddress,
+ IN USHORT TrantorErrorCode,
+ IN ULONG UniqueId
+ )
+{
+ return;
+}
+
+#else
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+
+typedef struct _NONCACHED_EXTENSION {
+ int junk;
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ //
+ // NonCached extension
+ //
+
+ PNONCACHED_EXTENSION NoncachedExtension;
+
+ //
+ // Adapter parameters
+ //
+
+ PBASE_REGISTER BaseIoAddress;
+
+ //
+ // Host Target id.
+ //
+
+ UCHAR HostTargetId;
+
+ //
+ // Counter values for timer.
+ //
+
+ BOOLEAN ExpectingInterrupt;
+ BOOLEAN NotifiedConfigurationError;
+
+ USHORT ContinueTimer;
+ USHORT TimerCaughtInterrupt;
+
+ //
+ // The SCSI Srb that is being worked on..
+ //
+ PSCSI_REQUEST_BLOCK Srb;
+
+ //
+ // the TSRB that is being sent
+ //
+ TSRB tsrb;
+
+ //
+ // The following structure is using to initialize the lower
+ // level driver. It contains informations such as the interrupt
+ // level and the type of parallel port.
+ //
+ INIT Init;
+
+ //
+ // A workspace used by the lower level on a per-card
+ // basis. All static information needed is stored here.
+ //
+ // NOTE: this array must be at the END of the DEVICE_EXTENSION
+ // since it's size is > 2. The size is determined and added onto
+ // the DEVICE_EXTENSION.
+ //
+ UCHAR pWorkspace[2];
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+//
+// Logical unit extension
+//
+
+typedef struct _HW_LU_EXTENSION {
+ PSCSI_REQUEST_BLOCK CurrentSrb;
+} HW_LU_EXTENSION, *PHW_LU_EXTENSION;
+
+//
+// Function declarations
+//
+// Functions that start with 'Trantor' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+TrantorEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+TrantorDetermineInstalled(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount,
+ OUT PBOOLEAN Again
+ );
+
+ULONG
+TrantorFindAdapter (
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+TrantorHwInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+TrantorStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+VOID
+TrantorTimer(
+ PVOID Context
+ );
+
+BOOLEAN
+TrantorInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+TrantorResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+VOID
+ExecuteSrb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK srb
+ );
+
+void DumpBytes(void *cp, int len);
+
+
+
+//
+// This is a bit restrictive. This will only hold information about the first
+// four adapters in the system. This means errors on the fifth and greater
+// adapters will not get logged.
+//
+
+#define NUMBER_HELD_EXTENSIONS 4
+
+TrantorAddressToExtensionIndex = 0;
+
+struct _EXTENSION_MAP {
+ PBASE_REGISTER IoAddress;
+ PVOID DeviceExtension;
+} TrantorAddressToExtensionMap[NUMBER_HELD_EXTENSIONS];
+
+VOID
+TrantorLogError(
+ IN PBASE_REGISTER IoAddress,
+ IN USHORT TrantorErrorCode,
+ IN ULONG UniqueId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine translates the Trantor based error value into an NT
+ error value and calls the port driver to log the error.
+
+Arguments:
+
+ TrantorErrorCode - The Trantor defined error value.
+ UniqueValue - A unique value for the error. This allows
+ the same error to be returned from multiple
+ places.
+
+Return Values:
+
+ None
+
+--*/
+
+{
+ USHORT error;
+ ULONG index;
+ PHW_DEVICE_EXTENSION deviceExtension = NULL;
+
+ for (index = 0; index < NUMBER_HELD_EXTENSIONS; index++) {
+ if (TrantorAddressToExtensionMap[index].IoAddress == IoAddress) {
+ deviceExtension = TrantorAddressToExtensionMap[index].DeviceExtension;
+ break;
+ }
+ }
+
+ if (deviceExtension == NULL) {
+ return;
+ }
+
+ switch (TrantorErrorCode) {
+ case RET_STATUS_PARITY_ERROR:
+ error = SP_BUS_PARITY_ERROR;
+ break;
+ case RET_STATUS_DATA_OVERRUN:
+ error = SP_PROTOCOL_ERROR;
+ break;
+ case RET_STATUS_PHASE_SEQ_FAILURE:
+ case RET_STATUS_UNEXPECTED_BUS_FREE:
+ error = SP_PROTOCOL_ERROR;
+ break;
+ case RET_STATUS_TIMEOUT:
+ case RET_STATUS_SELECTION_TIMEOUT:
+ error = SP_BUS_TIME_OUT;
+ break;
+ default:
+ error = SP_INTERNAL_ADAPTER_ERROR;
+ break;
+ }
+ ScsiPortLogError(deviceExtension,
+ deviceExtension->Srb,
+ 0,
+ 0,
+ 0,
+ error,
+ UniqueId);
+}
+
+
+ULONG
+TrantorParseArgumentString(
+ IN PCHAR String,
+ IN PCHAR KeyWord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will parse the string for a match on the keyword, then
+ calculate the value for the keyword and return it to the caller.
+
+Arguments:
+
+ String - The ASCII string to parse.
+ KeyWord - The keyword for the value desired.
+
+Return Values:
+
+ Zero if value not found
+ Value converted from ASCII to binary.
+
+--*/
+
+{
+ PCHAR cptr;
+ PCHAR kptr;
+ ULONG value;
+ ULONG stringLength = 0;
+ ULONG keyWordLength = 0;
+ ULONG index;
+
+ //
+ // Calculate the string length and lower case all characters.
+ //
+ cptr = String;
+ while (*cptr) {
+
+ if (*cptr >= 'A' && *cptr <= 'Z') {
+ *cptr = *cptr + ('a' - 'A');
+ }
+ cptr++;
+ stringLength++;
+ }
+
+ //
+ // Calculate the keyword length and lower case all characters.
+ //
+ cptr = KeyWord;
+ while (*cptr) {
+
+ if (*cptr >= 'A' && *cptr <= 'Z') {
+ *cptr = *cptr + ('a' - 'A');
+ }
+ cptr++;
+ keyWordLength++;
+ }
+
+ if (keyWordLength > stringLength) {
+
+ //
+ // Can't possibly have a match.
+ //
+ return 0;
+ }
+
+ //
+ // Now setup and start the compare.
+ //
+ cptr = String;
+
+ContinueSearch:
+ //
+ // The input string may start with white space. Skip it.
+ //
+ while (*cptr == ' ' || *cptr == '\t') {
+ cptr++;
+ }
+
+ if (*cptr == '\0') {
+
+ //
+ // end of string.
+ //
+ return 0;
+ }
+
+ kptr = KeyWord;
+ while (*cptr++ == *kptr++) {
+
+ if (*(cptr - 1) == '\0') {
+
+ //
+ // end of string
+ //
+ return 0;
+ }
+ }
+
+ if (*(kptr - 1) == '\0') {
+
+ //
+ // May have a match backup and check for blank or equals.
+ //
+
+ cptr--;
+ while (*cptr == ' ' || *cptr == '\t') {
+ cptr++;
+ }
+
+ //
+ // Found a match. Make sure there is an equals.
+ //
+ if (*cptr != '=') {
+
+ //
+ // Not a match so move to the next semicolon.
+ //
+ while (*cptr) {
+ if (*cptr++ == ';') {
+ goto ContinueSearch;
+ }
+ }
+ return 0;
+ }
+
+ //
+ // Skip the equals sign.
+ //
+ cptr++;
+
+ //
+ // Skip white space.
+ //
+ while ((*cptr == ' ') || (*cptr == '\t')) {
+ cptr++;
+ }
+
+ if (*cptr == '\0') {
+
+ //
+ // Early end of string, return not found
+ //
+ return 0;
+ }
+
+ if (*cptr == ';') {
+
+ //
+ // This isn't it either.
+ //
+ cptr++;
+ goto ContinueSearch;
+ }
+
+ value = 0;
+ if ((*cptr == '0') && (*(cptr + 1) == 'x')) {
+
+ //
+ // Value is in Hex. Skip the "0x"
+ //
+ cptr += 2;
+ for (index = 0; *(cptr + index); index++) {
+
+ if (*(cptr + index) == ' ' ||
+ *(cptr + index) == '\t' ||
+ *(cptr + index) == ';') {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
+ value = (16 * value) + (*(cptr + index) - '0');
+ } else {
+ if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
+ value = (16 * value) + (*(cptr + index) - 'a' + 10);
+ } else {
+
+ //
+ // Syntax error, return not found.
+ //
+ return 0;
+ }
+ }
+ }
+ } else {
+
+ //
+ // Value is in Decimal.
+ //
+ for (index = 0; *(cptr + index); index++) {
+
+ if (*(cptr + index) == ' ' ||
+ *(cptr + index) == '\t' ||
+ *(cptr + index) == ';') {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
+ value = (10 * value) + (*(cptr + index) - '0');
+ } else {
+
+ //
+ // Syntax error return not found.
+ //
+ return 0;
+ }
+ }
+ }
+
+ return value;
+ } else {
+
+ //
+ // Not a match check for ';' to continue search.
+ //
+ while (*cptr) {
+ if (*cptr++ == ';') {
+ goto ContinueSearch;
+ }
+ }
+
+ return 0;
+ }
+}
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+//
+// Delay for 10 us for interrupt timer.
+// Every 100 ms, we will receive a timer interrupt to poll our interrupt
+// routine. Our driver will thus work if interrupts are incorrectly
+// configured.
+//
+
+#define TRANTOR_TIMER_VALUE 10000
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG adapterCount;
+ ULONG isaStatus;
+ ULONG mcaStatus;
+ ULONG i;
+
+ DebugPrint((DEBUG_LEVEL,"\n\nSCSI Trantor MiniPort Driver\n"));
+
+ //
+ // Initialize Trantor Globals.
+ //
+
+ for (i = 0; i < NUMBER_HELD_EXTENSIONS; i++) {
+ TrantorAddressToExtensionMap[i].IoAddress = (PBASE_REGISTER) 0;
+ TrantorAddressToExtensionMap[i].DeviceExtension = (PVOID) NULL;
+ }
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = TrantorHwInitialize;
+ hwInitializationData.HwResetBus = TrantorResetBus;
+ hwInitializationData.HwStartIo = TrantorStartIo;
+ hwInitializationData.HwInterrupt = TrantorInterrupt;
+ hwInitializationData.HwFindAdapter = TrantorFindAdapter;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = FALSE;
+ hwInitializationData.MapBuffers = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ // the adapter needs some workspace this workspace varies from adapter
+ // to adapter, we will tack this space onto the end of the
+ // deviceExtension.
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION) +
+ CardGetWorkspaceSize();
+ hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
+
+ //
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = Isa;
+ hwInitializationData.NumberOfAccessRanges = CardNumberOfAddressRanges();
+
+ //
+ // Ask for SRB extensions for CCBs, not used.
+ //
+
+ hwInitializationData.SrbExtensionSize = 0;
+
+ //
+ // The adapter count is used by the find adapter routine to track how
+ // which adapter addresses have been tested.
+ //
+
+ adapterCount = 0;
+
+ isaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount);
+
+ //
+ // Now try to configure for the Mca bus.
+ // Specifiy the bus type.
+ //
+
+ hwInitializationData.AdapterInterfaceType = MicroChannel;
+ adapterCount = 0;
+ mcaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount);
+
+ //
+ // Return the smaller status.
+ //
+
+ return(mcaStatus < isaStatus ? mcaStatus : isaStatus);
+
+} // end TrantorEntry()
+
+
+ULONG
+TrantorFindAdapter (
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Context - Register base address
+ ConfigInfo - Configuration information structure describing HBA
+ This structure is defined in PORT.H.
+
+Return Value:
+
+ ULONG
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG status;
+
+ //
+ // Argument string is the registry entry for DriverParameter
+ // in the Device key under the driver. The registry looks like:
+ // Txxx
+ // Parameters
+ // Device0
+ // DriverParameter = IRQ=5
+ //
+ if (ArgumentString) {
+
+ ULONG irq = TrantorParseArgumentString(ArgumentString, "irq");
+
+ if (irq == 0) {
+
+ //
+ // Check for the old way.
+ //
+ irq = *((PULONG)ArgumentString);
+ if (irq > 15) {
+
+ //
+ // really was intended to be zero.
+ //
+ irq = 0;
+
+ } else {
+ irq = CardDefaultInterruptLevel();
+ }
+ }
+
+ ConfigInfo->BusInterruptLevel = irq;
+
+ } else {
+ if (ConfigInfo->BusInterruptLevel == 0) {
+
+ // use our default
+ ConfigInfo->BusInterruptLevel = CardDefaultInterruptLevel();
+ } // else
+ }
+
+ //
+ // set up our pInit structure with the appropriate information from
+ // the command line.
+ // Other info from cmd line such as parallel port type should
+ // go here too.
+ //
+
+ // for now, init the pInit structure, use no command string
+ // this sets up the init structure with all defaults.
+ // later we will want to get string from registry.
+
+ CardParseCommandString(&deviceExtension->Init,NULL);
+ deviceExtension->Init.InterruptLevel = (UCHAR) ConfigInfo->BusInterruptLevel;
+
+ ConfigInfo->NumberOfBuses = 1;
+ ConfigInfo->InitiatorBusId[0] = HOST_ID; // our adapter is at id HOST_ID
+ deviceExtension->HostTargetId = HOST_ID;
+
+ ConfigInfo->MaximumTransferLength = CardMaxTransferSize();
+ ConfigInfo->ScatterGather = FALSE;
+ ConfigInfo->Master = FALSE;
+ ConfigInfo->NumberOfPhysicalBreaks = 16;
+
+ TrantorAddressToExtensionMap[TrantorAddressToExtensionIndex].IoAddress =
+ deviceExtension->BaseIoAddress;
+ TrantorAddressToExtensionMap[TrantorAddressToExtensionIndex].DeviceExtension = HwDeviceExtension;
+
+ //
+ // Determine if there are any adapters installed. Determine installed
+ // will initialize the BaseIoAddress if an adapter is found.
+ //
+
+ status = TrantorDetermineInstalled(deviceExtension,
+ ConfigInfo,
+ Context,
+ Again);
+
+ //
+ // If there are not adapter's found then return.
+ //
+
+ if (status != SP_RETURN_FOUND) {
+ return(status);
+ }
+
+ DebugPrint((DEBUG_LEVEL,"TrantorFindAdapter: Configuration completed\n"));
+ return SP_RETURN_FOUND;
+} // end TrantorFindAdapter()
+
+
+ULONG
+TrantorDetermineInstalled(
+ IN PHW_DEVICE_EXTENSION HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if Trantor SCSI adapter is installed in system
+ by reading the status register as each base I/O address
+ and looking for a pattern. If an adapter is found, the BaseIoAddres is
+ initialized.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+ ConfigInfo - Supplies the known configuraiton information.
+
+ AdapterCount - Supplies the count of adapter slots which have been tested.
+
+ Again - Returns whehter the OS specific driver should call again.
+
+Return Value:
+
+ Returns a status indicating whether a driver is present or not.
+
+--*/
+
+{
+ PBASE_REGISTER baseIoAddress;
+ PUCHAR ioSpace;
+ PUCHAR fullIoSpace = NULL;
+ ULONG address;
+ PINIT pInit = &HwDeviceExtension->Init;
+ PWORKSPACE pWorkspace = HwDeviceExtension->pWorkspace;
+
+ //
+ // Scan though the adapter address looking for adapters.
+ //
+
+ if (CardAddressRangeLength() == 0xffff) {
+
+ //
+ // Card detection requires that the complete I/O space be mapped.
+ //
+
+ fullIoSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0),
+ 0xFFFF,
+ CardAddressRangeInIoSpace());
+ }
+
+ while ((address = (ULONG)CardAddress((USHORT)(*AdapterCount))) != 0) {
+
+ DebugPrint((DEBUG_LEVEL,"Trantor: Checking for adapter at %x\n", address));
+
+ //
+ // Get the system physical address for this card. The card uses I/O space.
+ //
+
+ ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(address),
+ CardAddressRangeLength(),
+ CardAddressRangeInIoSpace());
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ baseIoAddress = (PBASE_REGISTER)(ioSpace);
+
+ //
+ // Update the adapter count.
+ //
+
+ (*AdapterCount)++;
+
+ pInit->BaseIoAddress = baseIoAddress;
+ if (ioSpace != NULL && CardCheckAdapter(pWorkspace, pInit)) {
+
+ DebugPrint((DEBUG_LEVEL,"Trantor: Base IO address is %x\n", baseIoAddress));
+
+ //
+ // An adapter has been found. Set the base address in the device
+ // extension, and request another call.
+ //
+
+ HwDeviceExtension->BaseIoAddress = baseIoAddress;
+ HwDeviceExtension->Srb = NULL; // no Srb's pending for this device
+ *Again = TRUE;
+
+
+ //
+ // Set up the variables that control the timer.
+ //
+
+ HwDeviceExtension->ExpectingInterrupt = FALSE;
+ HwDeviceExtension->NotifiedConfigurationError = FALSE;
+ HwDeviceExtension->ContinueTimer = 5;
+ HwDeviceExtension->TimerCaughtInterrupt = 5;
+
+ //
+ // Fill in the access array information.
+ //
+
+ {
+ ULONG i;
+ for (i=0;i<CardNumberOfAddressRanges();i++) {
+ (*ConfigInfo->AccessRanges)[i].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(address+cardAddressRange[i].offset);
+ (*ConfigInfo->AccessRanges)[i].RangeLength = cardAddressRange[i].length;
+ (*ConfigInfo->AccessRanges)[i].RangeInMemory = cardAddressRange[i].memory;
+ }
+ }
+
+ // The device base should not be freed.
+ // but the full io space is freed if it was allocated.
+
+ if (fullIoSpace != NULL) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ fullIoSpace);
+ }
+ return(SP_RETURN_FOUND);
+ } else {
+ DebugPrint((DEBUG_LEVEL,"Trantor: Not at Base IO address %x\n", baseIoAddress));
+ }
+
+ // The device base can now be freed.
+ if (ioSpace != NULL) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ ioSpace);
+ }
+ }
+
+ //
+ // The entire table has been searched and no adapters have been found.
+ // Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *(AdapterCount) = 0;
+
+ if (fullIoSpace != NULL) {
+ ScsiPortFreeDeviceBase(HwDeviceExtension,
+ fullIoSpace);
+ }
+ return(SP_RETURN_NOT_FOUND);
+
+} // end TrantorDetermineInstalled()
+
+
+BOOLEAN
+TrantorHwInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a required entry point.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ DebugPrint((DEBUG_LEVEL,"TrantorHwInitialize: Do Nothing\n"));
+
+ return TRUE;
+
+} // end TrantorHwInitialize()
+
+void DumpBytes(void *vp, int len)
+ {
+ static int cnt = 10000;
+ unsigned char *cp = vp;
+ int i;
+ if (!cnt)
+ return;
+ else cnt--;
+ for (i=0;i<len;i++) {
+ if (!(i%16) && i)
+ DebugPrint((DEBUG_LEVEL,"\n"));
+ DebugPrint((DEBUG_LEVEL,"%02x ",cp[i]));
+ }
+ DebugPrint((DEBUG_LEVEL,"\n"));
+ }
+
+VOID
+TrantorTimer(
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will use the ScsiPort provided timer support to monitor
+ the hardware. This is done to insure operation of the miniport even
+ when the hardware is working in a polled mode or when it is configured
+ for an interrupt other than the one the driver expects.
+
+Arguments:
+
+ Context - Device adapter context.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION) Context;
+ PWORKSPACE pWorkspace = deviceExtension->pWorkspace;
+ BOOLEAN restartTimer = TRUE;
+
+ if (deviceExtension->ExpectingInterrupt == FALSE) {
+
+ //
+ // The interrupt routine got the interrupt. Decrement the number
+ // of times to continue scheduling a timer routine.
+ //
+ deviceExtension->ContinueTimer--;
+ return;
+ }
+
+ if (CardInterrupt(pWorkspace)) {
+
+ // If the interrupt routine does not claim this interrupt for some
+ // reason, restart the timer. If it does claim the interrupt, shut
+ // off the timer.
+ //
+ restartTimer = TrantorInterrupt(Context) == FALSE ? TRUE : FALSE;
+
+ //
+ // Now determine if an event log entry should be made to inform
+ // the system administrator that there is a possible configuration
+ // error on this driver.
+ //
+ if ((restartTimer == FALSE) &&
+ (deviceExtension->NotifiedConfigurationError == FALSE)) {
+ deviceExtension->TimerCaughtInterrupt--;
+ if (deviceExtension->TimerCaughtInterrupt == 0) {
+ ScsiPortLogError(deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_IRQ_NOT_RESPONDING,
+ (ULONG) deviceExtension);
+ deviceExtension->NotifiedConfigurationError = TRUE;
+ }
+ }
+ }
+
+ if (restartTimer == TRUE) {
+
+ //
+ // Not selected. Set timer for another call.
+ //
+ ScsiPortNotification(RequestTimerCall,
+ deviceExtension,
+ TrantorTimer,
+ TRANTOR_TIMER_VALUE);
+ }
+
+}
+
+BOOLEAN
+TrantorStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel. The Device is selected and the command sent.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PNONCACHED_EXTENSION noncachedExtension =
+ deviceExtension->NoncachedExtension;
+ PHW_LU_EXTENSION luExtension;
+ ULONG i = 0;
+
+ DebugPrint((DEBUG_LEVEL, "IO:"));
+ //
+ // Check if command is an ABORT request.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+ DebugPrint((DEBUG_LEVEL, "TrantorStartIo: SRB to abort already completed\n"));
+
+ // for an abort, we will do a reset bus
+ CardResetBus(deviceExtension->pWorkspace);
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR) Srb->PathId,
+ (UCHAR) -1,
+ (UCHAR) -1,
+ SRB_STATUS_BUS_RESET);
+
+
+//
+// Complete requests above does this
+//
+// ScsiPortNotification(RequestComplete,
+// deviceExtension,
+// Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ } else {
+ }
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((DEBUG_LEVEL, "TrantorStartIo: Abort request received\n"));
+
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset trantor card and SCSI bus.
+ //
+
+ DebugPrint((DEBUG_LEVEL, "TrantorStartIo: Reset bus request received\n"));
+
+ if (!TrantorResetBus(
+ deviceExtension,
+ Srb->PathId
+ )) {
+
+ DebugPrint((DEBUG_LEVEL,"TrantorStartIo: Reset bus failed\n"));
+
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+
+ } else {
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+
+//
+// TrantorResetBus does notification of all requests completes
+//
+// ScsiPortNotification(RequestComplete,
+// deviceExtension,
+// Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Get logical unit extension.
+ //
+
+ luExtension =
+ ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ //
+ // Move SRB to logical unit extension.
+ //
+
+ luExtension->CurrentSrb = Srb;
+
+ //
+ // Execute CCB.
+ //
+
+ ExecuteSrb(deviceExtension,Srb);
+
+ if (Srb->SrbStatus != SRB_STATUS_PENDING) {
+ //
+ // Notify of completion
+ //
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ } else {
+
+ if (deviceExtension->ContinueTimer != 0) {
+
+ // set for a timer interrupt in case interrupt does
+ // not come
+
+ deviceExtension->ExpectingInterrupt = TRUE;
+ ScsiPortNotification(RequestTimerCall,
+ deviceExtension,
+ TrantorTimer,
+ TRANTOR_TIMER_VALUE);
+ }
+ }
+
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ DebugPrint((DEBUG_LEVEL,"TrantorStartIo: Reset device not supported\n"));
+
+ //
+ // Drop through to default.
+ //
+
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ return TRUE;
+
+} // end TrantorStartIo()
+
+
+BOOLEAN
+TrantorInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the Trantor SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PWORKSPACE pWorkspace = deviceExtension->pWorkspace;
+ PSCSI_REQUEST_BLOCK srb = deviceExtension->Srb;
+ PTSRB t = &deviceExtension->tsrb;
+ USHORT rval;
+
+ // is there an interrupt from our card??
+ if (CardInterrupt(pWorkspace)) {
+
+ // Got the interrupt that was expected.
+ deviceExtension->ExpectingInterrupt = FALSE;
+
+ // is there a pending Srb??
+ if (srb) {
+
+ // finish the Srb, the tsrb is already set up.
+
+ rval = CardFinishCommandInterrupt(t);
+
+ srb->DataTransferLength = t->ActualDataLen;
+ srb->ScsiStatus = t->Status;
+
+ srb->SrbStatus = (UCHAR) TranslateErrorCode(rval);
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ // clear the pending srb from this device
+ deviceExtension->Srb = NULL;
+ }
+
+ // return true if it was our interrupt
+ return TRUE;
+ }
+
+ // not our interrupt, return false
+ return FALSE;
+
+} // end TrantorInterrupt()
+
+
+VOID
+ExecuteSrb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK srb
+ )
+
+/*++
+
+Routine Description:
+
+ Execute an Srb.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PWORKSPACE pWorkspace = DeviceExtension->pWorkspace;
+ USHORT rval;
+ PTSRB t = &DeviceExtension->tsrb;
+
+ // allow interrupts to occur
+ // send the command to our lower level driver
+ t->pWorkspace = pWorkspace;
+ t->Target = srb->TargetId;
+ t->Lun = srb->Lun;
+ t->pCommand = srb->Cdb;
+ t->CommandLen = srb->CdbLength;
+ t->Dir = (srb->SrbFlags & SRB_FLAGS_DATA_OUT ?
+ TSRB_DIR_OUT : TSRB_DIR_IN);
+ t->pData = srb->DataBuffer;
+ t->DataLen = srb->DataTransferLength;
+ t->Flags.DoRequestSense = FALSE;
+ rval = CardStartCommandInterrupt(t);
+
+ // if status pending, we are waiting for interrupt, save srb pointer
+
+ if (rval == RET_STATUS_PENDING) {
+ DeviceExtension->Srb = srb;
+ } else if (rval == RET_STATUS_MISSED_INTERRUPT) {
+
+ // if the device is ready, finish the command.
+
+ rval = CardFinishCommandInterrupt(t);
+ }
+
+ srb->SrbStatus = (UCHAR) TranslateErrorCode(rval);
+
+ return;
+} // end ExecuteSrb()
+
+
+BOOLEAN
+TrantorResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ )
+
+/*++
+
+Routine Description:
+
+ Reset Trantor SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+
+ CardResetBus(deviceExtension->pWorkspace);
+ DebugPrint((DEBUG_LEVEL,"ResetBus: Reset Trantor Adapter and SCSI bus\n"));
+
+// DbgBreakPoint();
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)PathId,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ (UCHAR)SRB_STATUS_BUS_RESET);
+
+ return TRUE;
+
+} // end TrantorResetBus()
+
+//
+// TranslateErrorCode
+//
+// This routine translates the error code returned from the lower level
+// library to the NT specific error code.
+//
+USHORT TranslateErrorCode(USHORT rval)
+{
+ switch (rval) {
+ case RET_STATUS_PENDING:
+ return SRB_STATUS_PENDING;
+ case RET_STATUS_SUCCESS:
+ return SRB_STATUS_SUCCESS;
+ case RET_STATUS_ABORTED:
+ return SRB_STATUS_ABORTED;
+ case RET_STATUS_ABORT_FAILED:
+ return SRB_STATUS_ABORT_FAILED;
+ case RET_STATUS_ERROR:
+ return SRB_STATUS_ERROR;
+ case RET_STATUS_BUSY:
+ return SRB_STATUS_BUSY;
+ case RET_STATUS_INVALID_REQUEST:
+ return SRB_STATUS_INVALID_REQUEST;
+ case RET_STATUS_INVALID_PATH_ID:
+ return SRB_STATUS_INVALID_PATH_ID;
+ case RET_STATUS_NO_DEVICE:
+ return SRB_STATUS_NO_DEVICE;
+ case RET_STATUS_TIMEOUT:
+ return SRB_STATUS_TIMEOUT;
+ case RET_STATUS_SELECTION_TIMEOUT:
+ return SRB_STATUS_SELECTION_TIMEOUT;
+ case RET_STATUS_COMMAND_TIMEOUT:
+ return SRB_STATUS_COMMAND_TIMEOUT;
+ case RET_STATUS_MESSAGE_REJECTED:
+ return SRB_STATUS_MESSAGE_REJECTED;
+ case RET_STATUS_BUS_RESET:
+ return SRB_STATUS_BUS_RESET;
+ case RET_STATUS_PARITY_ERROR:
+ return SRB_STATUS_PARITY_ERROR;
+ case RET_STATUS_REQUEST_SENSE_FAILED:
+ return SRB_STATUS_REQUEST_SENSE_FAILED;
+ case RET_STATUS_NO_HBA:
+ return SRB_STATUS_NO_HBA;
+ case RET_STATUS_DATA_OVERRUN:
+ return SRB_STATUS_DATA_OVERRUN;
+ case RET_STATUS_UNEXPECTED_BUS_FREE:
+ return SRB_STATUS_UNEXPECTED_BUS_FREE;
+ case RET_STATUS_PHASE_SEQ_FAILURE:
+ return SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ case RET_STATUS_BAD_SRB_BLOCK_LENGTH:
+ return SRB_STATUS_BAD_SRB_BLOCK_LENGTH;
+ case RET_STATUS_REQUEST_FLUSHED:
+ return SRB_STATUS_REQUEST_FLUSHED;
+ case RET_STATUS_INVALID_LUN:
+ return SRB_STATUS_INVALID_LUN;
+ case RET_STATUS_INVALID_TARGET_ID:
+ return SRB_STATUS_INVALID_TARGET_ID;
+ case RET_STATUS_BAD_FUNCTION:
+ return SRB_STATUS_BAD_FUNCTION;
+ case RET_STATUS_ERROR_RECOVERY:
+ return SRB_STATUS_ERROR_RECOVERY;
+ case RET_STATUS_MISSED_INTERRUPT:
+ return SRB_STATUS_ERROR;
+ default:
+ return SRB_STATUS_ERROR;
+ }
+ return SRB_STATUS_ERROR;
+}
+
+#endif // i386
diff --git a/private/ntos/miniport/trantor/winnt/t128/card.c b/private/ntos/miniport/trantor/winnt/t128/card.c
new file mode 100644
index 000000000..9650ab17d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/card.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardt128.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t128/card.h b/private/ntos/miniport/trantor/winnt/t128/card.h
new file mode 100644
index 000000000..7cf8e18d5
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/card.h
@@ -0,0 +1 @@
+#include "cardt128.h"
diff --git a/private/ntos/miniport/trantor/winnt/t128/cardutil.c b/private/ntos/miniport/trantor/winnt/t128/cardutil.c
new file mode 100644
index 000000000..a0e3193cf
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/cardutil.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardutil.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t128/makefile b/private/ntos/miniport/trantor/winnt/t128/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/trantor/winnt/t128/n5380.c b/private/ntos/miniport/trantor/winnt/t128/n5380.c
new file mode 100644
index 000000000..174801d6b
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/n5380.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\n5380.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t128/port.c b/private/ntos/miniport/trantor/winnt/t128/port.c
new file mode 100644
index 000000000..a380b5cd6
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/port.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\port.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t128/portmem.c b/private/ntos/miniport/trantor/winnt/t128/portmem.c
new file mode 100644
index 000000000..ca8a0d099
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/portmem.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\portmem.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t128/scsifnc.c b/private/ntos/miniport/trantor/winnt/t128/scsifnc.c
new file mode 100644
index 000000000..055d4666d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/scsifnc.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\scsifnc.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t128/sources b/private/ntos/miniport/trantor/winnt/t128/sources
new file mode 100644
index 000000000..ecc98ce75
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=t128
+TARGETPATH=..\..\exe
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\..\..\inc;..\include;..\..\include
+
+C_DEFINES=/DCARDTXXX_H=\"cardt128.h\"
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES= trantor.c scsifnc.c n5380.c card.c t128.c portmem.c t128.rc \
+ cardutil.c
diff --git a/private/ntos/miniport/trantor/winnt/t128/t128.c b/private/ntos/miniport/trantor/winnt/t128/t128.c
new file mode 100644
index 000000000..b8c3dfe1b
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/t128.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\t128.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t128/t128.rc b/private/ntos/miniport/trantor/winnt/t128/t128.rc
new file mode 100644
index 000000000..c41aeb305
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/t128.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Trantor T128 SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "t128.sys"
+#define VER_ORIGINALFILENAME_STR "t128.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/trantor/winnt/t128/trantor.c b/private/ntos/miniport/trantor/winnt/t128/trantor.c
new file mode 100644
index 000000000..420122471
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t128/trantor.c
@@ -0,0 +1,2 @@
+#include "..\..\source\trantor.c"
+
diff --git a/private/ntos/miniport/trantor/winnt/t13b/card.c b/private/ntos/miniport/trantor/winnt/t13b/card.c
new file mode 100644
index 000000000..c0a69e394
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/card.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardt13b.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t13b/card.h b/private/ntos/miniport/trantor/winnt/t13b/card.h
new file mode 100644
index 000000000..8a4c56735
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/card.h
@@ -0,0 +1 @@
+#include "cardt13b.h"
diff --git a/private/ntos/miniport/trantor/winnt/t13b/cardutil.c b/private/ntos/miniport/trantor/winnt/t13b/cardutil.c
new file mode 100644
index 000000000..a0e3193cf
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/cardutil.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardutil.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t13b/makefile b/private/ntos/miniport/trantor/winnt/t13b/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/trantor/winnt/t13b/n5380.c b/private/ntos/miniport/trantor/winnt/t13b/n5380.c
new file mode 100644
index 000000000..174801d6b
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/n5380.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\n5380.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t13b/n53c400.c b/private/ntos/miniport/trantor/winnt/t13b/n53c400.c
new file mode 100644
index 000000000..35eb8fa17
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/n53c400.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\n53c400.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t13b/portio.c b/private/ntos/miniport/trantor/winnt/t13b/portio.c
new file mode 100644
index 000000000..487e619fd
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/portio.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\portio.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t13b/scsifnc.c b/private/ntos/miniport/trantor/winnt/t13b/scsifnc.c
new file mode 100644
index 000000000..055d4666d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/scsifnc.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\scsifnc.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t13b/sources b/private/ntos/miniport/trantor/winnt/t13b/sources
new file mode 100644
index 000000000..4caa038fd
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=t13b
+TARGETPATH=..\..\exe
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\..\..\inc;..\include;..\..\include
+
+C_DEFINES=/DCARDTXXX_H=\"cardt13b.h\"
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES= trantor.c scsifnc.c n5380.c n53c400.c card.c portio.c t13b.rc \
+ cardutil.c
diff --git a/private/ntos/miniport/trantor/winnt/t13b/t13b.rc b/private/ntos/miniport/trantor/winnt/t13b/t13b.rc
new file mode 100644
index 000000000..363e01420
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/t13b.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Trantor T13B SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "t13b.sys"
+#define VER_ORIGINALFILENAME_STR "t13b.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/trantor/winnt/t13b/trantor.c b/private/ntos/miniport/trantor/winnt/t13b/trantor.c
new file mode 100644
index 000000000..420122471
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t13b/trantor.c
@@ -0,0 +1,2 @@
+#include "..\..\source\trantor.c"
+
diff --git a/private/ntos/miniport/trantor/winnt/t160/card.c b/private/ntos/miniport/trantor/winnt/t160/card.c
new file mode 100644
index 000000000..2bad69bd4
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/card.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardt160.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t160/card.h b/private/ntos/miniport/trantor/winnt/t160/card.h
new file mode 100644
index 000000000..452ff23bf
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/card.h
@@ -0,0 +1 @@
+#include "cardt160.h"
diff --git a/private/ntos/miniport/trantor/winnt/t160/cardutil.c b/private/ntos/miniport/trantor/winnt/t160/cardutil.c
new file mode 100644
index 000000000..a0e3193cf
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/cardutil.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardutil.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t160/makefile b/private/ntos/miniport/trantor/winnt/t160/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/trantor/winnt/t160/n5380.c b/private/ntos/miniport/trantor/winnt/t160/n5380.c
new file mode 100644
index 000000000..174801d6b
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/n5380.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\n5380.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t160/pc9010.c b/private/ntos/miniport/trantor/winnt/t160/pc9010.c
new file mode 100644
index 000000000..81d4b8bd8
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/pc9010.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\pc9010.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t160/portio.c b/private/ntos/miniport/trantor/winnt/t160/portio.c
new file mode 100644
index 000000000..487e619fd
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/portio.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\portio.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t160/scsifnc.c b/private/ntos/miniport/trantor/winnt/t160/scsifnc.c
new file mode 100644
index 000000000..055d4666d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/scsifnc.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\scsifnc.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t160/sources b/private/ntos/miniport/trantor/winnt/t160/sources
new file mode 100644
index 000000000..8bcd93122
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/sources
@@ -0,0 +1,39 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=t160
+TARGETPATH=..\..\exe
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\..\..\inc;..\include;..\..\include
+
+C_DEFINES=/DCARDTXXX_H=\"cardt160.h\"
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+i386_SOURCES=
+
+MIPS_SOURCES=
+
+SOURCES= trantor.c scsifnc.c n5380.c card.c portio.c \
+ pc9010.c t160.rc cardutil.c
diff --git a/private/ntos/miniport/trantor/winnt/t160/t160.rc b/private/ntos/miniport/trantor/winnt/t160/t160.rc
new file mode 100644
index 000000000..054f42d28
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/t160.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Trantor T160 SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "t160.sys"
+#define VER_ORIGINALFILENAME_STR "t160.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/trantor/winnt/t160/trantor.c b/private/ntos/miniport/trantor/winnt/t160/trantor.c
new file mode 100644
index 000000000..53bdd3835
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t160/trantor.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\trantor.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/card.c b/private/ntos/miniport/trantor/winnt/t338/card.c
new file mode 100644
index 000000000..8cf51afe6
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/card.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardt338.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/card.h b/private/ntos/miniport/trantor/winnt/t338/card.h
new file mode 100644
index 000000000..259ffb20e
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/card.h
@@ -0,0 +1 @@
+#include "cardt338.h"
diff --git a/private/ntos/miniport/trantor/winnt/t338/cardutil.c b/private/ntos/miniport/trantor/winnt/t338/cardutil.c
new file mode 100644
index 000000000..a0e3193cf
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/cardutil.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardutil.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/makefile b/private/ntos/miniport/trantor/winnt/t338/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/trantor/winnt/t338/n5380.c b/private/ntos/miniport/trantor/winnt/t338/n5380.c
new file mode 100644
index 000000000..174801d6b
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/n5380.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\n5380.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/p3c.c b/private/ntos/miniport/trantor/winnt/t338/p3c.c
new file mode 100644
index 000000000..776cfab33
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/p3c.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\t338.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/parallel.c b/private/ntos/miniport/trantor/winnt/t338/parallel.c
new file mode 100644
index 000000000..5e738d22e
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/parallel.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\parallel.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/portio.c b/private/ntos/miniport/trantor/winnt/t338/portio.c
new file mode 100644
index 000000000..487e619fd
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/portio.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\portio.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/scsifnc.c b/private/ntos/miniport/trantor/winnt/t338/scsifnc.c
new file mode 100644
index 000000000..055d4666d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/scsifnc.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\scsifnc.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/sources b/private/ntos/miniport/trantor/winnt/t338/sources
new file mode 100644
index 000000000..8b28e488d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/sources
@@ -0,0 +1,39 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=t338
+TARGETPATH=..\..\exe
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\..\..\inc;..\include;..\..\include
+
+C_DEFINES=/DCARDTXXX_H=\"cardt338.h\"
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+i386_SOURCES=
+
+MIPS_SOURCES=
+
+SOURCES= trantor.c scsifnc.c n5380.c card.c parallel.c t338.c t338.rc portio.c \
+ cardutil.c
diff --git a/private/ntos/miniport/trantor/winnt/t338/t338.c b/private/ntos/miniport/trantor/winnt/t338/t338.c
new file mode 100644
index 000000000..776cfab33
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/t338.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\t338.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t338/t338.rc b/private/ntos/miniport/trantor/winnt/t338/t338.rc
new file mode 100644
index 000000000..837f12254
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/t338.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Trantor T338 SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "t338.sys"
+#define VER_ORIGINALFILENAME_STR "t338.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/trantor/winnt/t338/trantor.c b/private/ntos/miniport/trantor/winnt/t338/trantor.c
new file mode 100644
index 000000000..420122471
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t338/trantor.c
@@ -0,0 +1,2 @@
+#include "..\..\source\trantor.c"
+
diff --git a/private/ntos/miniport/trantor/winnt/t348/card.c b/private/ntos/miniport/trantor/winnt/t348/card.c
new file mode 100644
index 000000000..72d569603
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/card.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardt348.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t348/card.h b/private/ntos/miniport/trantor/winnt/t348/card.h
new file mode 100644
index 000000000..c4766df1e
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/card.h
@@ -0,0 +1 @@
+#include "cardt348.h"
diff --git a/private/ntos/miniport/trantor/winnt/t348/cardutil.c b/private/ntos/miniport/trantor/winnt/t348/cardutil.c
new file mode 100644
index 000000000..a0e3193cf
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/cardutil.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardutil.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t348/makefile b/private/ntos/miniport/trantor/winnt/t348/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/trantor/winnt/t348/n5380.c b/private/ntos/miniport/trantor/winnt/t348/n5380.c
new file mode 100644
index 000000000..174801d6b
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/n5380.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\n5380.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t348/p3c.c b/private/ntos/miniport/trantor/winnt/t348/p3c.c
new file mode 100644
index 000000000..cb0551bc8
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/p3c.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\p3c.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t348/parallel.c b/private/ntos/miniport/trantor/winnt/t348/parallel.c
new file mode 100644
index 000000000..5e738d22e
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/parallel.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\parallel.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t348/portio.c b/private/ntos/miniport/trantor/winnt/t348/portio.c
new file mode 100644
index 000000000..487e619fd
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/portio.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\portio.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t348/scsifnc.c b/private/ntos/miniport/trantor/winnt/t348/scsifnc.c
new file mode 100644
index 000000000..055d4666d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/scsifnc.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\scsifnc.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t348/sources b/private/ntos/miniport/trantor/winnt/t348/sources
new file mode 100644
index 000000000..2d06a8295
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/sources
@@ -0,0 +1,39 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=t348
+TARGETPATH=..\..\exe
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\..\..\inc;..\include;..\..\include
+
+C_DEFINES=/DCARDTXXX_H=\"cardt348.h\"
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+i386_SOURCES=
+
+MIPS_SOURCES=
+
+SOURCES= trantor.c scsifnc.c n5380.c card.c parallel.c p3c.c portio.c t348.rc \
+ cardutil.c
diff --git a/private/ntos/miniport/trantor/winnt/t348/t348.rc b/private/ntos/miniport/trantor/winnt/t348/t348.rc
new file mode 100644
index 000000000..f6c47af32
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/t348.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Trantor T348 SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "t348.sys"
+#define VER_ORIGINALFILENAME_STR "t348.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/trantor/winnt/t348/trantor.c b/private/ntos/miniport/trantor/winnt/t348/trantor.c
new file mode 100644
index 000000000..420122471
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t348/trantor.c
@@ -0,0 +1,2 @@
+#include "..\..\source\trantor.c"
+
diff --git a/private/ntos/miniport/trantor/winnt/t358/card.c b/private/ntos/miniport/trantor/winnt/t358/card.c
new file mode 100644
index 000000000..539fba400
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/card.c
@@ -0,0 +1 @@
+#include "..\..\source\cardt358.c"
diff --git a/private/ntos/miniport/trantor/winnt/t358/cardutil.c b/private/ntos/miniport/trantor/winnt/t358/cardutil.c
new file mode 100644
index 000000000..a0e3193cf
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/cardutil.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardutil.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/t358/ep3c.c b/private/ntos/miniport/trantor/winnt/t358/ep3c.c
new file mode 100644
index 000000000..59688c2b9
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/ep3c.c
@@ -0,0 +1 @@
+#include "..\..\source\ep3c.c"
diff --git a/private/ntos/miniport/trantor/winnt/t358/makefile b/private/ntos/miniport/trantor/winnt/t358/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/trantor/winnt/t358/n5380.c b/private/ntos/miniport/trantor/winnt/t358/n5380.c
new file mode 100644
index 000000000..f813198ab
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/n5380.c
@@ -0,0 +1 @@
+#include "..\..\source\n5380.c"
diff --git a/private/ntos/miniport/trantor/winnt/t358/n53c400.c b/private/ntos/miniport/trantor/winnt/t358/n53c400.c
new file mode 100644
index 000000000..533b53584
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/n53c400.c
@@ -0,0 +1 @@
+#include "..\..\source\n53c400.c"
diff --git a/private/ntos/miniport/trantor/winnt/t358/parallel.c b/private/ntos/miniport/trantor/winnt/t358/parallel.c
new file mode 100644
index 000000000..7c72a1ac1
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/parallel.c
@@ -0,0 +1 @@
+#include "..\..\source\parallel.c"
diff --git a/private/ntos/miniport/trantor/winnt/t358/portio.c b/private/ntos/miniport/trantor/winnt/t358/portio.c
new file mode 100644
index 000000000..19ae3712b
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/portio.c
@@ -0,0 +1 @@
+#include "..\..\source\portio.c"
diff --git a/private/ntos/miniport/trantor/winnt/t358/scsifnc.c b/private/ntos/miniport/trantor/winnt/t358/scsifnc.c
new file mode 100644
index 000000000..0c3e83db5
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/scsifnc.c
@@ -0,0 +1 @@
+#include "..\..\source\scsifnc.c"
diff --git a/private/ntos/miniport/trantor/winnt/t358/sl386.c b/private/ntos/miniport/trantor/winnt/t358/sl386.c
new file mode 100644
index 000000000..f214c3187
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/sl386.c
@@ -0,0 +1 @@
+#include "..\..\source\sl386.c"
diff --git a/private/ntos/miniport/trantor/winnt/t358/sources b/private/ntos/miniport/trantor/winnt/t358/sources
new file mode 100644
index 000000000..22c816320
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/sources
@@ -0,0 +1,40 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=t358
+TARGETPATH=..\..\exe
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\..\..\inc;..\include;..\..\include
+
+C_DEFINES=/DCARDTXXX_H=\"cardt358.h\"
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+i386_SOURCES=
+
+MIPS_SOURCES=
+
+SOURCES= trantor.c scsifnc.c n5380.c card.c parallel.c \
+ ep3c.c sl386.c portio.c t358.rc n53c400.c cardutil.c
+
diff --git a/private/ntos/miniport/trantor/winnt/t358/t358.rc b/private/ntos/miniport/trantor/winnt/t358/t358.rc
new file mode 100644
index 000000000..3cf733cd9
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/t358.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Trantor T358 SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "t358.sys"
+#define VER_ORIGINALFILENAME_STR "t358.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/trantor/winnt/t358/trantor.c b/private/ntos/miniport/trantor/winnt/t358/trantor.c
new file mode 100644
index 000000000..b3edd55cd
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/t358/trantor.c
@@ -0,0 +1 @@
+#include "..\..\source\trantor.c"
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/card.c b/private/ntos/miniport/trantor/winnt/tmv1/card.c
new file mode 100644
index 000000000..b50cfe651
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/card.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardtmv1.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/card.h b/private/ntos/miniport/trantor/winnt/tmv1/card.h
new file mode 100644
index 000000000..98f702a4d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/card.h
@@ -0,0 +1 @@
+#include "cardtmv1.h"
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/cardutil.c b/private/ntos/miniport/trantor/winnt/tmv1/cardutil.c
new file mode 100644
index 000000000..a0e3193cf
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/cardutil.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\cardutil.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/findpas.c b/private/ntos/miniport/trantor/winnt/tmv1/findpas.c
new file mode 100644
index 000000000..ec27a2532
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/findpas.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\findpas.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/makefile b/private/ntos/miniport/trantor/winnt/tmv1/makefile
new file mode 100644
index 000000000..677d610db
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/mv101.c b/private/ntos/miniport/trantor/winnt/tmv1/mv101.c
new file mode 100644
index 000000000..52845ccfa
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/mv101.c
@@ -0,0 +1,4 @@
+#ifdef i386
+#include "..\..\source\mv101.c"
+#endif
+
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/n5380.c b/private/ntos/miniport/trantor/winnt/tmv1/n5380.c
new file mode 100644
index 000000000..174801d6b
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/n5380.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\n5380.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/port.c b/private/ntos/miniport/trantor/winnt/tmv1/port.c
new file mode 100644
index 000000000..a380b5cd6
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/port.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\port.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/portio.c b/private/ntos/miniport/trantor/winnt/tmv1/portio.c
new file mode 100644
index 000000000..487e619fd
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/portio.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\portio.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/scsifnc.c b/private/ntos/miniport/trantor/winnt/tmv1/scsifnc.c
new file mode 100644
index 000000000..055d4666d
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/scsifnc.c
@@ -0,0 +1,3 @@
+#ifdef i386
+#include "..\..\source\scsifnc.c"
+#endif
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/sources b/private/ntos/miniport/trantor/winnt/tmv1/sources
new file mode 100644
index 000000000..fb61768f8
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=tmv1
+TARGETPATH=..\..\exe
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\..\..\inc;..\include;..\..\include
+
+C_DEFINES=/DCARDTXXX_H=\"cardtmv1.h\"
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES= trantor.c scsifnc.c n5380.c card.c findpas.c portio.c mv101.c tmv1.rc \
+ cardutil.c
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/tmv1.rc b/private/ntos/miniport/trantor/winnt/tmv1/tmv1.rc
new file mode 100644
index 000000000..d2b242460
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/tmv1.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Trantor/Media Vision TMV1 SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "tmv1.sys"
+#define VER_ORIGINALFILENAME_STR "tmv1.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/trantor/winnt/tmv1/trantor.c b/private/ntos/miniport/trantor/winnt/tmv1/trantor.c
new file mode 100644
index 000000000..420122471
--- /dev/null
+++ b/private/ntos/miniport/trantor/winnt/tmv1/trantor.c
@@ -0,0 +1,2 @@
+#include "..\..\source\trantor.c"
+
diff --git a/private/ntos/miniport/ultra124/makefile b/private/ntos/miniport/ultra124/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/ultra124/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/ultra124/sources b/private/ntos/miniport/ultra124/sources
new file mode 100644
index 000000000..cc7c4c07a
--- /dev/null
+++ b/private/ntos/miniport/ultra124/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=ultra124
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=ultra124.c ultra124.rc
diff --git a/private/ntos/miniport/ultra124/ultra124.c b/private/ntos/miniport/ultra124/ultra124.c
new file mode 100644
index 000000000..6b23bcb65
--- /dev/null
+++ b/private/ntos/miniport/ultra124/ultra124.c
@@ -0,0 +1,1617 @@
+/* Copyright (c) 1992 Microsoft/UltrStor Corporation
+
+Module Name:
+ ultra124.c
+
+Abstract:
+ This is the port driver for the ULTRASTOR 124 EISA SCSI adapter.
+
+Authors:
+ Mike Glass / Edward Syu
+
+Environment:
+ kernel mode only
+
+Notes:
+
+Revision History:
+-----------------------------------------------------------------------------
+ Date Name Description
+
+08/25/92 Syu First time created. Modify from 24f source code.
+
+11/04/92 Fong * Change MSCP_TARGET_ERROR from 91h to A0H
+ * Handle Aborted command in Startio
+04/05/93 fong fix Handle Inquiry data problem for MARCH NT release
+-----------------------------------------------------------------------------
+
+--*/
+
+#include "miniport.h"
+#include "ultra124.h" // includes scsi.h
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+ PEISA_CONTROLLER EisaController;
+ UCHAR HostTargetId;
+ PSCSI_REQUEST_BLOCK CSIRSrb; // byte 24
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+//
+// Function declarations
+//
+// Functions that start with 'Ultra124' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+Ultra124FindAdapter(
+ IN PVOID DeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+Ultra124Initialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Ultra124StartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+Ultra124Interrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Ultra124ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+//
+// This function is called from Ultra124StartIo.
+//
+
+BOOLEAN
+BuildMscp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BuildMscp.
+//
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from Ultra124Interrupt.
+//
+
+VOID
+MapErrorToSrbStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+ReadDriveCapacity(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ ULONG AdapterCount = 0;
+
+ DebugPrint((1,"\n\nSCSI UltraStor 124 MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = Ultra124Initialize;
+ hwInitializationData.HwFindAdapter = Ultra124FindAdapter;
+ hwInitializationData.HwStartIo = Ultra124StartIo;
+ hwInitializationData.HwInterrupt = Ultra124Interrupt;
+ hwInitializationData.HwResetBus = Ultra124ResetBus;
+
+ //
+ // Set number of access ranges and bus type.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Indicate multiple requests per LUN is supported.
+ //
+
+ hwInitializationData.MultipleRequestPerLu = TRUE;
+
+ //
+ // Indicate auto request sense is supported.
+ //
+
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ //
+ // Ask for SRB extensions for MSCPs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(MSCP);
+ return ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &AdapterCount);
+
+} // end DriverEntry()
+
+
+ULONG
+Ultra124FindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo - Configuration information structure describing HBA
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ ULONG eisaSlotNumber;
+ PVOID eisaAddress;
+ PULONG adapterCount = Context;
+ UCHAR interruptLevel;
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ for (eisaSlotNumber=*adapterCount + 1;
+ eisaSlotNumber<MAXIMUM_EISA_SLOTS;
+ eisaSlotNumber++) {
+
+ //
+ // Update the adapter count to indicate this slot has been checked.
+ //
+
+ (*adapterCount)++;
+
+ //
+ // Get the system address for this card.
+ // The card uses I/O space.
+ //
+
+ eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ TRUE);
+
+ eisaController =
+ (PEISA_CONTROLLER)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE);
+
+ if (ScsiPortReadPortUlong(&eisaController->BoardId) ==
+ ULTRASTOR_124_EISA_ID) {
+ DebugPrint((1,
+ "Ultra124: Adapter found at EISA slot %d\n",
+ eisaSlotNumber));
+ break;
+ }
+
+ //
+ // If an adapter was not found unmap it.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension,
+ eisaAddress);
+
+ } // end for (eisaSlotNumber ...
+
+ if (!(eisaSlotNumber < MAXIMUM_EISA_SLOTS)) {
+
+ //
+ // No adapter was found. Indicate that we are done and there are no
+ // more adapters here. Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *adapterCount = 0;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // There is still more to look at.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Store base address of EISA registers in device extension.
+ //
+
+ deviceExtension->EisaController = eisaController;
+ deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0] = 0x07; //fix to 7 for U124
+
+ //
+ // Indicate maximum transfer length in bytes.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
+
+ //
+ // Maximum number of physical segments is 32.
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ interruptLevel =
+ ScsiPortReadPortUchar(&eisaController->InterruptLevel) & 0xF0;
+
+ switch (interruptLevel) {
+ case US_INTERRUPT_LEVEL_15:
+ ConfigInfo->BusInterruptLevel = 15;
+ break;
+
+ case US_INTERRUPT_LEVEL_14:
+ ConfigInfo->BusInterruptLevel = 14;
+ break;
+
+ case US_INTERRUPT_LEVEL_11:
+ ConfigInfo->BusInterruptLevel = 11;
+ break;
+
+ case US_INTERRUPT_LEVEL_10:
+ ConfigInfo->BusInterruptLevel = 10;
+ break;
+
+ default:
+ DebugPrint((1,"Ultra124FindAdapter: No interrupt level\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + EISA_ADDRESS_BASE);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ return SP_RETURN_FOUND;
+
+} // end Ultra124FindAdapter()
+
+
+BOOLEAN
+Ultra124Initialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+
+ DebugPrint((3,"Ultra124Initialize: Enter routine\n"));
+
+
+ //
+ // Enable system doorbell interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ US_ENABLE_SYSTEM_INTERRUPT+US_ENABLE_CSIR_INTERRUPT+US_ENABLE_MSCP_INTERRUPT);
+
+ return(TRUE);
+
+} // end Ultra124Initialize()
+
+
+BOOLEAN
+Ultra124StartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to send an MSCP.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PMSCP mscp;
+ PUCHAR mscpbuffer;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ ULONG physicalMscp;
+ ULONG length;
+ ULONG i = 0;
+
+ DebugPrint((2,"Ultra124StartIo: Enter routine\n"));
+
+ //DEBUGSTOP();
+
+ ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
+
+ //
+ // Make sure that the request is for a valid SCSI bus and LUN as
+ // the Ultra124 SCSI card does random things if address is wrong.
+ //
+
+ if (Srb->PathId != 0 || Srb->Lun != 0) {
+
+ //
+ // The Ultra124 card only supports logical unit zero and one bus.
+ //
+ DebugPrint((1,"Ultra124StartIo: Invalid LUN\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get MSCP from SRB.
+ //
+
+ mscp = Srb->SrbExtension;
+ mscpbuffer = (PUCHAR) mscp;
+
+ for (i=0; i<sizeof(MSCP); i++) //initialize as 0
+ (UCHAR) mscpbuffer[i] = 0;
+
+ //
+ // Save SRB back pointer in MSCP.
+ //
+
+ mscp->SrbAddress = Srb;
+
+ //
+ // Get MSCP physical address.
+ //
+
+ physicalMscp =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, mscp, &length));
+
+ //
+ // Assume physical address is contiguous for size of ECB.
+ //
+
+ ASSERT(length >= sizeof(MSCP));
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+ DebugPrint((3,"Ultra124StartIo: SCSI Execute IO\n"));
+
+ if (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
+ DebugPrint((3,"Ultra124StartIo: SCSI Read Capacity\n"));
+
+ if (ReadDriveCapacity(deviceExtension, Srb)) {
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+ else {
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+ }
+ else {
+ //
+ // Build MSCP for this request.
+ //
+ if (!(BuildMscp(deviceExtension, Srb))) {
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+ DebugPrint((1,"Ultra124StartIo: BuildMscp Fail\n"));
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ }
+ break;
+
+//{$8_24
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset Ultra124 and SCSI bus.
+ //
+
+ DebugPrint((1, "Ultra124StartIo: Reset bus request received\n"));
+
+ if (!Ultra124ResetBus( deviceExtension, Srb->PathId)) {
+ DebugPrint((1,"Ultra124StartIo: Reset bus failed\n"));
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ }
+ else {
+ DebugPrint((1,"Ultra124StartIo: Reset bus O.K.\n"));
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ }
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+//$11_4
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1, "Ultra124StartIo: Received Abort command\n"));
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ abortedSrb = ScsiPortGetSrb(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ if (abortedSrb != Srb->NextSrb ||
+ abortedSrb->SrbStatus != SRB_STATUS_PENDING) {
+
+ DebugPrint((1, "Ultra124StartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ }
+ else {
+
+ abortedSrb->SrbStatus = SRB_STATUS_ABORTED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ abortedSrb);
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ }
+ return TRUE;
+
+//$8_24}
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ DebugPrint((1,"Ultra124StartIo: Request Not Support\n"));
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // Write MSCP pointer and command to mailbox.
+ //
+
+
+ DebugPrint((3,"Ultra124StartIo: Check if OGM available\n"));
+
+ for (i=0; i<500; i++) {
+
+ if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) & US_MSCP_IN_USE)) {
+ break;
+ }
+ else {
+ //
+ // Stall 1 microsecond before trying again.
+ //
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i == 500) {
+ //
+ // Let operating system time out SRB.
+ //
+ DebugPrint((1,"Ultra124StartIo: Timed out waiting for mailbox\n"));
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ }
+ else {
+
+ //
+ // Write MSCP pointer to mailbox.
+ //
+ DebugPrint((2,"Ultra124StartIo: Send out OGM (Log.Addr %lx)\n",mscp));
+ ScsiPortWritePortUlong(&eisaController->OutGoingMailPointer,
+ physicalMscp);
+ //
+ // Send MAIL OUT
+ // Ring the local doorbell.
+ //
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
+ US_MSCP_IN_USE);
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ return TRUE;
+
+} // end Ultra124StartIo()
+
+
+BOOLEAN
+Ultra124Interrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the Ultra124 SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the MSCP is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PMSCP mscp;
+ PSCSI_REQUEST_BLOCK srb;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ ULONG physicalMscp;
+ UCHAR mscpStatus, csirStatus;
+ UCHAR InterruptMode;
+ UCHAR CDBOpcode;
+ ULONG BlockSize, TotalBlock;
+ PINQUIRYDATA InquiryBuffer;
+ PSCSI_READCAPACITY ReadCapacityBuffer;
+
+ CONST UCHAR VendorId[] = "ULTRSTOR";
+ CONST UCHAR ProductId[] = "U124 DiskArray ";
+ CONST UCHAR ProductRevisionLevel[] = "1.00";
+ UCHAR i;
+
+ //
+ // Check interrupt pending.
+ //
+ // Check CSIR command
+
+
+ DebugPrint((2,"Ultra124Interrupt: Enter routine\n"));
+
+ //DEBUGSTOP();
+
+
+ InterruptMode = ScsiPortReadPortUchar(&eisaController->SystemDoorBellInterrupt);
+
+ InterruptMode &= US_CSIR_COMPLETE + US_MSCP_COMPLETE;
+
+ switch (InterruptMode) {
+
+ case US_CSIR_COMPLETE:
+
+ DebugPrint((3, "U124Interrupt: CSIR interrupt\n"));
+
+ csirStatus = ScsiPortReadPortUchar(&eisaController->CSPByte0);
+
+ srb = deviceExtension->CSIRSrb;
+
+ if (!(csirStatus & CSIR_ERROR)) {
+
+ CDBOpcode = srb->Cdb[0];
+
+ switch (CDBOpcode) {
+
+ case SCSIOP_READ_CAPACITY:
+
+ TotalBlock = ScsiPortReadPortUlong((PULONG)(&eisaController->CSPByte2));
+ BlockSize = 0x200;
+ DebugPrint((3, "U124Interrupt(ReadCapacity): TotalBock %ld\n",TotalBlock ));
+ ReadCapacityBuffer = (PSCSI_READCAPACITY) srb->DataBuffer;
+ DebugPrint((3, "U124Interrupt: SRB Data Buffer -> %lx\n",
+ srb->DataBuffer));
+ DebugPrint((3, "U124Interrupt: Inquiry Buffer -> %lx\n",
+ ReadCapacityBuffer));
+ INTEL4_TO_SCSI4((PSCSI_4_BYTE) ReadCapacityBuffer->BlockCount,
+ (PINTEL_4_BYTE) &TotalBlock);
+ INTEL4_TO_SCSI4((PSCSI_4_BYTE) ReadCapacityBuffer->BlockLength,
+ (PINTEL_4_BYTE) &BlockSize);
+ break;
+
+ default:
+ break;
+ }
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ }
+ else {
+ DebugPrint((1, "U124Interrupt: CSIR interrupt with Error\n"));
+ MapErrorToSrbStatus(deviceExtension, srb);
+ }
+
+ // Call notification routine for the SRB.
+
+ ScsiPortNotification( RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ // Reset system doorbell interrupt.
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_CSIR_COMPLETE);
+
+ return TRUE;
+
+ case US_MSCP_COMPLETE:
+
+ DebugPrint((3, "U124Interrupt: MSCP interrupt\n"));
+ physicalMscp = ScsiPortReadPortUlong(&eisaController->InComingMailPointer);
+ //
+ // Get virtual MSCP address.
+ //
+ mscp = ScsiPortGetVirtualAddress(deviceExtension,
+ ScsiPortConvertUlongToPhysicalAddress(physicalMscp));
+ //
+ // Make sure the physical address was valid.
+ //
+ if (mscp == NULL) {
+ DebugPrint((1,"Ultra124Interrupt: No MSCP found\n"));
+ // Reset system doorbell interrupt.
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_MSCP_COMPLETE);
+
+ return FALSE;
+ }
+
+ srb = mscp->SrbAddress; // get SRB
+ if (srb == NULL) {
+
+ DebugPrint((1, "U124Interrupt: Srb in MSCP is NULL.\n"));
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_MSCP_COMPLETE);
+ return FALSE;
+ }
+
+ DebugPrint((2, "U124Interrupt: MSCP Log. Addr ->%lx\n",mscp));
+ DebugPrint((2, "U124Interrupt: SRB Log. Addr ->%lx\n",srb));
+ mscpStatus = mscp->OperationCode; //Error Code
+
+ if (mscpStatus & MSCP_ERROR) {
+
+ //
+ // Translate adapter status to SRB status
+ // and log error if necessary.
+ //
+
+ DebugPrint((1, "U124Interrupt: MSCP Done Fail.\n"));
+ MapErrorToSrbStatus(deviceExtension, srb);
+ }
+ else {
+ DebugPrint((3, "U124Interrupt: MSCP Status O.K.\n"));
+ CDBOpcode = srb->Cdb[0];
+
+ switch (CDBOpcode) {
+ case SCSIOP_INQUIRY:
+ DebugPrint((3, "U124Interrupt: SCSI Inquiry Command done\n"));
+
+ InquiryBuffer = (PINQUIRYDATA) srb->DataBuffer;
+
+ //
+ // clear the InquiryBuffer before filling in data to avoid
+ // garbage data in buffer (because some field in Inquiry data
+ // structure are defined in bits value.
+ //
+
+ for (i=0; i<srb->DataTransferLength; i++) {
+ *((PUCHAR) InquiryBuffer+i) = 0;
+ }
+
+ DebugPrint((3, "U124Interrupt: SRB Data Buffer -> %lx\n",
+ srb->DataBuffer));
+
+ DebugPrint((3, "U124Interrupt: Inquiry Buffer -> %lx\n",
+ InquiryBuffer));
+ InquiryBuffer->DeviceType = DIRECT_ACCESS_DEVICE;
+ InquiryBuffer->DeviceTypeModifier = 0; //not removable
+
+ InquiryBuffer->Versions = 0x02; //scsi 2
+ InquiryBuffer->ResponseDataFormat = 0x02; //scsi 2
+ InquiryBuffer->AdditionalLength = 0x8f; //scsi 2
+
+ InquiryBuffer->SoftReset = 0; //scsi 2
+ InquiryBuffer->CommandQueue = 1;
+ InquiryBuffer->Reserved2 = 0;
+ InquiryBuffer->LinkedCommands = 1;
+ InquiryBuffer->Synchronous = 1;
+ InquiryBuffer->Wide16Bit = 0;
+ InquiryBuffer->Wide32Bit = 0;
+ InquiryBuffer->RelativeAddressing = 1;
+
+ for (i=0; i<8; i++)
+ (UCHAR) InquiryBuffer->VendorId[i] = (UCHAR) VendorId[i];
+
+ for (i=0; i<16; i++)
+ (UCHAR) InquiryBuffer->ProductId[i] = (UCHAR) ProductId[i];
+
+ for (i=0; i<4; i++)
+ (UCHAR) InquiryBuffer->ProductRevisionLevel[i] = (UCHAR) ProductRevisionLevel[i];
+
+ break;
+
+ default:
+ DebugPrint((2, "U124Interrupt: SCSI command -> %x\n", CDBOpcode));
+ break;
+ }
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+ }
+ //
+ // Call notification routine for the SRB.
+ //
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_MSCP_COMPLETE);
+
+ return TRUE;
+
+ default:
+ //
+ // Handle spurious interrupt.
+ //
+ DebugPrint((1,"Ultra124Interrupt: Spurious interrupt\n"));
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 0
+ );
+
+ return FALSE;
+
+ }
+
+
+} // end Ultra124Interrupt()
+
+
+BOOLEAN
+BuildMscp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build MSCP for Ultra124 from SRB.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+ TRUE: MSCP command ready to send
+ FALSE: no U124 command match this SCSI pass thru command
+--*/
+
+{
+ PMSCP mscp = Srb->SrbExtension;
+ UCHAR CDBopcode;
+
+
+ DebugPrint((3,"BuildMscp: Enter routine\n"));
+
+ //
+ // Set MSCP command.
+ //
+
+ mscp->DriveControl = Srb->TargetId << 5;
+ CDBopcode = Srb->Cdb[0]; //get SCSI CDB opcode
+ DebugPrint((2, "U124BuildMSCP: SCSI command -> %x\n", CDBopcode));
+
+ switch (CDBopcode) {
+ case SCSIOP_INQUIRY:
+ mscp->OperationCode = MSCP_TEST_DRIVE_READY; //use for inquiry
+ break;
+
+ case SCSIOP_TEST_UNIT_READY:
+ mscp->OperationCode = MSCP_TEST_DRIVE_READY;
+ break;
+
+ case SCSIOP_REZERO_UNIT:
+ mscp->OperationCode = MSCP_REZERO_DRIVE;
+ break;
+
+ case SCSIOP_READ:
+ mscp->OperationCode = MSCP_READ_SECTOR;
+ SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
+ break;
+
+ case SCSIOP_READ6:
+ mscp->OperationCode = MSCP_READ_SECTOR;
+ SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
+ break;
+
+ case SCSIOP_WRITE:
+ mscp->OperationCode = MSCP_WRITE_SECTOR;
+ SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
+ break;
+
+ case SCSIOP_WRITE6:
+ mscp->OperationCode = MSCP_WRITE_SECTOR;
+ SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
+ break;
+
+ case SCSIOP_VERIFY:
+ mscp->OperationCode = MSCP_VERIFY_SECTOR;
+ SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
+ break;
+
+ case SCSIOP_VERIFY6:
+ mscp->OperationCode = MSCP_VERIFY_SECTOR;
+ SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
+ break;
+
+ case SCSIOP_SEEK:
+ mscp->OperationCode = MSCP_SEEK_DRIVE;
+ SCSI4_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_4_BYTE)&Srb->Cdb[C10_LBA_4]);
+ break;
+
+ case SCSIOP_SEEK6:
+ mscp->OperationCode = MSCP_SEEK_DRIVE;
+ SCSI2_TO_INTEL4((PINTEL_4_BYTE)&mscp->DriveLBA, (PSCSI_2_BYTE)&Srb->Cdb[C6_LBA_2]);
+ break;
+
+ default:
+ return FALSE; // no U124 command match this SCSI pass thru command
+ break;
+
+ }
+
+ //
+ // Build SGL in MSCP if data transfer.
+ //
+ if (Srb->DataTransferLength > 0) {
+ //
+ // Build scattergather descriptor list.
+ //
+ BuildSgl(DeviceExtension, Srb);
+ }
+ else {
+ //
+ // Set up MSCP for no data transfer.
+ //
+ mscp->DataLength = 0;
+ mscp->SgDescriptorCount = 0;
+ }
+ DebugPrint((2, "U124StartIO: Build MSCP done, MSCP-> %lx\n",mscp));
+
+ return TRUE;
+
+} // end BuildMscp()
+
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list in the MSCP.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PMSCP mscp = Srb->SrbExtension;
+ PSDL sdl = &mscp->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG descriptorCount = 0;
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SGL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SDL));
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+ DebugPrint((3, "BuildSgl: Data buffer %lx\n", dataPointer));
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "BuildSgl: Physical address %lx\n", physicalAddress));
+ DebugPrint((3, "Sgl: Data length %lx\n", length));
+ DebugPrint((3, "BuildSgl: Bytes left %lx\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ sdl->Descriptor[descriptorCount].Address = physicalAddress;
+ sdl->Descriptor[descriptorCount].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ //
+ // Check for only one descriptor. As an optimization, in these
+ // cases, use nonscattergather requests.
+ //
+
+ if (descriptorCount == 1) {
+ //
+ // Set descriptor count to 0.
+ //
+ mscp->SgDescriptorCount = 0;
+
+ //
+ // Set data pointer to data buffer.
+ //
+ mscp->DataPointer = physicalAddress;
+
+ //
+ // Set data transfer length.
+ //
+ mscp->DataLength = Srb->DataTransferLength;
+
+ //
+ // Clear scattergather bit.
+ //
+
+ }
+ else {
+ //
+ // Write SDL count to MSCP.
+ //
+ mscp->SgDescriptorCount = (UCHAR)descriptorCount;
+
+ //
+ // Write SGL address to ECB.
+ //
+ mscp->DataPointer = physicalSdl;
+ mscp->DataLength = Srb->DataTransferLength;
+
+ //
+ // Indicate scattergather operation.
+ //
+ mscp->DriveControl |= EnableScatterGather;
+ }
+
+ DebugPrint((2,"BuildSgl: SG-> %d, XfrBuffer-> %lx, XfrLength-> %lx\n",
+ descriptorCount, mscp->DataPointer, mscp->DataLength));
+ return;
+
+} // end BuildSgl()
+
+
+BOOLEAN
+Ultra124ResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Ultra124 SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ ULONG j;
+
+ //
+ // The Ultra124 only supports a single SCSI channel.
+ //
+
+
+
+ UNREFERENCED_PARAMETER(PathId);
+ DebugPrint((1,"ResetBus: Reset Ultra124 and SCSI bus\n"));
+ DebugPrint((3,"Ultra124ResetBUS: Enter routine\n"));
+
+ //
+ // Reset SCSI bus (use Reset HostAdapter).
+ //
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
+ US_HBA_RESET);
+
+ //
+ // Wait for local processor to clear reset bit.
+ //
+ for (j=0; j<200000; j++) {
+ if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) &
+ US_HBA_RESET)) {
+ DebugPrint((1,"Ultra124ResetBUS: Reset H/A O.K.\n"));
+ break;
+ }
+
+ ScsiPortStallExecution(10);
+
+ } // end for (j=0 ...
+
+
+ if (j == 200000) {
+ DebugPrint((1,"Ultra124ResetBUS: Reset H/A Fail\n"));
+ //
+ // Busy has not gone low. Assume the card is gone.
+ // Log the error and fail the request.
+ //
+ ScsiPortLogError(deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 16);
+
+ return FALSE;
+
+ }
+ DebugPrint((1,"Ultra124ResetBUS: Reset H/A Fail\n"));
+
+ //
+ // Complete all outstanding requests.
+ //
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)0,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ return TRUE;
+
+} // end Ultra124ResetBus()
+
+
+VOID
+MapErrorToSrbStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Translate Ultra124 error to SRB error.
+
+Arguments:
+
+ Device Extension for logging error
+ SRB
+
+Return Value:
+
+ Updated SRB
+
+--*/
+
+{
+ ULONG logError = 0;
+ UCHAR srbStatus;
+ PMSCP mscp = Srb->SrbExtension;
+ PUCHAR mscpbuffer;
+ PSENSE_DATA sensebuffer = Srb->SenseInfoBuffer;
+ UCHAR i;
+
+ DebugPrint((3,"Ultra124MapErrorToSrbStatus: Enter routine\n"));
+ mscpbuffer = (PUCHAR) Srb->SrbExtension;
+ Srb->ScsiStatus = SCSISTAT_GOOD; //only check-condition set when TARGET error
+
+ switch (mscp->OperationCode) {
+ case MSCP_TARGET_ERROR:
+
+ //
+ // clear the sensebuffer to 0
+ //
+ for (i=0; i< Srb->SenseInfoBufferLength; i++) {
+ *((PUCHAR) sensebuffer+i) = 0;
+ }
+
+ DebugPrint((1,"MapErrorToSrbStatus: HA_TARGET_ERROR\n"));
+ DebugPrint((1,"MapErrorToSrbStatus: srb->SenseInfoBufferLength = %d\n",Srb->SenseInfoBufferLength));
+
+ sensebuffer->SenseKey = (UCHAR) mscpbuffer[7];
+ sensebuffer->AdditionalSenseCode = (UCHAR) mscpbuffer[6];
+ sensebuffer->AdditionalSenseCodeQualifier = (UCHAR) mscpbuffer[5];
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ srbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
+ break;
+
+ case MSCP_DRIVE_FAULT:
+ DebugPrint((1,"MapErrorToSrbStatus: Device not found\n"));
+ srbStatus = SRB_STATUS_NO_DEVICE;
+ break;
+
+ case MSCP_DRIVE_NOT_PRESENT:
+ case MSCP_LOG_DRIVE_UNDEFINE:
+ case MSCP_LOG_DRIVE_NOT_READY:
+ DebugPrint((1,"MapErrorToSrbStatus: MSCP_LOG_DRIVE_NOT_READY\n"));
+ srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case MSCP_ADAPTER_ERROR:
+ switch ((UCHAR) mscpbuffer[7]) {
+ case HA_SELECTION_TIME_OUT:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_SELECTION_TIME_OUT\n"));
+ srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case HA_DATA_OVER_UNDER_RUN:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_DATA_OVER_UNDER_RUN\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_DATA_OVERRUN;
+ break;
+
+ case HA_BUS_FREE_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_BUS_FREE\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ break;
+
+ case HA_INVALID_PHASE:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_INVALID_PHASE\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ break;
+
+ case HA_ILLEGAL_COMMAND:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_ILLEGAL_COMMAND\n"));
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case HA_REQ_SENSE_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_REQ_SENSE_ERROR\n"));
+ srbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
+ break;
+
+ case HA_BUS_RESET_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_BUS_RESET_ERROR\n"));
+ srbStatus = SRB_STATUS_BUS_RESET;
+ break;
+
+ case HA_TIME_OUT_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: HA_DATA_TIME_OUT_ERROR\n"));
+ srbStatus = SRB_STATUS_COMMAND_TIMEOUT;
+ break;
+
+ default:
+ DebugPrint((1,"MapErrorToSrbStatus: General Failure\n"));
+ srbStatus = SRB_STATUS_ERROR;
+
+ }
+ break;
+
+ case MSCP_INVALID_COMMAND:
+ case MSCP_INVALID_PARAMETER:
+ case MSCP_INVALID_DATA_LIST:
+ DebugPrint((1,"MapErrorToSrbStatus: Invalid command\n"));
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ default:
+ DebugPrint((1,"MapErrorToSrbStatus: Unknown Error\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ } // end switch ...
+
+ //
+ // Log error if indicated.
+ //
+
+ if (logError) {
+ ScsiPortLogError(
+ DeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ 2 << 16 | mscp->OperationCode
+ );
+ }
+
+ //
+ // Set SRB status.
+ //
+ Srb->SrbStatus = srbStatus;
+
+ //
+ // Set target SCSI status in SRB.
+ //
+ return;
+
+} // end MapErrorToSrbStatus()
+
+
+BOOLEAN
+ReadDriveCapacity(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build Read Drive Capacity CSIR command from SRB
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+ TRUE: CSIR command
+ FALSE: CSIR command not ready
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = DeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PMSCP mscp = Srb->SrbExtension;
+ ULONG i;
+ UCHAR CDBopcode;
+
+
+ DebugPrint((3,"ReadDriveCapcity: Enter routine\n"));
+
+ //
+ // Set CSIR command.
+ //
+
+ deviceExtension->CSIRSrb = Srb; //save for later reference
+ CDBopcode = Srb->Cdb[0]; //get SCSI CDB opcode
+ mscp->CSIRBuffer.CSIROpcode = CSIR_READ_CAPACITY;
+ mscp->CSIRBuffer.CSIR1 = (Srb->TargetId) << 5; //drive ID
+ ScsiPortWritePortUchar(&eisaController->CSPByte0,
+ CSIR_READ_CAPACITY);
+ ScsiPortWritePortUchar(&eisaController->CSPByte1,
+ mscp->CSIRBuffer.CSIR1);
+
+ for (i=0; i<500; i++) {
+ if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) &
+ US_CSIR_IN_USE)) {
+
+ DebugPrint((3,"Ultra124StartIo: Read Capacity (CSIR)\n"));
+ break;
+ }
+ else {
+ //
+ // Stall 1 microsecond before trying again.
+ //
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i == 500) {
+ //
+ // Let operating system time out SRB.
+ //
+ DebugPrint((1,"Ultra124StartIo: Timed out waiting for CSIR\n"));
+ return FALSE;
+
+ }
+ else {
+ //
+ // Send CSIR command IN
+ // Ring the local doorbell.
+ //
+
+ DebugPrint((1,"Ultra124StartIo: Send out CSIR\n"));
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
+ US_CSIR_IN_USE);
+
+ }
+
+ return TRUE;
+
+} // end ReadDriveCapacity()
+
+
diff --git a/private/ntos/miniport/ultra124/ultra124.h b/private/ntos/miniport/ultra124/ultra124.h
new file mode 100644
index 000000000..85230c373
--- /dev/null
+++ b/private/ntos/miniport/ultra124/ultra124.h
@@ -0,0 +1,396 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ultra124.h
+
+Abstract:
+
+ This file contains the structures and definitions that define
+ the ULTRASTOR 124 EISA SCSI host bus adapter.
+
+Author:
+
+ Mike Glass (MGLASS)
+ Edward Syu (ES)
+
+Revision History:
+
+
+--*/
+
+#include "scsi.h"
+
+
+#define U124DEBUG 0
+
+#ifdef U124DEBUG
+ #define DEBUGSTOP() \
+ _asm {int 3}
+#else
+ #define DEBUGSTOP()
+#endif
+
+
+//
+// SCATTER/GATHER definitions
+//
+
+#define MAXIMUM_EISA_SLOTS 0xF
+#define EISA_ADDRESS_BASE 0x0C80
+#define MAXIMUM_SG_DESCRIPTORS 33
+#define MAXIMUM_TRANSFER_LENGTH 0xFFFFFFFF
+
+//Note: U124 SG struct diff. from U24F/U14F
+typedef struct _SGD {
+ ULONG Length;
+ ULONG Address;
+} SGD, *PSGD;
+
+typedef struct _SDL {
+ SGD Descriptor[MAXIMUM_SG_DESCRIPTORS];
+} SDL, *PSDL;
+
+//
+// MailBox SCSI Command Packet
+//
+
+#pragma pack(1)
+
+//
+// CSIR command
+//
+typedef struct _CSIR {
+ UCHAR CSIROpcode; // byte 0
+ UCHAR CSIR1; // byte 1
+ UCHAR CSIR2; // byte 2
+ UCHAR CSIR3; // byte 3
+ UCHAR CSIR4; // byte 4
+ UCHAR CSIR5; // byte 5
+} CSIR, *PCSIR;
+
+//CSP format for logical-drive-specific or general command
+typedef struct _MSCP {
+ UCHAR OperationCode; // byte 00 (Opcode / Error Code)
+ UCHAR DriveControl; // Drive: bit 5-7
+ // ScatterGather bit 4
+ // Control bit 3-0
+ UCHAR SgDescriptorCount; // byte 02
+ UCHAR Reserved; // byte 03
+ ULONG DataPointer; // byte 04-07
+ ULONG DriveLBA; // byte 08-0B
+ ULONG DataLength; // byte 0C-0F
+ PSCSI_REQUEST_BLOCK SrbAddress; // byte 10
+ SDL Sdl; // byte 14
+ CSIR CSIRBuffer; // for CSIR command
+} MSCP, *PMSCP;
+
+#define EnableScatterGather 0x10
+
+#pragma pack()
+
+
+//
+// Operation codes
+//
+
+// MailBox commands
+// Logical Drive Commands
+#define MSCP_TEST_DRIVE_READY 0x00
+#define MSCP_REZERO_DRIVE 0x01
+#define MSCP_READ_SECTOR 0x02
+#define MSCP_WRITE_SECTOR 0x03
+#define MSCP_VERIFY_SECTOR 0x04
+#define MSCP_SEEK_DRIVE 0x05
+
+// Logical Drive Maintenance Commands
+#define MSCP_INIT_DRIVE 0x10
+#define MSCP_SCAN_DRIVE 0x11
+#define MSCP_REBUILD 0x12 //unused
+#define MSCP_INTEGRITY_CHECK 0x13
+#define MSCP_INTEGRITY_FIX 0x14
+#define MSCP_FORCE_REBUILD 0x15
+
+// CSIR commands
+#define CSIR_READ_CAPACITY 0x01
+#define CSIR_DEFINE_LOG_DRIVE 0x02
+#define CSIR_ASSIGN_PARTITION 0x03
+#define CSIR_ISOLATE_CHANNEL 0x04
+#define CSIR_UNISOLATE_CHANNEL 0x05
+#define CSIR_REPORT_STATUS 0x06
+#define CSIR_RET_PHY_CONNECT 0x07
+#define CSIR_CTRL_DIAG 0x08
+#define CSIR_INIT_MAILBOX 0x09
+#define CSIR_RET_CONFIG 0x0A
+#define CSIR_RET_LOG_DRV_DEFINE 0x0B
+#define CSIR_RET_PART_INFO 0x0C
+#define CSIR_RESERVED_1 0x0D
+#define CSIR_RESERVED_2 0x0E
+#define CSIR_RET_UNITS_DOWN 0x0F
+#define CSIR_CLEAR_UNIT_DOWN 0x10
+#define CSIR_PREPARE_SHIP 0x11
+#define CSIR_WIPE_CTRL_NVRAM 0x11
+
+
+//
+// Host Adapter Error Codes
+//
+
+#define MSCP_NO_ERROR 0x00
+#define MSCP_ERROR 0x80
+#define CSIR_ERROR 0x80
+#define MSCP_INVALID_COMMAND 0x81
+#define MSCP_INVALID_PARAMETER 0x82
+#define MSCP_INVALID_DATA_LIST 0x83
+#define MSCP_LOG_DRIVE_UNDEFINE 0x84
+
+#define MSCP_DRIVE_NOT_PRESENT 0x88
+#define MSCP_LOG_DRIVE_NOT_READY 0x89
+#define MSCP_DRIVE_FAULT 0x8A
+#define MSCP_INTEGRITY_CHECK_FAIL 0x8B
+#define MSCP_RECOVERY_FAIL 0x8C //double error
+#define MSCP_SCSI_UNKNOWN_ERROR 0x8D
+
+#define MSCP_ADAPTER_ERROR 0x90
+// SubCodes for adapter error loaded into byte 7 of MSCP
+
+ #define HA_NO_ERROR 0x00
+ #define HA_BMIC_ERROR 0x44
+ #define HA_ABORT_ERROR 0x84
+ #define HA_SELECTION_TIME_OUT 0x91
+ #define HA_DATA_OVER_UNDER_RUN 0x92
+ #define HA_BUS_FREE_ERROR 0x93
+ #define HA_INVALID_PHASE 0x94
+ #define HA_ILLEGAL_COMMAND 0x96
+ #define HA_REQ_SENSE_ERROR 0x9B
+ #define HA_COMPLETE_MSG_ERROR 0x9F
+ #define HA_BUS_RESET_ERROR 0xA3
+ #define HA_TIME_OUT_ERROR 0x58
+ #define HA_GENERAL_ERROR 0x59
+
+
+#define MSCP_TARGET_ERROR 0xA0
+//Subcode for SCSI target error
+// byte 7 of MSCP : SCSI sense key
+// byte 6/5 of MSCP : SCSI sense code
+
+#define MSCP_POWER_ON_DIAG_ERROR 0xB0
+//Subcode for diag. error (byte 4 of MSCP)
+ #define DIAG_EPROM_CHKSUM_ERROR 0x01
+ #define DIAG_CODE_RAM_ERROR 0x02
+ #define DIAG_NVRAM_ERROR 0x03
+ #define DIAG_BUFFER_RAM_ERROR 0x04
+ #define DIAG_SCRIPT_RAM_ERROR 0x05
+ #define DIAG_ISA_RAM_ERROR 0x06
+ #define DIAG_BMIC_INIT_ERROR 0x07
+ #define DIAG_PARITY_INIT_ERROR 0x08
+ #define DIAG_CHANNEL_0_INIT_ERROR 0x09
+ #define DIAG_CHANNEL_1_INIT_ERROR 0x0A
+ #define DIAG_CHANNEL_2_INIT_ERROR 0x0B
+ #define DIAG_CHANNEL_3_INIT_ERROR 0x0C
+ #define DIAG_CHANNEL_4_INIT_ERROR 0x0D
+ #define DIAG_ISA_INIT_ERROR 0x0E
+
+//
+// EISA Registers definition
+//
+
+#pragma pack(1)
+
+typedef struct _EISA_CONTROLLER {
+ ULONG BoardId; // zC80
+ UCHAR ExpansionBoard; // zC84
+ UCHAR InterruptLevel; // zC85
+ UCHAR AuxControl; // zC86
+ UCHAR HostAdapterId; // zC87
+ UCHAR RegisterRev1[40]; // zC88-zCAF
+
+ UCHAR LocalDoorBellMask; // zCB0
+ UCHAR LocalDoorBellInterrupt; // zCB1
+ UCHAR SystemDoorBellMask; // zCB2
+ UCHAR SystemDoorBellInterrupt; // zCB3
+ UCHAR ErrorRegister; // zCB4
+ UCHAR RegisterRev2[3]; // zCB5-zCB7
+
+ UCHAR CSPByte0; // zCB8
+ UCHAR CSPByte1; // zCB9
+ UCHAR CSPByte2; // zCBA
+ UCHAR CSPByte3; // zCBB
+ UCHAR CSPByte4; // zCBC
+ UCHAR CSPByte5; // zCBD
+ UCHAR RegisterRev3[2]; // zCBE-zCBF
+ ULONG OutGoingMailPointer; // zCC0
+ ULONG InComingMailPointer; // zCC4
+
+} EISA_CONTROLLER, *PEISA_CONTROLLER;
+
+#pragma pack()
+
+//
+// UltraStor 124 board id
+//
+
+#define ULTRASTOR_124_EISA_ID 0x40126356
+
+//
+// Interrupt levels
+//
+
+#define US_INTERRUPT_LEVEL_15 0x10
+#define US_INTERRUPT_LEVEL_14 0x20
+#define US_INTERRUPT_LEVEL_11 0x40
+#define US_INTERRUPT_LEVEL_10 0x80
+
+//
+// Alternate address selection
+//
+
+#define US_SECONDARY_ADDRESS 0x08
+
+//
+// ISA TSR Port enabled
+//
+
+#define US_ISA_TSR_PORT_ENABLED 0x04
+
+//
+// Local interrupt status
+// System interrupt mask
+// 0xCB1
+// 0xCB2
+
+#define US_CSIR_IN_USE 0x10
+#define US_MSCP_IN_USE 0x01
+#define US_HBA_RESET 0x40
+
+#define US_ENABLE_SYSTEM_INTERRUPT 0x80
+#define US_ENABLE_CSIR_INTERRUPT 0x10
+#define US_ENABLE_MSCP_INTERRUPT 0x01
+
+//
+// System interrupt status
+// 0xCB3
+
+#define US_RESET_MSCP_COMPLETE 0x01
+#define US_MSCP_COMPLETE 0x01
+#define US_RESET_CSIR_COMPLETE 0x10
+#define US_CSIR_COMPLETE 0x10
+
+//
+// Error Register
+// 0xCB4
+
+#define DRIVE_DOWN 0x01
+
+
+#define CDB_6_BYTE 6 // Length of 6 byte CDB
+#define CDB_10_BYTE 10 // Length of 10 byte CDB
+#define CDB_12_BYTE 12 // Length of 12 byte CDB
+
+#define C6_OPCODE 0
+#define C6_LUN 1
+#define C6_LBA_2 2
+#define C6_LBA_1 3
+#define C6_XFRLEN 4
+#define C6_CONTROL 5
+
+#define C10_OPCODE 0
+#define C10_LUN 1
+#define C10_LBA_4 2
+#define C10_LBA_3 3
+#define C10_LBA_2 4
+#define C10_LBA_1 5
+#define C10_RESERVED 6
+#define C10_XFR_2 7
+#define C10_XFR_1 8
+#define C10_CONTROL 9
+
+#define C12_OPCODE 0
+#define C12_LUN 1
+#define C12_LBA_4 2
+#define C12_LBA_3 3
+#define C12_LBA_2 4
+#define C12_LBA_1 5
+#define C12_XFR_4 6
+#define C12_XFR_3 7
+#define C12_XFR_2 8
+#define C12_XFR_1 9
+#define C12_RESERVED 10
+#define C12_CONTROL 11
+
+// Read Capacity Data
+
+typedef struct _SCSIReadCapacity {
+UCHAR BlockCount[4]; //# of Logical Block Address
+UCHAR BlockLength[4]; //block length (in bytes)
+} SCSI_READCAPACITY, *PSCSI_READCAPACITY, *NPSCSI_READCAPCITY;
+
+//
+// The following definitions are used to convert SCSI & INTEL format
+//
+
+typedef struct _INTEL_4_BYTE {
+ UCHAR Byte0;
+ UCHAR Byte1;
+ UCHAR Byte2;
+ UCHAR Byte3;
+} INTEL_4_BYTE, *PINTEL_4_BYTE;
+
+typedef struct _INTEL_2_BYTE {
+ UCHAR Byte0;
+ UCHAR Byte1;
+} INTEL_2_BYTE, *PINTEL_2_BYTE;
+
+typedef struct _SCSI_2_BYTE {
+ UCHAR S1;
+ UCHAR S0;
+} SCSI_2_BYTE, *PSCSI_2_BYTE;
+
+typedef struct _SCSI_4_BYTE {
+ UCHAR S3;
+ UCHAR S2;
+ UCHAR S1;
+ UCHAR S0;
+} SCSI_4_BYTE, *PSCSI_4_BYTE;
+
+
+#define INTEL2_TO_SCSI2(ScsiTwo, IntelTwo) { \
+ (ScsiTwo)->S0 = (Inteltwo)->Byte0; \
+ (ScsiTwo)->S1 = (Inteltwo)->Byte1; \
+}
+
+#define SCSI2_TO_INTEL2(IntelTwo, ScsiTwo) { \
+ (IntelTwo)->Byte0 = (ScsiTwo)->S0; \
+ (IntelTwo)->Byte1 = (ScsiTwo)->S1; \
+}
+#define INTEL4_TO_SCSI2(Two, Four) { \
+ ASSERT(!((Four)->Byte3)); \
+ ASSERT(!((Four)->Byte2)); \
+ (Two)->S0 = (Four)->Byte0; \
+ (Two)->S1 = (Four)->Byte1; \
+}
+
+#define SCSI2_TO_INTEL4(Four, Two) { \
+ (Four)->Byte0 = (Two)->S0; \
+ (Four)->Byte1 = (Two)->S1; \
+ (Four)->Byte2 = 0; \
+ (Four)->Byte3 = 0; \
+}
+
+#define SCSI4_TO_INTEL4(IntelFour, ScsiFour) { \
+ (IntelFour)->Byte0 = (ScsiFour)->S0; \
+ (IntelFour)->Byte1 = (ScsiFour)->S1; \
+ (IntelFour)->Byte2 = (ScsiFour)->S2; \
+ (IntelFour)->Byte3 = (ScsiFour)->S3; \
+}
+
+#define INTEL4_TO_SCSI4(ScsiFour, IntelFour) { \
+ (ScsiFour)->S0 = (IntelFour)->Byte0; \
+ (ScsiFour)->S1 = (IntelFour)->Byte1; \
+ (ScsiFour)->S2 = (IntelFour)->Byte2; \
+ (ScsiFour)->S3 = (IntelFour)->Byte3; \
+}
+
+
diff --git a/private/ntos/miniport/ultra124/ultra124.rc b/private/ntos/miniport/ultra124/ultra124.rc
new file mode 100644
index 000000000..b95a9a144
--- /dev/null
+++ b/private/ntos/miniport/ultra124/ultra124.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "ULTRASTOR EISA SCSI Adapter Driver"
+#define VER_INTERNALNAME_STR "ultra124.sys"
+#define VER_ORIGINALFILENAME_STR "ultra124.sys"
+
+#include "common.ver"
diff --git a/private/ntos/miniport/ultra14f/makefile b/private/ntos/miniport/ultra14f/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/ultra14f/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/ultra14f/sources b/private/ntos/miniport/ultra14f/sources
new file mode 100644
index 000000000..13b50aec0
--- /dev/null
+++ b/private/ntos/miniport/ultra14f/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=ultra14f
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=ultra14f.c ultra14f.rc
diff --git a/private/ntos/miniport/ultra14f/ultra14f.c b/private/ntos/miniport/ultra14f/ultra14f.c
new file mode 100644
index 000000000..9f406c515
--- /dev/null
+++ b/private/ntos/miniport/ultra14f/ultra14f.c
@@ -0,0 +1,1561 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ultra14f.c
+
+Abstract:
+
+ This is the port driver for the ULTRASTOR 14F ISA SCSI adapter.
+
+Author:
+
+ Stephen Fong
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "ultra14f.h" // includes scsi.h
+
+CONST ULONG AdapterAddresses[] = {0X330, 0X340, /* 0X310, */ 0X240, 0X230, 0X210, 0X140, 0X130, 0};
+
+//
+// Logical Unit extension
+//
+typedef struct _SPECIFIC_LU_EXTENSION {
+ UCHAR DisconnectErrorCount; // keep track of # of disconnect error
+} SPECIFIC_LU_EXTENSION, *PSPECIFIC_LU_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+ PU14_BASEIO_ADDRESS U14_BaseIO_Address;
+ UCHAR HostTargetId;
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+//
+// Function declarations
+//
+// Functions that start with 'Ultra14f' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+Ultra14fFindAdapter(
+ IN PVOID DeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+Ultra14fInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Ultra14fStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+Ultra14fInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Ultra14fResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+//
+// This function is called from Ultra14fStartIo.
+//
+
+VOID
+BuildMscp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PSPECIFIC_LU_EXTENSION luExtension
+ );
+
+//
+// This function is called from BuildMscp.
+//
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from Ultra14fInterrupt.
+//
+
+VOID
+MapErrorToSrbStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ ULONG AdapterCount = 0;
+
+ DebugPrint((1,"\n\nSCSI UltraStor 14f MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = Ultra14fInitialize;
+ hwInitializationData.HwFindAdapter = Ultra14fFindAdapter;
+ hwInitializationData.HwStartIo = Ultra14fStartIo;
+ hwInitializationData.HwInterrupt = Ultra14fInterrupt;
+ hwInitializationData.HwResetBus = Ultra14fResetBus;
+
+ //
+ // Set number of access ranges and bus type.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = Isa;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Indicate auto request sense is supported.
+ //
+
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // Specify size of logical unit extension.
+ //
+ hwInitializationData.SpecificLuExtensionSize = sizeof(SPECIFIC_LU_EXTENSION);
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ //
+ // Ask for SRB extensions for MSCPs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(MSCP);
+
+ return ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &AdapterCount);
+
+} // end DriverEntry()
+
+
+ULONG
+Ultra14fFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo - Configuration information structure describing HBA
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PU14_BASEIO_ADDRESS baseIoAddress;
+ PVOID ioSpace;
+ PULONG adapterCount = Context;
+ UCHAR interruptLevel;
+ UCHAR dmaChannel;
+ UCHAR productId1;
+ UCHAR productId2;
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ while (AdapterAddresses[*adapterCount]) {
+
+ //
+ // Get the system address for this card.
+ // The card uses I/O space.
+ //
+
+ baseIoAddress = ScsiPortGetDeviceBase(
+ deviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]),
+ 0x10, // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+ //
+ // Update the adapter count to indicate this IO addr has been checked.
+ //
+
+ (*adapterCount)++;
+
+ productId1 = ScsiPortReadPortUchar(&baseIoAddress->ProductId1);
+ productId2 = ScsiPortReadPortUchar(&baseIoAddress->ProductId2);
+
+ if ((productId1 == ULTRASTOR_14F_ID1) &&
+ ((productId2 & (0xF0)) == ULTRASTOR_14F_ID2)) {
+
+ DebugPrint((1,
+ "Ultra14f: Adapter found at io address %x\n",
+ baseIoAddress));
+
+ break;
+ }
+
+ //
+ // If an adapter was not found unmap it.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension,
+ baseIoAddress);
+
+ } // end while (AdapterAddress ...
+
+ if (!AdapterAddresses[*adapterCount]) {
+
+ //
+ // No adapter was found. Indicate that we are done and there are no
+ // more adapters here. Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *adapterCount = 0;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // There is still more to look at.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Store IO base address of Ultra 14F in device extension.
+ //
+
+
+ deviceExtension->U14_BaseIO_Address = baseIoAddress;
+
+ deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0] =
+ ScsiPortReadPortUchar(&baseIoAddress->Config2) & 0x07;
+
+ //
+ // Indicate maximum transfer length in bytes.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
+
+ //
+ // The supported maximum number of physical segments is 17,
+ // but 16 is used to circumvent a firmware bug.
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ interruptLevel =
+ ScsiPortReadPortUchar(&baseIoAddress->Config1) & 0x30;
+
+ switch (interruptLevel) {
+ case US_INTERRUPT_LEVEL_15:
+ ConfigInfo->BusInterruptLevel = 15;
+ break;
+ case US_INTERRUPT_LEVEL_14:
+ ConfigInfo->BusInterruptLevel = 14;
+ break;
+ case US_INTERRUPT_LEVEL_11:
+ ConfigInfo->BusInterruptLevel = 11;
+ break;
+ case US_INTERRUPT_LEVEL_10:
+ ConfigInfo->BusInterruptLevel = 10;
+ break;
+ default:
+ DebugPrint((1,"Ultra24fConfiguration: No interrupt level\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ DebugPrint((2,"Ultra14f: IRQ Configurated at %x\n",
+ ConfigInfo->BusInterruptLevel));
+
+ //
+ // If product sub-model is 1 (indicate 34L), don't setup DMA
+ //
+
+ if (!(productId2 & 0x01)) {
+
+ //
+ // Get the dma Channel
+ //
+
+ dmaChannel =
+ ScsiPortReadPortUchar(&baseIoAddress->Config1) & 0xC0;
+
+ switch (dmaChannel) {
+ case US_DMA_CHANNEL_5:
+ ConfigInfo->DmaChannel = 5;
+ break;
+ case US_DMA_CHANNEL_6:
+ ConfigInfo->DmaChannel = 6;
+ break;
+ case US_DMA_CHANNEL_7:
+ ConfigInfo->DmaChannel = 7;
+ break;
+ case US_DMA_CHANNEL_5_RESERVED:
+ ConfigInfo->DmaChannel = 5;
+ break;
+ default:
+ DebugPrint((1,"Ultra14fFindAdapter: Invalid DMA channel\n"));
+ return SP_RETURN_ERROR;
+ } //end switch
+
+ DebugPrint((2,"Ultra14f: DMA Configurated at %x\n",
+ ConfigInfo->DmaChannel));
+
+ } //end if
+
+ //
+ // Check if ISA TSR port is enabled.
+ //
+
+ if ((ScsiPortReadPortUchar(&baseIoAddress->Config2) & 0xC0) ==
+ US_ISA_SECONDARY_ADDRESS) {
+
+ DebugPrint((1,
+ "Ultra14fFindAdapter: ATDISK emulation at secondary address\n"));
+
+ ConfigInfo->AtdiskSecondaryClaimed = TRUE;
+
+ } else if ((ScsiPortReadPortUchar(&baseIoAddress->Config2) & 0xC0) ==
+ US_ISA_PRIMARY_ADDRESS) {
+
+ DebugPrint((1,
+ "Ultra24fConfiguration: ATDISK emulation at primary address\n"));
+
+ ConfigInfo->AtdiskPrimaryClaimed = TRUE;
+ }
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]);
+
+ (*ConfigInfo->AccessRanges)[0].RangeLength = 16;
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ return SP_RETURN_FOUND;
+
+} // end Ultra14fFindAdapter()
+
+
+BOOLEAN
+Ultra14fInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PU14_BASEIO_ADDRESS u14_baseio_address = deviceExtension->U14_BaseIO_Address;
+ UCHAR status;
+ ULONG i;
+
+ //
+ // issue a Soft reset and a SCSI bus reset to Ultra14F
+ //
+
+ ScsiPortWritePortUchar(&u14_baseio_address->LocalDoorBellInterrupt,
+ US_HA_SOFT_RESET);
+
+ ScsiPortStallExecution(500*1000); //stall about 0.5 seconds
+
+ //
+ // Wait up to 1500,000 microseconds (1.5 sec) for adapter to initialize
+ // Keep polling for Soft Reset bit to be clear.
+ //
+
+ for (i = 0; i < 150000; i++) {
+
+ ScsiPortStallExecution(10);
+
+ status = ScsiPortReadPortUchar(
+ &u14_baseio_address->LocalDoorBellInterrupt);
+
+ if (!(status & US_HA_SOFT_RESET)) {
+
+ break;
+ }
+ }
+
+ //
+ // Check if reset failed or succeeded.
+ //
+
+ if (status & US_HA_SOFT_RESET) {
+ DebugPrint((1, "Ultra14F, HwInitialize: Soft reset failed.\n"));
+ }
+
+ //
+ // Enable ICMINT and SINTEN
+ //
+
+ ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellMask,
+ US_ENABLE_ICMINT+US_ENABLE_SYSTEM_DOORBELL);
+
+ //
+ // reset the ICMINT
+ //
+
+ ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellInterrupt,
+ US_RESET_ICMINT);
+
+ return(TRUE);
+
+ //
+ // Enable system doorbell interrupt and Incoming mail interrupt.
+ //
+
+ ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellMask,
+ (US_ENABLE_ICMINT + US_ENABLE_SYSTEM_DOORBELL));
+
+} // end Ultra14fInitialize()
+
+
+BOOLEAN
+Ultra14fStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to send an MSCP.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PU14_BASEIO_ADDRESS u14_baseio_address = deviceExtension->U14_BaseIO_Address;
+ PSPECIFIC_LU_EXTENSION luExtension;
+ PMSCP mscp;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ ULONG physicalMscp;
+ ULONG length;
+ ULONG i = 0;
+
+ //
+ // Check for ABORT command.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ DebugPrint((1, "Ultra14fStartIo: Received Abort command\n"));
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ abortedSrb = ScsiPortGetSrb(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ if (abortedSrb != Srb->NextSrb ||
+ abortedSrb->SrbStatus != SRB_STATUS_PENDING) {
+
+ DebugPrint((1, "Ultra14fStartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ } else {
+
+ //
+ // Check if interrupt pending.
+ //
+
+ if (ScsiPortReadPortUchar(&u14_baseio_address->SystemDoorBellInterrupt)
+ & US_ICMINT) {
+
+ DebugPrint((1,"Ultra14fStartIo: Interrupt pending\n"));
+
+ //
+ // Reset the ICMINT system doorbell interrupt.
+ //
+
+ ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellInterrupt,
+ US_RESET_ICMINT);
+
+ //
+ // Abort the outstanding SRB.
+ //
+
+ abortedSrb->SrbStatus = SRB_STATUS_ABORTED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ abortedSrb);
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ } else {
+
+ //
+ // Ultra14f adapter does not support the abort command.
+ // Reset the bus. The reset routine will complete all
+ // outstanding requests and indicate ready for next request.
+ //
+
+ if (!Ultra14fResetBus(deviceExtension, Srb->PathId)) {
+
+ DebugPrint((1,
+ "Ultra14fStartIo: Reset scsi bus failed\n"));
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+ }
+ }
+
+ return TRUE;
+
+ } else {
+
+ //
+ // This is a request to a device.
+ //
+
+ mscp = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in MSCP.
+ //
+
+ mscp->SrbAddress = Srb;
+ mscp->AbortSrb = NULL;
+ }
+
+ //
+ // Get MSCP physical address.
+ //
+
+ physicalMscp =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, mscp, &length));
+
+ //
+ // Assume physical address is contiguous for size of ECB.
+ //
+
+ ASSERT(length >= sizeof(MSCP));
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Determine the logical unit that this request is for.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ //
+ // Build MSCP for this request.
+ //
+
+ BuildMscp(deviceExtension, Srb, luExtension);
+
+ break;
+
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // wait for a free OGM Slot (OGMINT to be clear)
+ //
+
+ for (i=0; i<50000; i++) {
+
+ if (!(ScsiPortReadPortUchar(
+ &u14_baseio_address->LocalDoorBellInterrupt) &
+ US_OGMINT)) {
+ break;
+
+ } else {
+
+ //
+ // Stall 1 microsecond before trying again.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i == 50000) {
+
+ //
+ // Let operating system time out SRB.
+ //
+
+ DebugPrint((1,"Ultra14fStartIo: Timed out waiting for mailbox\n"));
+
+ } else {
+
+ //
+ // Write MSCP pointer to mailbox.
+ //
+
+ ScsiPortWritePortUlong(&u14_baseio_address->OutGoingMailPointer,
+ physicalMscp);
+
+ //
+ // Issue a OGMINT to send to the host adapter
+ //
+
+ ScsiPortWritePortUchar(&u14_baseio_address->LocalDoorBellInterrupt,
+ US_OGMINT);
+
+ if (!mscp->DisableDisconnect) {
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest, deviceExtension);
+
+ }
+ }
+
+ return TRUE;
+
+} // end Ultra14fStartIo()
+
+
+BOOLEAN
+Ultra14fInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the Ultra14f SCSI adapter.
+ It reads the system Doorbell interrupt register to determine if the
+ adapter is indeed the source of the interrupt and clears the interrupt at
+ the device.
+ If the adapter is interrupting because a mailbox is full, the MSCP is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PMSCP mscp;
+ PSCSI_REQUEST_BLOCK srb;
+ PU14_BASEIO_ADDRESS u14_baseio_address =
+ deviceExtension->U14_BaseIO_Address;
+ ULONG physicalMscp;
+
+ //
+ // Check interrupt pending.
+ //
+
+ if (!(ScsiPortReadPortUchar(&u14_baseio_address->SystemDoorBellInterrupt)
+ & US_ICMINT)) {
+
+ //
+ // Handle spurious interrupt.
+ //
+
+ DebugPrint((2,"Ultra14fInterrupt: Spurious interrupt\n"));
+
+ return FALSE;
+ }
+
+ //
+ // Get physical address of MSCP
+ //
+
+ physicalMscp = ScsiPortReadPortUlong(
+ &u14_baseio_address->InComingMailPointer);
+
+ //
+ // Get virtual MSCP address.
+ //
+
+ mscp = ScsiPortGetVirtualAddress(deviceExtension,
+ ScsiPortConvertUlongToPhysicalAddress(physicalMscp));
+
+ //
+ // Make sure the physical address was valid.
+ //
+
+ if (mscp == NULL) {
+
+ ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellInterrupt,
+ US_RESET_ICMINT);
+
+ DebugPrint((1,"\n\nUltra14f Interrupt: recieve NULL MSCP\n"));
+
+ return FALSE;
+
+ } else {
+
+ //
+ // Get SRB from MSCP.
+ //
+
+ srb = mscp->SrbAddress;
+
+ //
+ // Check status of completing MSCP in mailbox. and update SRB statuses
+ //
+
+ if (!((mscp->AdapterStatus) | (mscp->TargetStatus))) {
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+
+ } else {
+
+ //
+ // Translate adapter status to SRB status
+ // and log error if necessary.
+ //
+
+ MapErrorToSrbStatus(deviceExtension, srb);
+
+ }
+ }
+
+ if (mscp->DisableDisconnect) {
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest, deviceExtension);
+
+ }
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ //
+ // Reset the ICMINT system doorbell interrupt.
+ //
+
+ ScsiPortWritePortUchar(&u14_baseio_address->SystemDoorBellInterrupt,
+ US_RESET_ICMINT);
+
+ return TRUE;
+
+} // end Ultra14fInterrupt()
+
+
+VOID
+BuildMscp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PSPECIFIC_LU_EXTENSION luExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Build MSCP for Ultra14f from SRB.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PMSCP mscp = Srb->SrbExtension;
+ ULONG length;
+
+ //
+ // Set MSCP command.
+ //
+
+ mscp->OperationCode = MSCP_OPERATION_SCSI_COMMAND;
+
+ //
+ // Check SRB for disabled disconnect.
+ //
+ // NOTE: UltraStor 14f SCSI adapter does not
+ // support disabling synchronous transfer
+ // per request.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
+ mscp->DisableDisconnect = TRUE;
+ } else {
+
+ //
+ // Earlier ultra14f firmware has a bug with disconnect.
+ // A counter is used here to check whether or not to disable
+ // disconnect due to disconnect related problem that already happened
+ // for the requested device,
+ //
+
+ if (luExtension->DisconnectErrorCount >= 5) {
+
+ if (luExtension->DisconnectErrorCount == 5) {
+
+ ScsiPortLogError(DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_BAD_FW_WARNING,
+ 1 << 16);
+ }
+
+ mscp->DisableDisconnect = TRUE;
+
+ }
+ else {
+
+ mscp->DisableDisconnect = FALSE;
+
+ }
+ }
+
+
+ //
+ // Set channel, target id and lun.
+ //
+
+ mscp->Channel = Srb->PathId;
+ mscp->TargetId = Srb->TargetId;
+ mscp->Lun = Srb->Lun;
+
+ //
+ // Set CDB length and copy to MSCP.
+ //
+
+ mscp->CdbLength = Srb->CdbLength;
+ ScsiPortMoveMemory(mscp->Cdb, Srb->Cdb, Srb->CdbLength);
+
+ //
+ // Build SGL in MSCP if data transfer.
+ //
+
+ if (Srb->DataTransferLength > 0) {
+
+ //
+ // Build scattergather descriptor list.
+ //
+
+ BuildSgl(DeviceExtension, Srb);
+
+ //
+ // Set transfer direction.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ //
+ // Write request.
+ //
+
+ mscp->TransferDirection = MSCP_TRANSFER_OUT;
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ //
+ // Read request.
+ //
+
+ mscp->TransferDirection = MSCP_TRANSFER_IN;
+ }
+
+ } else {
+
+ //
+ // Set up MSCP for no data transfer.
+ //
+
+ mscp->TransferDirection = MSCP_NO_TRANSFER;
+ mscp->DataLength = 0;
+ mscp->ScatterGather = FALSE;
+ mscp->SgDescriptorCount = 0;
+ }
+
+ //
+ // Setup auto sense if necessary.
+ //
+
+ if (Srb->SenseInfoBufferLength != 0 &&
+ !(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)) {
+
+ //
+ // Set the flag to enable auto sense and fill in the address and
+ // length of the sense buffer.
+ //
+
+ mscp->RequestSenseLength = Srb->SenseInfoBufferLength;
+ mscp->RequestSensePointer = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ Srb->SenseInfoBuffer,
+ &length));
+
+ ASSERT(length >= Srb->SenseInfoBufferLength);
+
+ } else {
+
+ //
+ // Ultra14F uses nonzero request sense pointer
+ // as an indication of autorequestsense.
+ //
+
+ mscp->RequestSenseLength = 0;
+ mscp->RequestSensePointer = 0;
+ }
+
+ //
+ // Zero out command link, status and abort fields.
+ //
+
+ mscp->CommandLink = 0;
+ mscp->CommandLinkId = 0;
+ mscp->AdapterStatus = 0;
+ mscp->TargetStatus = 0;
+ mscp->AbortSrb = 0;
+
+ //
+ // Bypass cache.
+ //
+
+ mscp->UseCache = FALSE;
+
+ return;
+
+} // end BuildMscp()
+
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list in the MSCP.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PMSCP mscp = Srb->SrbExtension;
+ PSDL sdl = &mscp->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG descriptorCount = 0;
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SGL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SDL));
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ sdl->Descriptor[descriptorCount].Address = physicalAddress;
+ sdl->Descriptor[descriptorCount].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ //
+ // Check for only one descriptor. As an optimization, in these
+ // cases, use nonscattergather requests.
+ //
+
+ if (descriptorCount == 1) {
+
+ //
+ // Set descriptor count to 0.
+ //
+
+ mscp->SgDescriptorCount = 0;
+
+ //
+ // Set data pointer to data buffer.
+ //
+
+ mscp->DataPointer = physicalAddress;
+
+ //
+ // Set data transfer length.
+ //
+
+ mscp->DataLength = Srb->DataTransferLength;
+
+ //
+ // Clear scattergather bit.
+ //
+
+ mscp->ScatterGather = FALSE;
+
+ } else {
+
+ //
+ // Write SDL count to MSCP.
+ //
+
+ mscp->SgDescriptorCount = (UCHAR)descriptorCount;
+
+ //
+ // Write SGL address to ECB.
+ //
+
+ mscp->DataPointer = physicalSdl;
+
+ mscp->DataLength = Srb->DataTransferLength;
+
+ //
+ // Indicate scattergather operation.
+ //
+
+ mscp->ScatterGather = TRUE;
+ }
+
+ return;
+
+} // end BuildSgl()
+
+
+BOOLEAN
+Ultra14fResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Ultra14f SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PU14_BASEIO_ADDRESS u14_baseio_address =
+ deviceExtension->U14_BaseIO_Address;
+ ULONG j;
+
+ //
+ // The Ultra14f only supports a single SCSI channel.
+ //
+
+ UNREFERENCED_PARAMETER(PathId);
+
+
+ //
+ // Reset SCSI bus.
+ //
+
+ ScsiPortWritePortUchar(&u14_baseio_address->LocalDoorBellInterrupt,
+ (US_HA_SOFT_RESET | US_ENABLE_SCSI_BUS_RESET));
+
+ //
+ // Wait for local processor to clear both reset bits.
+ //
+
+ for (j=0; j<200000; j++) {
+
+ if (!(ScsiPortReadPortUchar(&u14_baseio_address->LocalDoorBellInterrupt) &
+ (US_HA_SOFT_RESET | US_ENABLE_SCSI_BUS_RESET))) {
+
+ break;
+ }
+
+ ScsiPortStallExecution(10);
+
+ } // end for (j=0 ...
+
+ if (j == 200000) {
+
+ DebugPrint((1,"Ultra14fResetBus: Reset timed out\n"));
+
+ //
+ // Busy has not gone low. Assume the card is gone.
+ // Log the error and fail the request.
+ //
+
+ ScsiPortLogError(deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 16);
+
+ return FALSE;
+ }
+
+ // ScsiPortStallExecution(200*1000); // has to wait about 2 seconds
+ // for F/W to be actually ready
+ // don't do this for now until
+ // Ha_Inquiry is implemented later
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)0,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end Ultra14fResetBus()
+
+
+VOID
+MapErrorToSrbStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+/*++
+
+Routine Description:
+
+ Translate Ultra14f error to SRB error.
+
+Arguments:
+
+ Device Extension for logging error
+ SRB
+
+Return Value:
+
+ Updated SRB
+
+--*/
+
+{
+ ULONG logError = 0;
+ UCHAR srbStatus;
+ PMSCP mscp = Srb->SrbExtension;
+ PSPECIFIC_LU_EXTENSION luExtension;
+
+ switch (mscp->AdapterStatus) {
+
+ case MSCP_NO_ERROR:
+ srbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
+ break;
+
+ case MSCP_SELECTION_TIMEOUT:
+ srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ DebugPrint((1,"MapErrorToSrbStatus: Target SCSI device not found\n"));
+ break;
+
+ case MSCP_BUS_UNDER_OVERRUN:
+ DebugPrint((1,"MapErrorToSrbStatus: Data over/underrun\n"));
+ srbStatus = SRB_STATUS_DATA_OVERRUN;
+ break;
+
+ case MSCP_UNEXPECTED_BUS_FREE:
+
+ //
+ // Ultra14F older firmware has a bug that causes unexpected bus free
+ // error and invalid SCSI command errors during disconnect. A counter
+ // is used here to keep track of the number of such error for each
+ // device. When the number of maximum disconnected error count is
+ // reached, the driver will disable disconnect for the device with the
+ // disconnected problem.
+ //
+
+ DebugPrint((1,"MapErrorToSrbStatus: Unexpected bus free\n"));
+
+ //
+ // Determine the logical unit that this request is for.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ logError = SP_PROTOCOL_ERROR;
+ luExtension->DisconnectErrorCount += 1;
+ srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ break;
+
+ case MSCP_ILLEGAL_SCSI_COMMAND:
+
+ //
+ // Ultra14F older firmware has a bug that causes unexpected bus free
+ // error and invalid SCSI command errors during disconnect. A counter
+ // is used here to keep track of the number of such error for each
+ // device. When the number of maximum disconnected error count is
+ // reached, the driver will disable disconnect for the device with the
+ // disconnected problem.
+ //
+
+ DebugPrint((1,"MapErrorToSrbStatus: Illegal SCSI Command\n"));
+
+ //
+ // Determine the logical unit that this request is for.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(DeviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+ luExtension->DisconnectErrorCount += 1;
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case MSCP_INVALID_PHASE_CHANGE:
+ DebugPrint((1,"MapErrorToSrbStatus: Invalid bus phase\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ break;
+
+ case MSCP_INVALID_COMMAND:
+ case MSCP_INVALID_PARAMETER:
+ case MSCP_INVALID_DATA_LIST:
+ case MSCP_INVALID_SG_LIST:
+// case MSCP_ILLEGAL_SCSI_COMMAND:
+ DebugPrint((1,"MapErrorToSrbStatus: Invalid command %x\n", mscp->AdapterStatus));
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case MSCP_BUS_RESET_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: Bus reset\n"));
+ srbStatus = SRB_STATUS_BUS_RESET;
+ break;
+
+ case MSCP_ABORT_NOT_FOUND:
+ case MSCP_SCSI_BUS_ABORT_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: Abort not found\n"));
+ srbStatus = SRB_STATUS_ABORT_FAILED;
+ break;
+
+ default:
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ } // end switch ...
+
+ //
+ // Log error if indicated.
+ //
+
+ if (logError) {
+
+ ScsiPortLogError(
+ DeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ 2 << 16 | mscp->AdapterStatus
+ );
+ }
+
+ //
+ // Set SRB status.
+ //
+
+ Srb->SrbStatus = srbStatus;
+
+ //
+ // Set target SCSI status in SRB.
+ //
+
+ Srb->ScsiStatus = mscp->TargetStatus;
+
+ return;
+
+} // end MapErrorToSrbStatus()
diff --git a/private/ntos/miniport/ultra14f/ultra14f.h b/private/ntos/miniport/ultra14f/ultra14f.h
new file mode 100644
index 000000000..b5ec0c924
--- /dev/null
+++ b/private/ntos/miniport/ultra14f/ultra14f.h
@@ -0,0 +1,223 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ultra14f.h
+
+Abstract:
+
+ This file contains the structures and definitions that define
+ the ULTRASTOR 14F ISA SCSI host bus adapter.
+
+Author:
+
+ Stephen Fong (SF)
+
+Revision History:
+
+
+--*/
+
+#include "scsi.h"
+
+//
+// SCATTER/GATHER definitions
+//
+
+#define MAXIMUM_SG_DESCRIPTORS 16
+#define MAXIMUM_TRANSFER_LENGTH 0xFFFFFFFF
+
+typedef struct _SGD {
+ ULONG Address;
+ ULONG Length;
+} SGD, *PSGD;
+
+typedef struct _SDL {
+ SGD Descriptor[MAXIMUM_SG_DESCRIPTORS];
+} SDL, *PSDL;
+
+//
+// MailBox SCSI Command Packet
+//
+
+#pragma pack(1)
+
+typedef struct _MSCP {
+ UCHAR OperationCode:3; // byte 00
+ UCHAR TransferDirection:2;
+ UCHAR DisableDisconnect:1;
+ UCHAR UseCache:1;
+ UCHAR ScatterGather:1;
+ UCHAR TargetId:3; // byte 01
+ UCHAR Channel:2;
+ UCHAR Lun:3;
+ ULONG DataPointer; // byte 02
+ ULONG DataLength; // byte 06
+ ULONG CommandLink; // byte 0a
+ UCHAR CommandLinkId; // byte 0e
+ UCHAR SgDescriptorCount; // byte 0f
+ UCHAR RequestSenseLength; // byte 10
+ UCHAR CdbLength; // byte 11
+ UCHAR Cdb[12]; // byte 12
+ UCHAR AdapterStatus; // byte 1e
+ UCHAR TargetStatus; // byte 1f
+ ULONG RequestSensePointer; // byte 20
+ PSCSI_REQUEST_BLOCK SrbAddress; // byte 24
+ PSCSI_REQUEST_BLOCK AbortSrb; // byte 28
+ SDL Sdl; // byte 2c
+} MSCP, *PMSCP;
+
+#pragma pack()
+
+//
+// Operation codes
+//
+
+#define MSCP_OPERATION_HA_COMMAND 1
+#define MSCP_OPERATION_SCSI_COMMAND 2
+#define MSCP_OPERATION_DEVICE_RESET 4
+
+//
+// Transfer direction
+//
+
+#define MSCP_TRANSFER_SCSI 0
+#define MSCP_TRANSFER_IN 1
+#define MSCP_TRANSFER_OUT 2
+#define MSCP_NO_TRANSFER 3
+
+//
+// Host Adapter Error Codes
+//
+
+#define MSCP_NO_ERROR 0x00
+#define MSCP_INVALID_COMMAND 0x01
+#define MSCP_INVALID_PARAMETER 0x02
+#define MSCP_INVALID_DATA_LIST 0x03
+#define MSCP_CPU_DIAG_ERROR 0x30
+#define MSCP_BUFFER_RAM_DIAG_ERROR 0x31
+#define MSCP_STATIC_RAM_DIAG_FAIL 0x32
+#define MSCP_BMIC_CHIP_DIAG_ERROR 0x33
+#define MSCP_CACHE_TAG_RAM_FAIL 0x34
+#define MSCP_ROM_CHECKSUM_CHECK 0x35
+#define MSCP_INVALID_CONFIG_DATA 0x36
+#define MSCP_BUFFER_UNDERRUN 0x40
+#define MSCP_BUFFER_OVERRUN 0x41
+#define MSCP_BUFFER_PARITY_ERROR 0x42
+#define MSCP_ISA_BUS_PARITY_ERROR 0x43
+#define MSCP_ISA_INTERFACE_ERROR 0x44
+#define MSCP_SCSI_BUS_ABORT_ERROR 0x84
+#define MSCP_SELECTION_TIMEOUT 0x91
+#define MSCP_BUS_UNDER_OVERRUN 0x92
+#define MSCP_UNEXPECTED_BUS_FREE 0x93
+#define MSCP_INVALID_PHASE_CHANGE 0x94
+#define MSCP_ILLEGAL_SCSI_COMMAND 0x96
+#define MSCP_AUTO_SENSE_ERROR 0x9B
+#define MSCP_UNEXPECTED_COMPLETE 0x9F
+#define MSCP_BUS_RESET_ERROR 0xA3
+
+#define MSCP_ABORT_NOT_FOUND 0xAA
+#define MSCP_INVALID_SG_LIST 0xFF
+
+//
+// ISA Registers definition
+//
+
+#pragma pack(1)
+
+typedef struct _U14_BASEIO_ADDRESS {// baseioport offset
+ UCHAR LocalDoorBellMask; // + 0
+ UCHAR LocalDoorBellInterrupt; // + 1
+ UCHAR SystemDoorBellMask; // + 2
+ UCHAR SystemDoorBellInterrupt; // + 3
+ UCHAR ProductId1; // + 4
+ UCHAR ProductId2; // + 5
+ UCHAR Config1; // + 6
+ UCHAR Config2; // + 7
+ ULONG OutGoingMailPointer; // + 8
+ ULONG InComingMailPointer; // + C
+} U14_BASEIO_ADDRESS, *PU14_BASEIO_ADDRESS;
+
+#pragma pack()
+
+//
+// UltraStor 14F board id
+//
+
+#define ULTRASTOR_14F_ID1 0x56
+#define ULTRASTOR_14F_ID2 0x40 // to work with both 14F, 34L and other models
+ // driver should mask ID2 byte bit0-bit3 to 0
+
+//
+// InComing Statuses
+//
+
+#define ICM_STATUS_COMPLETE_SUCCESS 0x01
+#define ICM_STATUS_COMPLETE_ERROR 0x02
+#define ICM_STATUS_ABORT_SUCCESS 0x03
+#define ICM_STATUS_ABORT_FAILED 0x04
+
+//
+// DMA Channels
+//
+#define US_DMA_CHANNEL_5 0x00
+#define US_DMA_CHANNEL_6 0x40
+#define US_DMA_CHANNEL_7 0x80
+#define US_DMA_CHANNEL_5_RESERVED 0xC0
+
+//
+// Interrupt levels
+//
+
+#define US_INTERRUPT_LEVEL_15 0x00
+#define US_INTERRUPT_LEVEL_14 0x10
+#define US_INTERRUPT_LEVEL_11 0x20
+#define US_INTERRUPT_LEVEL_10 0x30
+
+//
+// Alternate address selection
+//
+
+#define US_ISA_SECONDARY_ADDRESS 0x40
+
+//
+// ISA TSR Port enabled
+//
+
+#define US_ISA_PRIMARY_ADDRESS 0x00
+
+#define US_ISA_DISABLE 0x80
+
+//
+// Local doorbell mask (baseaddr+0)
+//
+
+#define US_ENABLE_OGMINT 0x01
+#define US_ENABLE_SCSI_BUS_RESET 0x20
+#define US_ENABLE_HA_SOFT_RESET 0x40
+
+//
+// Local doorbell interrupt/status (baseaddr+1)
+//
+
+#define US_OGMINT 0x01
+#define US_SCSI_BUS_RESET 0x20
+#define US_HA_SOFT_RESET 0x40
+
+//
+// System doorbell mask (baseaddr+2)
+//
+
+#define US_ENABLE_ICMINT 0x01
+#define US_ENABLE_SYSTEM_DOORBELL 0x80
+
+//
+// System doorbell interrupt (baseaddr+3)
+//
+
+#define US_ICMINT 0x01
+#define US_SINT_PENDING 0x80
+
+#define US_RESET_ICMINT 0x01
diff --git a/private/ntos/miniport/ultra14f/ultra14f.rc b/private/ntos/miniport/ultra14f/ultra14f.rc
new file mode 100644
index 000000000..32fdc868b
--- /dev/null
+++ b/private/ntos/miniport/ultra14f/ultra14f.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "ULTRASTOR ISA SCSI Adapter Driver"
+#define VER_INTERNALNAME_STR "ultra14f.sys"
+#define VER_ORIGINALFILENAME_STR "ultra14f.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/ultra24f/makefile b/private/ntos/miniport/ultra24f/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/ultra24f/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/ultra24f/sources b/private/ntos/miniport/ultra24f/sources
new file mode 100644
index 000000000..10975e425
--- /dev/null
+++ b/private/ntos/miniport/ultra24f/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=ultra24f
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=ultra24f.c ultra24f.rc
diff --git a/private/ntos/miniport/ultra24f/ultra24f.c b/private/ntos/miniport/ultra24f/ultra24f.c
new file mode 100644
index 000000000..b720d1920
--- /dev/null
+++ b/private/ntos/miniport/ultra24f/ultra24f.c
@@ -0,0 +1,1401 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ultra24f.c
+
+Abstract:
+
+ This is the port driver for the ULTRASTOR 24F EISA SCSI adapter.
+
+Authors:
+
+ Mike Glass
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "ultra24f.h" // includes scsi.h
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+ PEISA_CONTROLLER EisaController;
+ UCHAR HostTargetId;
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+//
+// Function declarations
+//
+// Functions that start with 'Ultra24f' are entry points
+// for the OS port driver.
+//
+
+ULONG
+DriverEntry(
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ );
+
+ULONG
+Ultra24fFindAdapter(
+ IN PVOID DeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+Ultra24fInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Ultra24fStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+Ultra24fInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Ultra24fResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+//
+// This function is called from Ultra24fStartIo.
+//
+
+VOID
+BuildMscp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BuildMscp.
+//
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+SendCommand(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR OperationCode,
+ IN ULONG Address
+ );
+
+//
+// This function is called from Ultra24fInterrupt.
+//
+
+VOID
+MapErrorToSrbStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG i;
+ ULONG AdapterCount = 0;
+
+ DebugPrint((1,"\n\nSCSI UltraStor 24f MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize =
+ sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = Ultra24fInitialize;
+ hwInitializationData.HwFindAdapter = Ultra24fFindAdapter;
+ hwInitializationData.HwStartIo = Ultra24fStartIo;
+ hwInitializationData.HwInterrupt = Ultra24fInterrupt;
+ hwInitializationData.HwResetBus = Ultra24fResetBus;
+
+ //
+ // Set number of access ranges and bus type.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Indicate auto request sense is supported.
+ //
+
+ hwInitializationData.AutoRequestSense = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ //
+ // Ask for SRB extensions for MSCPs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(MSCP);
+
+ return ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData,
+ &AdapterCount);
+
+} // end DriverEntry()
+
+
+ULONG
+Ultra24fFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo - Configuration information structure describing HBA
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ ULONG eisaSlotNumber;
+ PVOID eisaAddress;
+ PULONG adapterCount = Context;
+ UCHAR interruptLevel;
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+ for (eisaSlotNumber=*adapterCount + 1;
+ eisaSlotNumber<MAXIMUM_EISA_SLOTS;
+ eisaSlotNumber++) {
+
+ //
+ // Update the adapter count to indicate this slot has been checked.
+ //
+
+ (*adapterCount)++;
+
+ //
+ // Get the system address for this card.
+ // The card uses I/O space.
+ //
+
+ eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ TRUE);
+
+ eisaController =
+ (PEISA_CONTROLLER)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE);
+
+ if (ScsiPortReadPortUlong(&eisaController->BoardId) ==
+ ULTRASTOR_24F_EISA_ID) {
+
+ DebugPrint((1,
+ "Ultra24f: Adapter found at EISA slot %d\n",
+ eisaSlotNumber));
+
+ break;
+ }
+
+ //
+ // If an adapter was not found unmap it.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension,
+ eisaAddress);
+
+ } // end for (eisaSlotNumber ...
+
+ if (!(eisaSlotNumber < MAXIMUM_EISA_SLOTS)) {
+
+ //
+ // No adapter was found. Indicate that we are done and there are no
+ // more adapters here. Clear the adapter count for the next bus.
+ //
+
+ *Again = FALSE;
+ *adapterCount = 0;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // There is still more to look at.
+ //
+
+ *Again = TRUE;
+
+ //
+ // Store base address of EISA registers in device extension.
+ //
+
+ deviceExtension->EisaController = eisaController;
+
+ deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0] =
+ ScsiPortReadPortUchar(&eisaController->HostAdapterId) & 0x07;
+
+ //
+ // Indicate maximum transfer length in bytes.
+ //
+
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
+
+ //
+ // Maximum number of physical segments is 32.
+ //
+
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
+
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ interruptLevel =
+ ScsiPortReadPortUchar(&eisaController->InterruptLevel) & 0xF0;
+
+ switch (interruptLevel) {
+ case US_INTERRUPT_LEVEL_15:
+ ConfigInfo->BusInterruptLevel = 15;
+ break;
+ case US_INTERRUPT_LEVEL_14:
+ ConfigInfo->BusInterruptLevel = 14;
+ break;
+ case US_INTERRUPT_LEVEL_11:
+ ConfigInfo->BusInterruptLevel = 11;
+ break;
+ case US_INTERRUPT_LEVEL_10:
+ ConfigInfo->BusInterruptLevel = 10;
+ break;
+ default:
+ DebugPrint((1,"Ultra24fFindAdapter: No interrupt level\n"));
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // Set interrupt level.
+ //
+
+ ConfigInfo->InterruptMode = Latched;
+
+ //
+ // Check is ISA TSR port is enabled and the primary address is indicated.
+ //
+
+ if (!(ScsiPortReadPortUchar(&eisaController->InterruptLevel) &
+ US_SECONDARY_ADDRESS)) {
+
+ //
+ // If this bit is set then the unsupported secondary address is
+ // treated as an indication that the WD1003 compatibility mode
+ // is disabled. If it is not set then the ATDISK primary address
+ // must be claimed.
+ //
+
+ DebugPrint((1,
+ "Ultra24fFindAdapter: ATDISK emulation at Primary address\n"));
+
+ // ConfigInfo->AtdiskPrimaryClaimed = TRUE;
+ }
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + 0xC80);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ return SP_RETURN_FOUND;
+
+} // end Ultra24fFindAdapter()
+
+
+BOOLEAN
+Ultra24fInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter by enabling system doorbell interrupts.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+
+ //
+ // Enable system doorbell interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
+ US_ENABLE_DOORBELL_INTERRUPT);
+
+ ScsiPortWritePortUchar(&eisaController->SystemInterrupt,
+ US_ENABLE_SYSTEM_DOORBELL);
+
+ return(TRUE);
+
+} // end Ultra24fInitialize()
+
+
+BOOLEAN
+Ultra24fStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel to send an MSCP.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PMSCP mscp;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ UCHAR opCode;
+ ULONG physicalMscp;
+ ULONG length;
+ ULONG i = 0;
+
+ ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
+
+ //
+ // Make sure that the request is for LUN 0. This
+ // is because the Ultra24F scsi adapter echoes devices
+ // on extra LUNs.
+ //
+
+ if (Srb->Lun != 0) {
+
+ //
+ // The Ultra24F card only supports logical unit zero.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Check if this is an abort function.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Verify that SRB to abort is still outstanding.
+ //
+
+ abortedSrb = ScsiPortGetSrb(deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ Srb->QueueTag);
+
+ if (abortedSrb != Srb->NextSrb ||
+ abortedSrb->SrbStatus != SRB_STATUS_PENDING) {
+
+ DebugPrint((1, "Ultra24fStartIo: SRB to abort already completed\n"));
+
+ //
+ // Complete abort SRB.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+ }
+
+ //
+ // Get MSCP to abort.
+ //
+
+ mscp = Srb->NextSrb->SrbExtension;
+
+ //
+ // Set abort SRB for completion.
+ //
+
+ mscp->AbortSrb = Srb;
+
+ } else {
+
+ //
+ // This is a request to a device.
+ //
+
+ mscp = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in MSCP and
+ // clear ABORT SRB field.
+ //
+
+ mscp->SrbAddress = Srb;
+ mscp->AbortSrb = NULL;
+ }
+
+ //
+ // Get MSCP physical address.
+ //
+
+ physicalMscp =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, mscp, &length));
+
+ //
+ // Assume physical address is contiguous for size of ECB.
+ //
+
+ ASSERT(length >= sizeof(MSCP));
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Build MSCP for this request.
+ //
+
+ BuildMscp(deviceExtension, Srb);
+
+ opCode = OGM_COMMAND_SLOT_ACTIVE;
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1, "Ultra24fStartIo: Abort request received\n"));
+
+ opCode = OGM_COMMAND_SLOT_ABORT;
+
+ break;
+
+ default:
+
+ DebugPrint((1, "Ultra24fStartIo: Unrecognized SRB function\n"));
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ //
+ // Write MSCP pointer and command to mailbox.
+ //
+
+ for (i=0; i<500; i++) {
+
+ if (ScsiPortReadPortUchar(&eisaController->OutGoingMailCommand) ==
+ OGM_COMMAND_SLOT_FREE) {
+
+ break;
+
+ } else {
+
+ //
+ // Stall 1 microsecond before trying again.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i == 500) {
+
+ //
+ // Let operating system time out SRB.
+ //
+
+ DebugPrint((1,"Ultra24fStartIo: Timed out waiting for mailbox\n"));
+
+ } else {
+
+ //
+ // Write MSCP pointer to mailbox. This 4-byte register is not
+ // dword aligned so it must be read a byte at a time.
+ //
+
+ ScsiPortWritePortUchar((UCHAR *)(&eisaController->OutGoingMailPointer),
+ (UCHAR)(physicalMscp & 0xff));
+ ScsiPortWritePortUchar((UCHAR *)(&eisaController->OutGoingMailPointer)+1,
+ (UCHAR)((physicalMscp>>8) & 0xff));
+ ScsiPortWritePortUchar((UCHAR *)(&eisaController->OutGoingMailPointer)+2,
+ (UCHAR)((physicalMscp>>16) & 0xff));
+ ScsiPortWritePortUchar((UCHAR *)(&eisaController->OutGoingMailPointer)+3,
+ (UCHAR)((physicalMscp>>24) & 0xff));
+
+ //
+ // Write command to mailbox.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->OutGoingMailCommand, opCode);
+
+ //
+ // Ring the local doorbell.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
+ US_MSCP_AVAILABLE);
+ }
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextLuRequest,
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun);
+
+ return TRUE;
+
+} // end Ultra24fStartIo()
+
+
+BOOLEAN
+Ultra24fInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the Ultra24f SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the MSCP is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PMSCP mscp;
+ PSCSI_REQUEST_BLOCK srb;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ ULONG physicalMscp;
+ UCHAR mscpStatus;
+
+ //
+ // Check interrupt pending.
+ //
+
+ if (ScsiPortReadPortUchar(&eisaController->SystemDoorBellInterrupt) &
+ US_RESET_MSCP_COMPLETE) {
+
+ //
+ // Reset system doorbell interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
+ US_RESET_MSCP_COMPLETE);
+
+ } else {
+
+ //
+ // Handle spurious interrupt.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Check status of completing MSCP in mailbox.
+ //
+
+ mscpStatus = ScsiPortReadPortUchar(&eisaController->InComingMailStatus);
+
+ switch (mscpStatus) {
+
+ case ICM_STATUS_COMPLETE_SUCCESS:
+ case ICM_STATUS_COMPLETE_ERROR:
+
+ //
+ // Get physical address of MSCP
+ //
+
+ physicalMscp = ScsiPortReadPortUlong(&eisaController->InComingMailPointer);
+
+ //
+ // Get virtual MSCP address.
+ //
+
+ mscp = ScsiPortGetVirtualAddress(deviceExtension,
+ ScsiPortConvertUlongToPhysicalAddress(physicalMscp));
+
+ //
+ // Make sure the physical address was valid.
+ //
+
+ if (mscp == NULL) {
+ break;
+ }
+
+ //
+ // Get SRB from MSCP.
+ //
+
+ srb = mscp->SrbAddress;
+
+ //
+ // Update SRB statuses.
+ //
+
+ if (mscpStatus == ICM_STATUS_COMPLETE_ERROR) {
+
+ //
+ // Translate adapter status to SRB status
+ // and log error if necessary.
+ //
+
+ MapErrorToSrbStatus(deviceExtension, srb);
+
+ } else {
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+ srb->ScsiStatus = SCSISTAT_GOOD;
+ }
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ break;
+
+ case ICM_STATUS_ABORT_SUCCESS:
+ case ICM_STATUS_ABORT_FAILED:
+
+ DebugPrint((1,"Ultra24fInterrupt: Abort command completed\n"));
+ break;
+
+ case ICM_STATUS_SLOT_FREE:
+
+ DebugPrint((1, "Ultra24fInterrupt: Mailbox empty\n"));
+ return TRUE;
+
+ default:
+
+ DebugPrint((1,
+ "Ultra24fInterrupt: Unexpected mailbox status %x\n",
+ mscpStatus));
+
+ //
+ // Log the error.
+ //
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 1 << 16 | mscpStatus
+ );
+
+ break;
+
+ } // end switch(mscpStatus)
+
+ //
+ // Clear incoming mailbox status.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->InComingMailStatus,
+ ICM_STATUS_SLOT_FREE);
+
+ return TRUE;
+
+} // end Ultra24fInterrupt()
+
+
+VOID
+BuildMscp(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build MSCP for Ultra24f from SRB.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PMSCP mscp = Srb->SrbExtension;
+ ULONG length;
+
+ //
+ // Set MSCP command.
+ //
+
+ mscp->OperationCode = MSCP_OPERATION_SCSI_COMMAND;
+
+ //
+ // Check SRB for disabled disconnect.
+ //
+ // NOTE: UltraStor 24f SCSI adapter does not
+ // support disabling synchronous transfer
+ // per request.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
+ mscp->DisableDisconnect = TRUE;
+ }
+
+ //
+ // Set channel, target id and lun.
+ //
+
+ mscp->Channel = Srb->PathId;
+ mscp->TargetId = Srb->TargetId;
+ mscp->Lun = Srb->Lun;
+
+ //
+ // Set CDB length and copy to MSCP.
+ //
+
+ mscp->CdbLength = Srb->CdbLength;
+ ScsiPortMoveMemory(mscp->Cdb, Srb->Cdb, Srb->CdbLength);
+
+ //
+ // Build SGL in MSCP if data transfer.
+ //
+
+ if (Srb->DataTransferLength > 0) {
+
+ //
+ // Build scattergather descriptor list.
+ //
+
+ BuildSgl(DeviceExtension, Srb);
+
+ //
+ // Set transfer direction.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+
+ //
+ // Write request.
+ //
+
+ mscp->TransferDirection = MSCP_TRANSFER_OUT;
+
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+
+ //
+ // Read request.
+ //
+
+ mscp->TransferDirection = MSCP_TRANSFER_IN;
+ }
+
+ } else {
+
+ //
+ // Set up MSCP for no data transfer.
+ //
+
+ mscp->TransferDirection = MSCP_NO_TRANSFER;
+ mscp->DataLength = 0;
+ mscp->ScatterGather = FALSE;
+ mscp->SgDescriptorCount = 0;
+ }
+
+ //
+ // Setup auto sense if necessary.
+ //
+
+ if (Srb->SenseInfoBufferLength != 0 &&
+ !(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)) {
+
+ //
+ // Set the flag to enable auto sense and fill in the address and length
+ // of the sense buffer.
+ //
+
+ mscp->RequestSenseLength = Srb->SenseInfoBufferLength;
+ mscp->RequestSensePointer = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ Srb->SenseInfoBuffer,
+ &length));
+
+ ASSERT(length >= Srb->SenseInfoBufferLength);
+
+ } else {
+
+ //
+ // Ultra24F uses nonzero request sense pointer
+ // as an indication of autorequestsense.
+ //
+
+ mscp->RequestSenseLength = 0;
+ mscp->RequestSensePointer = 0;
+ }
+
+ //
+ // Zero out command link, status and abort fields.
+ //
+
+ mscp->CommandLink = 0;
+ mscp->AdapterStatus = 0;
+ mscp->TargetStatus = 0;
+ mscp->AbortSrb = 0;
+
+ //
+ // Bypass cache.
+ //
+
+ mscp->UseCache = FALSE;
+
+ return;
+
+} // end BuildMscp()
+
+
+VOID
+BuildSgl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list in the MSCP.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PMSCP mscp = Srb->SrbExtension;
+ PSDL sdl = &mscp->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG descriptorCount = 0;
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SGL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SDL));
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ sdl->Descriptor[descriptorCount].Address = physicalAddress;
+ sdl->Descriptor[descriptorCount].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ //
+ // Check for only one descriptor. As an optimization, in these
+ // cases, use nonscattergather requests.
+ //
+
+ if (descriptorCount == 1) {
+
+ //
+ // Set descriptor count to 0.
+ //
+
+ mscp->SgDescriptorCount = 0;
+
+ //
+ // Set data pointer to data buffer.
+ //
+
+ mscp->DataPointer = physicalAddress;
+
+ //
+ // Set data transfer length.
+ //
+
+ mscp->DataLength = Srb->DataTransferLength;
+
+ //
+ // Clear scattergather bit.
+ //
+
+ mscp->ScatterGather = FALSE;
+
+ } else {
+
+ //
+ // Write SDL count to MSCP.
+ //
+
+ mscp->SgDescriptorCount = (UCHAR)descriptorCount;
+
+ //
+ // Write SGL address to ECB.
+ //
+
+ mscp->DataPointer = physicalSdl;
+
+ //
+ // Zero data transfer length as an indication
+ // of scattergater.
+ //
+
+ mscp->DataLength = 0;
+ mscp->DataLength = Srb->DataTransferLength;
+
+ //
+ // Indicate scattergather operation.
+ //
+
+ mscp->ScatterGather = TRUE;
+ }
+
+ return;
+
+} // end BuildSgl()
+
+BOOLEAN
+Ultra24fResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Ultra24f SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ ULONG j;
+
+ //
+ // The Ultra24F only supports a single SCSI channel.
+ //
+
+ UNREFERENCED_PARAMETER(PathId);
+
+ DebugPrint((2,"ResetBus: Reset Ultra24f and SCSI bus\n"));
+
+ //
+ // Reset SCSI bus.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
+ (US_SCSI_BUS_RESET | US_HBA_RESET));
+
+ //
+ // Complete all outstanding requests.
+ //
+
+ ScsiPortCompleteRequest(deviceExtension,
+ (UCHAR)0,
+ (UCHAR)-1,
+ (UCHAR)-1,
+ SRB_STATUS_BUS_RESET);
+
+ //
+ // Wait for local processor to clear reset bit.
+ //
+
+ for (j=0; j<200000; j++) {
+
+ if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) &
+ US_SCSI_BUS_RESET)) {
+
+ break;
+ }
+
+ ScsiPortStallExecution(10);
+
+ } // end for (j=0 ...
+
+ if (j == 200000) {
+
+ //
+ // Busy has not gone low. Assume the card is gone.
+ // Log the error and fail the request.
+ //
+
+ ScsiPortLogError(deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 16);
+
+ return FALSE;
+
+ }
+
+ return TRUE;
+
+} // end Ultra24fResetBus()
+
+
+VOID
+MapErrorToSrbStatus(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Translate Ultra24f error to SRB error.
+
+Arguments:
+
+ Device Extension for logging error
+ SRB
+
+Return Value:
+
+ Updated SRB
+
+--*/
+
+{
+ ULONG logError = 0;
+ UCHAR srbStatus;
+ PMSCP mscp = Srb->SrbExtension;
+
+ switch (mscp->AdapterStatus) {
+
+ case MSCP_NO_ERROR:
+ srbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
+ break;
+
+ case MSCP_SELECTION_TIMEOUT:
+ srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+ break;
+
+ case MSCP_BUS_UNDER_OVERRUN:
+ DebugPrint((1,"MapErrorToSrbStatus: Data over/underrun\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_DATA_OVERRUN;
+ break;
+
+ case MSCP_UNEXPECTED_BUS_FREE:
+ DebugPrint((1,"MapErrorToSrbStatus: Unexpected bus free\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+ break;
+
+ case MSCP_INVALID_PHASE_CHANGE:
+ DebugPrint((1,"MapErrorToSrbStatus: Invalid bus phase\n"));
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+ break;
+
+ case MSCP_INVALID_COMMAND:
+ case MSCP_INVALID_PARAMETER:
+ case MSCP_INVALID_DATA_LIST:
+ case MSCP_INVALID_SG_LIST:
+ case MSCP_ILLEGAL_SCSI_COMMAND:
+ DebugPrint((1,"MapErrorToSrbStatus: Invalid command\n"));
+ srbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
+
+ case MSCP_BUS_RESET_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: Bus reset\n"));
+ srbStatus = SRB_STATUS_BUS_RESET;
+ break;
+
+ case MSCP_ABORT_NOT_FOUND:
+ case MSCP_SCSI_BUS_ABORT_ERROR:
+ DebugPrint((1,"MapErrorToSrbStatus: Abort not found\n"));
+ srbStatus = SRB_STATUS_ABORT_FAILED;
+ break;
+
+ default:
+ logError = SP_PROTOCOL_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+ break;
+
+ } // end switch ...
+
+ //
+ // Log error if indicated.
+ //
+
+ if (logError) {
+
+ ScsiPortLogError(
+ DeviceExtension,
+ Srb,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun,
+ logError,
+ 2 << 16 | mscp->AdapterStatus
+ );
+ }
+
+ //
+ // Set SRB status.
+ //
+
+ Srb->SrbStatus = srbStatus;
+
+ //
+ // Set target SCSI status in SRB.
+ //
+
+ Srb->ScsiStatus = mscp->TargetStatus;
+
+ return;
+
+} // end MapErrorToSrbStatus()
diff --git a/private/ntos/miniport/ultra24f/ultra24f.h b/private/ntos/miniport/ultra24f/ultra24f.h
new file mode 100644
index 000000000..b8c792c64
--- /dev/null
+++ b/private/ntos/miniport/ultra24f/ultra24f.h
@@ -0,0 +1,222 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ultra24f.h
+
+Abstract:
+
+ This file contains the structures and definitions that define
+ the ULTRASTOR 24F EISA SCSI host bus adapter.
+
+Author:
+
+ Mike Glass (MGLASS)
+
+Revision History:
+
+
+--*/
+
+#include "scsi.h"
+
+//
+// SCATTER/GATHER definitions
+//
+
+#define MAXIMUM_EISA_SLOTS 15
+#define EISA_ADDRESS_BASE 0x0C80
+#define MAXIMUM_SG_DESCRIPTORS 17
+#define MAXIMUM_TRANSFER_LENGTH 0xFFFFFFFF
+
+typedef struct _SGD {
+ ULONG Address;
+ ULONG Length;
+} SGD, *PSGD;
+
+typedef struct _SDL {
+ SGD Descriptor[MAXIMUM_SG_DESCRIPTORS];
+} SDL, *PSDL;
+
+//
+// MailBox SCSI Command Packet
+//
+
+#pragma pack(1)
+
+typedef struct _MSCP {
+ UCHAR OperationCode:3; // byte 00
+ UCHAR TransferDirection:2;
+ UCHAR DisableDisconnect:1;
+ UCHAR UseCache:1;
+ UCHAR ScatterGather:1;
+ UCHAR TargetId:3; // byte 01
+ UCHAR Channel:2;
+ UCHAR Lun:3;
+ ULONG DataPointer; // byte 02
+ ULONG DataLength; // byte 06
+ ULONG CommandLink; // byte 0a
+ UCHAR CommandLinkId; // byte 0e
+ UCHAR SgDescriptorCount; // byte 0f
+ UCHAR RequestSenseLength; // byte 10
+ UCHAR CdbLength; // byte 11
+ UCHAR Cdb[12]; // byte 12
+ UCHAR AdapterStatus; // byte 1e
+ UCHAR TargetStatus; // byte 1f
+ ULONG RequestSensePointer; // byte 20
+ PSCSI_REQUEST_BLOCK SrbAddress; // byte 24
+ PSCSI_REQUEST_BLOCK AbortSrb; // byte 28
+ SDL Sdl; // byte 2c
+} MSCP, *PMSCP;
+
+#pragma pack()
+
+//
+// Operation codes
+//
+
+#define MSCP_OPERATION_HA_COMMAND 1
+#define MSCP_OPERATION_SCSI_COMMAND 2
+#define MSCP_OPERATION_DEVICE_RESET 4
+
+//
+// Transfer direction
+//
+
+#define MSCP_TRANSFER_SCSI 0
+#define MSCP_TRANSFER_IN 1
+#define MSCP_TRANSFER_OUT 2
+#define MSCP_NO_TRANSFER 3
+
+//
+// Host Adapter Error Codes
+//
+
+#define MSCP_NO_ERROR 0x00
+#define MSCP_INVALID_COMMAND 0x01
+#define MSCP_INVALID_PARAMETER 0x02
+#define MSCP_INVALID_DATA_LIST 0x03
+#define MSCP_CPU_DIAG_ERROR 0x30
+#define MSCP_BUFFER_RAM_DIAG_ERROR 0x31
+#define MSCP_STATIC_RAM_DIAG_FAIL 0x32
+#define MSCP_BMIC_CHIP_DIAG_ERROR 0x33
+#define MSCP_CACHE_TAG_RAM_FAIL 0x34
+#define MSCP_ROM_CHECKSUM_CHECK 0x35
+#define MSCP_INVALID_CONFIG_DATA 0x36
+#define MSCP_BUFFER_UNDERRUN 0x40
+#define MSCP_BUFFER_OVERRUN 0x41
+#define MSCP_BUFFER_PARITY_ERROR 0x42
+#define MSCP_EISA_PARITY_ERROR 0x43
+#define MSCP_EISA_INTERFACE_ERROR 0x44
+#define MSCP_SCSI_BUS_ABORT_ERROR 0x84
+#define MSCP_SELECTION_TIMEOUT 0x91
+#define MSCP_BUS_UNDER_OVERRUN 0x92
+#define MSCP_UNEXPECTED_BUS_FREE 0x93
+#define MSCP_INVALID_PHASE_CHANGE 0x94
+#define MSCP_ILLEGAL_SCSI_COMMAND 0x96
+#define MSCP_AUTO_SENSE_ERROR 0x9B
+#define MSCP_UNEXPECTED_COMPLETE 0x9F
+#define MSCP_BUS_RESET_ERROR 0xA3
+#define MSCP_ABORT_NOT_FOUND 0xAA
+#define MSCP_INVALID_SG_LIST 0xFF
+
+//
+// EISA Registers definition
+//
+
+#pragma pack(1)
+
+typedef struct _EISA_CONTROLLER {
+ ULONG BoardId; // zC80
+ UCHAR ExpansionBoard; // zC84
+ UCHAR InterruptLevel; // zC85
+ UCHAR AuxControl; // zC86
+ UCHAR HostAdapterId; // zC87
+ UCHAR BmicStatus; // zC88
+ UCHAR SystemInterrupt; // zC89
+ UCHAR SemaphorePort0; // zC8A
+ UCHAR NotDefined1; // zC8B
+ UCHAR LocalDoorBellMask; // zC8C
+ UCHAR LocalDoorBellInterrupt; // zC8D
+ UCHAR SystemDoorBellMask; // zC8E
+ UCHAR SystemDoorBellInterrupt; // zC8F
+ UCHAR CommandStatusInterface; // zC90
+ UCHAR CsipData[5]; // zC91
+ UCHAR OutGoingMailCommand; // zC96
+ ULONG OutGoingMailPointer; // zC97
+ UCHAR InComingMailStatus; // zC9B
+ ULONG InComingMailPointer; // zC9C
+} EISA_CONTROLLER, *PEISA_CONTROLLER;
+
+#pragma pack()
+
+//
+// UltraStor 24F board id
+//
+
+#define ULTRASTOR_24F_EISA_ID 0x40026356
+
+//
+// OutGoing Commands
+//
+
+#define OGM_COMMAND_SLOT_FREE 0x00
+#define OGM_COMMAND_SLOT_ACTIVE 0x01
+#define OGM_COMMAND_SLOT_ABORT 0x02
+
+//
+// InComing Statuses
+//
+
+#define ICM_STATUS_SLOT_FREE 0x00
+#define ICM_STATUS_COMPLETE_SUCCESS 0x01
+#define ICM_STATUS_COMPLETE_ERROR 0x02
+#define ICM_STATUS_ABORT_SUCCESS 0x03
+#define ICM_STATUS_ABORT_FAILED 0x04
+
+//
+// Interrupt levels
+//
+
+#define US_INTERRUPT_LEVEL_15 0x10
+#define US_INTERRUPT_LEVEL_14 0x20
+#define US_INTERRUPT_LEVEL_11 0x40
+#define US_INTERRUPT_LEVEL_10 0x80
+
+//
+// Alternate address selection
+//
+
+#define US_SECONDARY_ADDRESS 0x08
+
+//
+// ISA TSR Port enabled
+//
+
+#define US_ISA_TSR_PORT_ENABLED 0x04
+
+//
+// Local doorbell interrupt
+//
+
+#define US_CSIR_COMMAND_AVAILABLE 0x01
+#define US_MSCP_AVAILABLE 0x02
+#define US_SCSI_BUS_RESET 0x40
+#define US_HBA_RESET 0x80
+
+//
+// System doorbell interrupt
+//
+
+#define US_RESET_MSCP_COMPLETE 0x02
+#define US_MSCP_COMPLETE 0x02
+#define US_ENABLE_SYSTEM_DOORBELL 0x01
+
+//
+// Interrupt masks (system and local)
+//
+
+#define US_ENABLE_DOORBELL_INTERRUPT 0x02
+#define US_ENABLE_CSIR_INTERRUPT 0x01
diff --git a/private/ntos/miniport/ultra24f/ultra24f.rc b/private/ntos/miniport/ultra24f/ultra24f.rc
new file mode 100644
index 000000000..ab8f790c1
--- /dev/null
+++ b/private/ntos/miniport/ultra24f/ultra24f.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "ULTRASTOR EISA SCSI Adapter Driver"
+#define VER_INTERNALNAME_STR "ultra2f.sys"
+#define VER_ORIGINALFILENAME_STR "ultra2f.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/wd33c93/makefile b/private/ntos/miniport/wd33c93/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/miniport/wd33c93/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/wd33c93/maynard.h b/private/ntos/miniport/wd33c93/maynard.h
new file mode 100644
index 000000000..9e6576549
--- /dev/null
+++ b/private/ntos/miniport/wd33c93/maynard.h
@@ -0,0 +1,173 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ maynard.h
+
+Abstract:
+
+ The module defines the structures, and defines for the Maynard 16-bit
+ host bus adapter card.
+
+Author:
+
+ Jeff Havens (jhavens) 20-June-1991
+
+Revision History:
+
+
+--*/
+
+#ifndef _MAYNARD_
+#define _MAYNARD_
+
+//
+// Define the SCSI host adapter card register structure.
+//
+
+typedef struct _CARD_REGISTERS {
+ UCHAR InternalAddress;
+ UCHAR IoChannel;
+ UCHAR CardControl;
+ UCHAR IoChannel2;
+ UCHAR SetWriteLogic;
+ UCHAR SetReadLogic;
+ UCHAR Unused;
+}CARD_REGISTERS, *PCARD_REGISTERS;
+
+//
+// Define the SCSI host adapter card control register structure.
+//
+
+typedef struct _CARD_CONTROL {
+ UCHAR ResetScsiBus : 1;
+ UCHAR EnableDmaWrite : 1;
+ UCHAR SetBufferedIo : 1;
+ UCHAR SetIrql : 3;
+ UCHAR SetDmaRequest : 2;
+}CARD_CONTROL, *PCARD_CONTROL;
+
+//
+// Specify board dependent parameters.
+//
+
+#define CLOCK_CONVERSION_FACTOR 0x0
+#define SYNCHRONOUS_OFFSET 0x0c
+#define SYNCHRONOUS_PERIOD 0x32
+#define SYNCHRONOUS_PERIOD_STEP 0x32
+#define ASYNCHRONOUS_OFFSET 0x00
+#define ASYNCHRONOUS_PERIOD 0X02
+#define SCSI_CLOCK_SPEED 10 // Clock speed of the WD protocol chip in MHz.
+#define SELECT_TIMEOUT_VALUE (SCSI_CLOCK_SPEED * 4) // = (Input clock * 250ms timeout) / 80 rounded up.
+#define CARD_DMA_MODE DMA_NORMAL
+
+//
+// SCSI Protocol Chip Control read and write macros.
+//
+
+#define SCSI_READ(ChipAddr, Register) ( \
+ ScsiPortWritePortUchar(&((ChipAddr)->InternalAddress), \
+ (UCHAR) &((PSCSI_REGISTERS) 0)->Register), \
+ ScsiPortReadPortUchar(&((ChipAddr)->IoChannel)))
+
+#define SCSI_READ_AUX(ChipAddr, Register) (ScsiPortReadPortUchar (&((ChipAddr)->InternalAddress)))
+
+#define SCSI_WRITE(ChipAddr, Register, Value) { \
+ ScsiPortWritePortUchar(&((ChipAddr)->InternalAddress), \
+ (UCHAR) &((PSCSI_REGISTERS) 0)->Register); \
+ ScsiPortWritePortUchar(&((ChipAddr)->IoChannel), (Value)); }
+
+#define SCSI_READ_TRANSFER_COUNT(ChipAddr, Count) { \
+ ScsiPortWritePortUchar(&((ChipAddr)->InternalAddress), \
+ (UCHAR) &((PSCSI_REGISTERS) 0)->TransferCountMsb); \
+ Count = ScsiPortReadPortUchar(&((ChipAddr)->IoChannel)) << 16; \
+ Count |= ScsiPortReadPortUchar(&((ChipAddr)->IoChannel)) << 8 ; \
+ Count |= ScsiPortReadPortUchar(&((ChipAddr)->IoChannel)); }
+
+#define SCSI_WRITE_TRANSFER_COUNT(ChipAddr, Count) { \
+ SCSI_WRITE(ChipAddr, TransferCountMsb, (UCHAR)(Count >> 16)); \
+ ScsiPortWritePortUchar(&((ChipAddr)->IoChannel), (UCHAR)(Count >> 8)); \
+ ScsiPortWritePortUchar(&((ChipAddr)->IoChannel), (UCHAR)Count); }
+
+#define SCSI_RESET_BUS(DeviceExtension) { CARD_CONTROL CardControl; \
+ *((PUCHAR) &CardControl) = 0; CardControl.ResetScsiBus = 1; \
+ CardControl.SetIrql = DeviceExtension->IrqCode; \
+ CardControl.SetDmaRequest = DeviceExtension->DmaCode; \
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->CardControl), *((PUCHAR) & CardControl)); \
+ ScsiPortStallExecution( 25 ); CardControl.ResetScsiBus = 1; \
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->CardControl), *((PUCHAR) & CardControl)); \
+ }
+
+#define CARD_INITIALIZE(DeviceExtension) { CARD_CONTROL CardControl; \
+ *((PUCHAR) &CardControl) = 0; \
+ CardControl.SetIrql = DeviceExtension->IrqCode; \
+ CardControl.SetDmaRequest = DeviceExtension->DmaCode; \
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->CardControl), \
+ *((PUCHAR) & CardControl)); }
+
+#define CARD_DMA_INITIATE(DeviceExtension, ToDevice) {\
+ SCSI_CONTROL ScsiControl;\
+ CARD_CONTROL CardControl;\
+ *((PUCHAR) &CardControl) = 0;\
+ CardControl.EnableDmaWrite = ToDevice ? 0 : 1;\
+ CardControl.SetIrql = DeviceExtension->IrqCode;\
+ CardControl.SetDmaRequest = DeviceExtension->DmaCode;\
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->CardControl), *((PUCHAR)&CardControl));\
+ ScsiPortWritePortUchar(ToDevice ? &((DeviceExtension->Adapter)->SetReadLogic) : &((DeviceExtension->Adapter)->SetWriteLogic), TRUE);\
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->InternalAddress), (UCHAR)(&(((PSCSI_REGISTERS)0)->Control)));\
+ *((PUCHAR)&ScsiControl) = ScsiPortReadPortUchar(&((DeviceExtension->Adapter)->IoChannel));\
+ ScsiControl.DmaModeSelect = DMA_NORMAL;\
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->InternalAddress), (UCHAR)(&(((PSCSI_REGISTERS)0)->Control)));\
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->IoChannel), *((PUCHAR)&ScsiControl));}
+
+#define CARD_DMA_TERMINATE(DeviceExtension) {\
+ SCSI_CONTROL ScsiControl;\
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->InternalAddress), (UCHAR)(&(((PSCSI_REGISTERS)0)->Control)));\
+ *((PUCHAR)&ScsiControl) = ScsiPortReadPortUchar(&((DeviceExtension->Adapter)->IoChannel));\
+ ScsiControl.DmaModeSelect = DMA_POLLED;\
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->InternalAddress), (UCHAR)(&(((PSCSI_REGISTERS)0)->Control)));\
+ ScsiPortWritePortUchar(&((DeviceExtension->Adapter)->IoChannel), *((PUCHAR)&ScsiControl));}
+
+//
+// Define SCSI host adapter card configuration parameters.
+//
+
+#ifdef SCSI_VECTOR
+#undef SCSI_VECTOR
+#endif
+
+#ifdef SCSI_LEVEL
+#undef SCSI_LEVEL
+#endif
+
+#ifdef SCSI_PHYSICAL_BASE
+#undef SCSI_PHYSICAL_BASE
+#endif
+
+//
+// Define for EISA card using interrupt request level of 10.
+//
+
+#define SCSI_LEVEL 10
+#define SCSI_VECTOR 0
+#define SCSI_BUS_INTERFACE Isa
+
+//
+// Define EISA DMA channel request level of 6.
+//
+
+#define CARD_DMA_REQUEST 6
+#define CARD_DMA_WIDTH Width16Bits;
+#define CARD_DMA_SPEED TypeA;
+
+//
+// Define the default physical base address for SCSI protocol card.
+//
+
+#define SCSI_PHYSICAL_BASE 0x360
+#define SCSI_SECOND_PHYSICAL_BASE 0x370
+
+#endif
+
diff --git a/private/ntos/miniport/wd33c93/s3scsi.h b/private/ntos/miniport/wd33c93/s3scsi.h
new file mode 100644
index 000000000..d978b0217
--- /dev/null
+++ b/private/ntos/miniport/wd33c93/s3scsi.h
@@ -0,0 +1,145 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1991 Compaq Computer Corporation
+
+Module Name:
+
+ s3scsi.h
+
+Abstract:
+
+ The module defines the structures, and defines for the 32-bit
+ GIO bus HPC scsi interface.
+
+Author:
+
+ Jeff Havens (jhavens) 20-June-1991
+ Tom Bonola (o-tomb) 25-Aug-1991
+
+Revision History:
+
+
+--*/
+
+#ifndef _S3SCSI_
+#define _S3SCSI_
+
+#include "sgidef.h"
+
+//
+// Define the SCSI host adapter card register structure.
+//
+
+typedef struct _CARD_REGISTERS {
+ UCHAR fill1;
+ UCHAR InternalAddress; // SCSI.ADDR
+ UCHAR fill2[3];
+ UCHAR IoChannel; // SCSI.DATA
+ UCHAR fill3[2];
+}CARD_REGISTERS, *PCARD_REGISTERS;
+
+//
+// Define the SCSI host adapter card control register structure.
+//
+
+typedef struct _CARD_CONTROL {
+ UCHAR ResetScsiBus : 1;
+ UCHAR EnableDmaWrite : 1;
+ UCHAR SetBufferedIo : 1;
+ UCHAR SetIrql : 3;
+ UCHAR SetDmaRequest : 2;
+}CARD_CONTROL, *PCARD_CONTROL;
+
+//
+// Specify board dependent parameters.
+//
+
+#define CLOCK_CONVERSION_FACTOR CLOCK_20MHZ
+#define SYNCHRONOUS_OFFSET 0x0c
+#define SYNCHRONOUS_PERIOD 0x32
+#define SYNCHRONOUS_PERIOD_STEP 0x32
+#define ASYNCHRONOUS_OFFSET 0x00
+#define ASYNCHRONOUS_PERIOD 0X02
+#define SCSI_CLOCK_SPEED 20 // Clock speed of the WD protocol chip in MHz.
+#define SELECT_TIMEOUT_VALUE (SCSI_CLOCK_SPEED * 4) // = (Input clock * 250ms timeout) / 80 rounded up.
+#define CARD_DMA_MODE DMA_BURST
+
+//
+// SCSI Protocol Chip Control read and write macros.
+//
+
+#define SCSI_READ(ChipAddr, Register) ( \
+ ScsiPortWritePortUchar(&((ChipAddr)->InternalAddress), \
+ (UCHAR) &((PSCSI_REGISTERS) 0)->Register), \
+ ScsiPortReadPortUchar(&((ChipAddr)->IoChannel)))
+
+#define SCSI_READ_AUX(ChipAddr, Register) \
+ (ScsiPortReadPortUchar (&((ChipAddr)->InternalAddress)))
+
+#define SCSI_WRITE(ChipAddr, Register, Value) { \
+ ScsiPortWritePortUchar(&((ChipAddr)->InternalAddress), \
+ (UCHAR) &((PSCSI_REGISTERS) 0)->Register); \
+ ScsiPortWritePortUchar(&((ChipAddr)->IoChannel), (Value)); }
+
+#define SCSI_READ_TRANSFER_COUNT(ChipAddr, Count) { \
+ ScsiPortWritePortUchar(&((ChipAddr)->InternalAddress), \
+ (UCHAR) &((PSCSI_REGISTERS) 0)->TransferCountMsb); \
+ Count = ScsiPortReadPortUchar(&((ChipAddr)->IoChannel)) << 16; \
+ Count |= ScsiPortReadPortUchar(&((ChipAddr)->IoChannel)) << 8 ; \
+ Count |= ScsiPortReadPortUchar(&((ChipAddr)->IoChannel)); }
+
+#define SCSI_WRITE_TRANSFER_COUNT(ChipAddr, Count) { \
+ SCSI_WRITE(ChipAddr, TransferCountMsb, Count >> 16); \
+ ScsiPortWritePortUchar(&((ChipAddr)->IoChannel), Count >> 8); \
+ ScsiPortWritePortUchar(&((ChipAddr)->IoChannel), Count); }
+
+#define SCSI_RESET_BUS(ChipAddr) \
+ *(volatile ULONG *)&SCSI0_HPCREG->ScsiCNTL = SGI_CNTL_SCSIRESET; \
+ KeStallExecutionProcessor( 25 ); \
+ *(volatile ULONG *)&SCSI0_HPCREG->ScsiCNTL = 0L; \
+ KeStallExecutionProcessor( 1000 )
+
+#define CARD_INITIALIZE(ChipAddr)
+#define CARD_DMA_INITIATE(ChipAddr, ToDevice)
+#define CARD_DMA_TERMINATE(ChipAddr)
+
+//
+// Define SCSI host adapter card configuration parameters.
+//
+
+#ifdef SCSI_VECTOR
+#undef SCSI_VECTOR
+#endif
+
+#ifdef SCSI_LEVEL
+#undef SCSI_LEVEL
+#endif
+
+#ifdef SCSI_PHYSICAL_BASE
+#undef SCSI_PHYSICAL_BASE
+#endif
+
+//
+// Define for LOCAL0 register
+//
+
+#define SCSI_LEVEL LOCAL0_LEVEL
+#define SCSI_VECTOR SGI_VECTOR_SCSI
+#define SCSI_BUS_INTERFACE Internal
+
+//
+// Define SCSI DMA channel.
+//
+
+#define CARD_DMA_REQUEST SGI_SCSI_DMA_CHANNEL
+#define CARD_DMA_WIDTH Width32Bits;
+#define CARD_DMA_SPEED TypeA;
+
+//
+// Define the default physical base address for SCSI controller.
+//
+
+#define SCSI_PHYSICAL_BASE SGI_SCSI0_WD_BASE
+
+#endif
diff --git a/private/ntos/miniport/wd33c93/sources b/private/ntos/miniport/wd33c93/sources
new file mode 100644
index 000000000..48879bbf5
--- /dev/null
+++ b/private/ntos/miniport/wd33c93/sources
@@ -0,0 +1,37 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=wd33c93
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+#MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=wd33c93.c wd33c93.rc
diff --git a/private/ntos/miniport/wd33c93/vendor.h b/private/ntos/miniport/wd33c93/vendor.h
new file mode 100644
index 000000000..69465aa54
--- /dev/null
+++ b/private/ntos/miniport/wd33c93/vendor.h
@@ -0,0 +1,26 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vendor.h
+
+Abstract:
+
+ The module includes the appropriate vendor header file.
+
+Author:
+
+ Jeff Havens (jhavens) 20-June-1991
+
+Revision History:
+
+
+--*/
+
+#if defined(SGI)
+#include "s3scsi.h"
+#else
+#include "maynard.h"
+#endif
diff --git a/private/ntos/miniport/wd33c93/wd33c93.c b/private/ntos/miniport/wd33c93/wd33c93.c
new file mode 100644
index 000000000..efc9df3f8
--- /dev/null
+++ b/private/ntos/miniport/wd33c93/wd33c93.c
@@ -0,0 +1,5946 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ wd33c93.c
+
+Abstract:
+
+ This module contains the WD33C93-specific functions for the NT SCSI port
+ driver.
+
+Author:
+
+ Jeff Havens (jhavens) 10-June-1991
+
+Environment:
+
+ Kernel Mode only
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "scsi.h"
+#include "wd33c93.h"
+#include "vendor.h"
+
+#if DBG
+int WdDebug;
+#define WdPrint(arg) ScsiDebugPrint arg
+#else
+#define WdPrint(arg)
+#endif
+
+#define ScsiPortGetNextLink(srb) srb->NextSrb
+
+//
+// Define SCSI Protocol Chip configuration parameters.
+//
+
+#define INITIATOR_BUS_ID 0x7
+#define RESET_STALL_TIME 25 // The minimum assertion time for a SCSI bus reset.
+#define RESET_DELAY_TIME 3 // Time in 250ms increments to delay after reset.
+#define INTERRUPT_STALL_TIME 50 // Time to wait for the next interrupt.
+#define INTERRUPT_CLEAR_TIME 10
+#define DATA_BUS_READY_TIME 3000
+
+
+//
+// WD33C93-specific port driver device extension flags.
+//
+
+#define PD_SYNCHRONOUS_RESPONSE_SENT 0X0001
+#define PD_SYNCHRONOUS_TRANSFER_SENT 0X0002
+#define PD_PENDING_START_IO 0X0004
+#define PD_MESSAGE_OUT_VALID 0X0008
+#define PD_DISCONNECT_EXPECTED 0X0010
+#define PD_SEND_MESSAGE_REQUEST 0X0020
+#define PD_POSSIBLE_EXTRA_MESSAGE_OUT 0X0040
+#define PD_DISCONNECT_INTERRUPT_ENABLED 0X0080
+#define PD_DMA_ACTIVE 0X0100
+#define PD_PARITY_ERROR 0X0200
+#define PD_PENDING_DATA_TRANSFER 0X0400
+
+//
+// The following defines specify masks which are used to clear flags when
+// specific events occur, such as reset or disconnect.
+//
+
+#define PD_ADAPTER_RESET_MASK ( PD_SYNCHRONOUS_TRANSFER_SENT | \
+ PD_PENDING_START_IO | \
+ PD_MESSAGE_OUT_VALID | \
+ PD_SEND_MESSAGE_REQUEST | \
+ PD_POSSIBLE_EXTRA_MESSAGE_OUT | \
+ PD_DMA_ACTIVE | \
+ PD_PARITY_ERROR | \
+ PD_PENDING_DATA_TRANSFER | \
+ PD_DISCONNECT_EXPECTED \
+ )
+
+#define PD_ADAPTER_DISCONNECT_MASK ( PD_SYNCHRONOUS_TRANSFER_SENT | \
+ PD_MESSAGE_OUT_VALID | \
+ PD_SEND_MESSAGE_REQUEST | \
+ PD_POSSIBLE_EXTRA_MESSAGE_OUT | \
+ PD_PARITY_ERROR | \
+ PD_PENDING_DATA_TRANSFER | \
+ PD_DISCONNECT_EXPECTED \
+ )
+
+//
+// The largest SCSI bus message expected.
+//
+
+#define MESSAGE_BUFFER_SIZE 7
+
+//
+// Retry count limits.
+//
+
+#define RETRY_SELECTION_LIMIT 1
+#define RETRY_ERROR_LIMIT 2
+#define MAX_INTERRUPT_COUNT 64
+
+//
+// Bus and chip states.
+//
+
+typedef enum _ADAPTER_STATE {
+ BusFree,
+ Select,
+ SelectAndTransfer,
+ CommandOut,
+ DataTransfer,
+ DataTransferComplete,
+ DisconnectExpected,
+ MessageAccepted,
+ MessageIn,
+ MessageOut,
+ StatusIn
+} ADAPTER_STATE, *PADAPTER_STATE;
+
+//
+// WD33C93-specific port driver logical unit flags.
+//
+
+#define PD_SYNCHRONOUS_NEGOTIATION_DONE 0X0001
+#define PD_DO_NOT_NEGOTIATE 0X0002
+#define PD_STATUS_VALID 0X0004
+#define PD_DO_NOT_CHECK_TRANSFER_LENGTH 0X0008
+#define PD_INITIATE_RECOVERY 0X0010
+
+//
+// The following defines specify masks which are used to clear flags when
+// specific events occur, such as reset or command complete.
+//
+
+#define PD_LU_COMPLETE_MASK (PD_STATUS_VALID | \
+ PD_DO_NOT_CHECK_TRANSFER_LENGTH | \
+ PD_INITIATE_RECOVERY \
+ )
+
+#define PD_LU_RESET_MASK (PD_SYNCHRONOUS_NEGOTIATION_DONE |\
+ PD_STATUS_VALID | \
+ PD_DO_NOT_CHECK_TRANSFER_LENGTH | \
+ PD_INITIATE_RECOVERY \
+ )
+//
+// WD33C93-specific port driver logical unit extension.
+//
+
+typedef struct _SPECIFIC_LOGICAL_UNIT_EXTENSION {
+ USHORT LuFlags;
+ UCHAR SynchronousPeriod;
+ UCHAR SynchronousOffset;
+ ULONG SavedDataPointer;
+ ULONG SavedDataLength;
+ ULONG MaximumTransferLength;
+ PSCSI_REQUEST_BLOCK ActiveLuRequest;
+ PSCSI_REQUEST_BLOCK ActiveSendRequest;
+ ULONG RetryCount;
+ UCHAR SavedCommandPhase;
+}SPECIFIC_LOGICAL_UNIT_EXTENSION, *PSPECIFIC_LOGICAL_UNIT_EXTENSION;
+
+//
+// WD33C93-specific port driver device object extension.
+//
+
+typedef struct _SPECIFIC_DEVICE_EXTENSION {
+ ULONG AdapterFlags;
+ ADAPTER_STATE AdapterState; // Current state of the adapter
+ PCARD_REGISTERS Adapter; // Address of the WD33C93 card
+ AUXILIARY_STATUS AdapterStatus; // Saved status register value
+ SCSI_STATUS AdapterInterrupt; // Saved interrupt status register
+ UCHAR CommandPhase; // Saved command phase value
+ UCHAR InitiatorBusId; // This adapter's SCSI bus ID in bit mask form
+ UCHAR DmaCommand;
+ UCHAR DmaPhase;
+ UCHAR MessageCount; // Count of bytes in message buffer
+ UCHAR MessageSent; // Count of bytes sent to target
+ UCHAR RequestCount;
+ UCHAR DmaCode;
+ UCHAR IrqCode;
+ UCHAR MessageBuffer[MESSAGE_BUFFER_SIZE]; // SCSI bus message buffer
+ ULONG ActiveDataPointer; // SCSI bus active data pointer
+ ULONG ActiveDataLength; // The amount of data to be transferred.
+ LONG InterruptCount; // Count of interrupts since connection.
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION ActiveLogicalUnit;
+
+ // Pointer to the active request.
+
+ PSCSI_REQUEST_BLOCK NextSrbRequest;
+ // Pointer to the next SRB to process.
+
+} SPECIFIC_DEVICE_EXTENSION, *PSPECIFIC_DEVICE_EXTENSION;
+
+
+//
+// Functions passed to the OS-specific port driver.
+//
+
+ULONG
+WdFindAdapter(
+ IN PVOID ServiceContext,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+WdInitializeAdapter(
+ IN PVOID ServiceContext
+ );
+
+BOOLEAN
+WdInterruptServiceRoutine(
+ IN PVOID ServiceContext
+ );
+
+BOOLEAN
+WdResetScsiBus(
+ IN PVOID ServiceContext,
+ IN ULONG PathId
+ );
+
+VOID
+WdSetupDma(
+ PVOID ServiceContext
+ );
+
+BOOLEAN
+WdStartIo(
+ IN PVOID ServiceContext,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// WD33C93-specific internal mini-port driver functions.
+//
+
+VOID
+WdAcceptMessage(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN SetAttention,
+ IN BOOLEAN SetSynchronousParameters
+ );
+
+VOID
+WdCleanupAfterReset(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN ExternalReset
+ );
+
+VOID
+WdCompleteSendMessage(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG SrbStatus
+ );
+
+BOOLEAN
+WdDecodeSynchronousRequest(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension,
+ IN BOOLEAN ResponseExpected
+ );
+
+VOID
+WdDumpState(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+WdIssueCommand(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR CommandByte,
+ IN LONG TransferCount,
+ IN UCHAR CommandPhase
+ );
+
+VOID
+WdLogError(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG ErrorCode,
+ IN ULONG UniqueId
+ );
+
+BOOLEAN
+WdMessageDecode(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ );
+
+VOID
+WdProcessRequestCompletion(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+WdProcessReselection(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR TargetId,
+ IN UCHAR LogicalUnitNumber
+ );
+
+VOID
+WdResetScsiBusInternal(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG PathId
+ );
+
+VOID
+WdSelectTarget(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ );
+
+VOID
+WdSendMessage(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ );
+
+VOID
+WdStartExecution(
+ PSCSI_REQUEST_BLOCK Srb,
+ PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ );
+
+BOOLEAN
+WdTransferInformation(
+ PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PUCHAR BufferPointer,
+ ULONG Count,
+ BOOLEAN TransferToChip
+ );
+
+ULONG
+WdParseArgumentString(
+ IN PCHAR String,
+ IN PCHAR KeyWord
+ );
+
+VOID
+WdAcceptMessage(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN SetAttention,
+ IN BOOLEAN SetSynchronousParameters
+ )
+/*++
+
+Routine Description:
+
+ This procedure tells the adapter to accept a pending message on the SCSI
+ bus. Optionally, it will set the synchronous transfer parameters and the
+ attention signal.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension.
+
+ SetAttention - Indicates the attention line on the SCSI bus should be set.
+
+ SetSynchronousParameters - Indicates the synchronous data transfer
+ parameters should be set.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ SCSI_SYNCHRONOUS scsiSynchronous;
+
+ /* Powerfail */
+
+ //
+ // Check to see if the synchonous data transfer parameters need to be set.
+ //
+
+ if (SetSynchronousParameters) {
+
+ //
+ // These must be set before a data transfer is started.
+ //
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+ *((PUCHAR) &scsiSynchronous) = 0;
+ scsiSynchronous.SynchronousOffset = luExtension->SynchronousOffset;
+ scsiSynchronous.SynchronousPeriod = luExtension->SynchronousPeriod;
+
+ SCSI_WRITE(
+ DeviceExtension->Adapter,
+ Synchronous,
+ *((PUCHAR) &scsiSynchronous)
+ );
+ }
+
+ //
+ // Check to see if the attention signal needs to be set.
+ //
+
+ if (SetAttention) {
+
+ //
+ // This requests that the target enter the message-out phase.
+ //
+
+ WdIssueCommand(DeviceExtension, ASSERT_ATN, -1, 0);
+ }
+
+ //
+ // Indicate to the adapter that the message-in phase may now be completed.
+ //
+
+ WdIssueCommand(DeviceExtension, NEGATE_ACK, -1, 0);
+}
+
+
+VOID
+WdCleanupAfterReset(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN BOOLEAN ExternalReset
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up the adapter-specific
+ and logical-unit-specific data structures. Any active requests are
+ completed and the synchronous negotiation flags are cleared.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to device extension for the bus that
+ was reset.
+
+ ExternalReset - When set, indicates that the reset was generated by a
+ SCSI device other than this host adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LONG pathId = 0;
+ LONG targetId;
+ LONG luId;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+
+ //
+ // Check to see if a data transfer was in progress, if so, flush the DMA.
+ //
+
+ if (DeviceExtension->AdapterFlags & PD_DMA_ACTIVE) {
+ CARD_DMA_TERMINATE( DeviceExtension );
+ ScsiPortFlushDma(DeviceExtension);
+ }
+
+ //
+ // if the current state is Select then SCSI port driver needs
+ // to be notified that new requests can be sent.
+ //
+
+ if (DeviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ //
+ // Ask for another request and clear the pending one. The pending
+ // request will be processed when the rest of the active requests
+ // are completed.
+
+ DeviceExtension->NextSrbRequest = NULL;
+ DeviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
+
+ ScsiPortNotification( NextRequest, DeviceExtension, NULL );
+
+ }
+
+ //
+ // If there was an active request, then complete it with
+ // SRB_STATUS_PHASE_SEQUENCE_FAILURE so the class driver will know not
+ // to retry it too many times.
+ //
+
+ if (DeviceExtension->ActiveLogicalUnit != NULL
+ && DeviceExtension->ActiveLogicalUnit->ActiveLuRequest != NULL) {
+
+ //
+ // Set the SrbStatus in the SRB, complete the request and
+ // clear the active pointers
+ //
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+
+ luExtension->ActiveLuRequest->SrbStatus =
+ SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ luExtension->ActiveLuRequest
+ );
+
+ //
+ // Check to see if there was a synchronous negotiation in progress. If
+ // there was then do not try to negotiate with this target again.
+ //
+
+ if (DeviceExtension->AdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT |
+ PD_SYNCHRONOUS_TRANSFER_SENT | PD_POSSIBLE_EXTRA_MESSAGE_OUT)) {
+
+ //
+ // This target cannot negotiate properly. Set a flag to prevent
+ // further attempts and set the synchronous parameters to use
+ // asynchronous data transfer.
+ //
+
+ /* TODO: Consider propagating this flag to all the Lus on this target. */
+ luExtension->LuFlags |= PD_DO_NOT_NEGOTIATE;
+ luExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ luExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+
+ }
+
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->RetryCount = 0;
+ DeviceExtension->ActiveLogicalUnit = NULL;
+
+ }
+
+ //
+ // Clear the appropriate state flags as well as the next request.
+ // The request will actually be cleared when the logical units are processed.
+ // Note that it is not necessary to fail the request waiting to be started
+ // since it will be processed properly by the target controller, but it
+ // is cleared anyway.
+ //
+
+ for (targetId = 0; targetId < SCSI_MAXIMUM_TARGETS; targetId++) {
+
+ //
+ // Loop through each of the possible logical units for this target.
+ //
+
+ for (luId = 0; luId < SCSI_MAXIMUM_LOGICAL_UNITS; luId++) {
+
+ luExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ (UCHAR)pathId,
+ (UCHAR)targetId,
+ (UCHAR)luId
+ );
+
+ if (luExtension == NULL) {
+ continue;
+ }
+
+ if (luExtension->ActiveLuRequest != NULL) {
+
+ //
+ // Set the SrbStatus in the SRB, complete the request and
+ // clear the active pointers
+ //
+
+ luExtension->ActiveLuRequest->SrbStatus =
+ SRB_STATUS_BUS_RESET;
+
+ //
+ // Complete the request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ luExtension->ActiveLuRequest
+ );
+
+ luExtension->ActiveLuRequest = NULL;
+
+ }
+
+ if (luExtension->ActiveSendRequest != NULL) {
+
+ //
+ // Set the SrbStatus in the SRB, complete the request and
+ // clear the active pointers
+ //
+
+ luExtension->ActiveSendRequest->SrbStatus =
+ SRB_STATUS_BUS_RESET;
+
+ //
+ // Complete the request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ luExtension->ActiveSendRequest
+ );
+
+ luExtension->ActiveSendRequest = NULL;
+
+ }
+
+ //
+ // Clear the necessary logical unit flags.
+ //
+
+ luExtension->LuFlags &= ~PD_LU_RESET_MASK;
+ luExtension->RetryCount = 0;
+ luExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ luExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+
+ } /* for luId */
+ } /* for targetId */
+
+ //
+ // Set the bus state to free and clear the adapter flags.
+ //
+
+ DeviceExtension->AdapterState = BusFree;
+ DeviceExtension->AdapterFlags &= ~PD_ADAPTER_RESET_MASK;
+ DeviceExtension->ActiveLogicalUnit = NULL;
+
+}
+
+VOID
+WdCompleteSendMessage(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG SrbStatus
+ )
+/*++
+
+Routine Description:
+
+ This function does the cleanup necessary to complete a send-message request.
+ This includes completing any affected execute-I/O requests and cleaning
+ up the device extension state.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension of the SCSI bus
+ adapter. The active logical unit is stored in ActiveLogicalUnit.
+
+ SrbStatus - Indicates the status that the request should be completed with
+ if the request did not complete normally, then any active execute
+ requests are not considered to have been affected.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ LONG targetId;
+ LONG luId;
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+ srb = luExtension->ActiveSendRequest;
+
+ //
+ // Clean up any EXECUTE requests which may have been affected by this
+ // message.
+ //
+
+ if (SrbStatus == SRB_STATUS_SUCCESS) {
+ switch (srb->Function) {
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ //
+ // Make sure there is still a request to complete. If so complete
+ // it with an SRB_STATUS_ABORTED status.
+ //
+
+ if (luExtension->ActiveLuRequest == NULL) {
+
+ //
+ // If there is no request, then fail the abort.
+ //
+
+ SrbStatus = SRB_STATUS_ABORT_FAILED;
+ break;
+ }
+
+ luExtension->ActiveLuRequest->SrbStatus =
+ SRB_STATUS_ABORTED;
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ luExtension->ActiveLuRequest
+ );
+
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->RetryCount = 0;
+ luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
+
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ //
+ // Cycle through each of the possible logical units looking
+ // for requests which have been cleared by the target reset.
+ //
+
+ targetId = srb->TargetId;
+
+ for (luId = 0; luId < SCSI_MAXIMUM_LOGICAL_UNITS; luId) {
+
+ luExtension = ScsiPortGetLogicalUnit( DeviceExtension,
+ srb->PathId,
+ (UCHAR)targetId,
+ (UCHAR)luId
+ );
+
+ if (luExtension == NULL) {
+ continue;
+ }
+
+ if (luExtension->ActiveLuRequest != NULL) {
+
+ //
+ // Set the SrbStatus in the SRB, complete the
+ // request and clear the active pointers
+ //
+
+ luExtension->ActiveLuRequest->SrbStatus =
+ SRB_STATUS_BUS_RESET;
+
+ //
+ // Complete the request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ luExtension->ActiveLuRequest
+ );
+
+ luExtension->RetryCount = 0;
+ luExtension->ActiveLuRequest = NULL;
+
+ //
+ // Clear the necessary logical unit flags.
+ //
+
+ luExtension->LuFlags &= ~PD_LU_RESET_MASK;
+ }
+ } /* for luId */
+
+ /* TODO: Handle CLEAR QUEUE and ABORT WITH TAG */
+ }
+
+ } else {
+
+ //
+ // If an abort request fails then complete target of the abort;
+ // otherwise the target of the ABORT may never be compileted.
+ //
+
+ if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Make sure there is still a request to complete. If so
+ // it with an SRB_STATUS_ABORTED status.
+ //
+
+ if (luExtension->ActiveLuRequest != NULL) {
+
+ luExtension->ActiveLuRequest->SrbStatus =
+ SRB_STATUS_ABORTED;
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ luExtension->ActiveLuRequest
+ );
+
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->RetryCount = 0;
+ luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
+
+ }
+ }
+ }
+
+ //
+ // Complete the actual send-message request.
+ //
+
+ srb->SrbStatus = (UCHAR)SrbStatus;
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ srb
+ );
+
+ //
+ // Clear the active send request and PD_SEND_MESSAGE_REQUEST flag.
+ //
+
+ luExtension->ActiveSendRequest = NULL;
+ luExtension->RetryCount = 0;
+ DeviceExtension->AdapterFlags &= ~PD_SEND_MESSAGE_REQUEST;
+}
+
+BOOLEAN
+WdIssueCommand(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR CommandByte,
+ IN LONG TransferCount,
+ IN UCHAR CommandPhase
+ )
+
+/*++
+
+Routine Description:
+
+ This function waits for the command buffer to become available and then
+ issues the requested command. The transfer count registers
+ and CommandPhase are optionally set.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+ CommandByte - Supplies the command byte to be written to the SCSI
+ protocol chip.
+
+ TransferCount - Supplies the value to load in transfer count register.
+ If -1 is supplied, then the transfer counter is not loaded.
+
+ CommandPhase - Supplies the value to load into the Command Phase register.
+
+Return Value:
+
+ TRUE - If the command was written.
+
+ FALSE - If the command could not be written.
+
+--*/
+
+{
+ ULONG i;
+ AUXILIARY_STATUS auxiliaryStatus;
+
+ //
+ // First make sure the SCSI adapter chip is ready for a command.
+ //
+
+ *((PUCHAR) &auxiliaryStatus) = SCSI_READ_AUX(
+ DeviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ for (i = 0;
+ i < INTERRUPT_STALL_TIME && auxiliaryStatus.CommandInProgress;
+ i++) {
+
+ ScsiPortStallExecution(1);
+
+ *((PUCHAR) &auxiliaryStatus) = SCSI_READ_AUX(
+ DeviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+ }
+
+ if (auxiliaryStatus.CommandInProgress) {
+
+ //
+ // The chip is messed up but there is nothing that can be done so
+ // just return false.
+ //
+
+ WdPrint((0, "WdIssueCommand: A command in progress timeout occured! Aux Status 0x%.2X\n", auxiliaryStatus));
+ WdDumpState(DeviceExtension);
+ return(FALSE);
+ }
+
+ //
+ // Set the transfer count if necessary.
+ //
+
+ if (TransferCount != -1) {
+
+ //
+ // Set up the SCSI protocol chip for the data transfer with the
+ // transfer length, regardless of the length.
+ //
+
+ SCSI_WRITE_TRANSFER_COUNT(DeviceExtension->Adapter, TransferCount);
+
+ }
+
+ if (CommandByte == SELECT_ATN_AND_TRANSFER ||
+ CommandByte == SELECT_AND_TRANSFER) {
+
+ //
+ // These commands use the command phase register, so set it to the
+ // requested value.
+ //
+
+ SCSI_WRITE(DeviceExtension->Adapter, CommandPhase, CommandPhase);
+ }
+
+ SCSI_WRITE(DeviceExtension->Adapter, Command, CommandByte);
+
+ return(TRUE);
+}
+
+
+BOOLEAN
+WdMessageDecode(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ This function decodes the SCSI bus message-in the device extension message
+ buffer. After the message is decoded it decides what action to take in
+ response to the message. If an outgoing message needs to be sent, then
+ it is placed in the message buffer and true is returned. If the message
+ is acceptable, then the device state is set either to DisconnectExpected or
+ MessageAccepted and the MessageCount is reset to 0.
+
+ Some messages are made up of serveral bytes. This funtion will simply
+ return false when an incomplete message is detected, allowing the target
+ to send the rest of the message. The message count is left unchanged.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+Return Value:
+
+ TRUE - Returns true if there is a reponse message to be sent.
+
+ FALSE - If there is no response message.
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK srb;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ LONG offset;
+ LONG i;
+ ULONG savedAdapterFlags;
+ PSCSI_EXTENDED_MESSAGE extendedMessage;
+
+ //
+ // Note: the ActivelogicalUnit field could be invalid if the
+ // PD_DISCONNECT_EXPECTED flag is set, so luExtension cannot be used until
+ // this flag has been checked.
+ //
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+ savedAdapterFlags = DeviceExtension->AdapterFlags;
+
+ //
+ // A number of special cases must be handled if a special message has
+ // just been sent. These special messages are synchronous negotiations
+ // or a messages which imply a disconnect. The special cases are:
+ //
+ // If a disconnect is expected because of a send-message request,
+ // then the only valid message-in is a MESSAGE REJECT; other messages
+ // are a protocol error and are rejected.
+ //
+ // If a synchronous negotiation response was just sent and the message
+ // in was not a MESSAGE REJECT, then the negotiation has been accepted.
+ //
+ // If a synchronous negotiation request was just sent, then valid responses
+ // are a MESSAGE REJECT or an extended synchronous message back.
+ //
+
+ if (DeviceExtension->AdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT |
+ PD_DISCONNECT_EXPECTED | PD_SYNCHRONOUS_TRANSFER_SENT)) {
+
+ if (DeviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED &&
+ DeviceExtension->MessageBuffer[0] != SCSIMESS_MESSAGE_REJECT) {
+
+ //
+ // The target is not responding correctly to the message. Send a
+ // message reject of this message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ } else {
+ srb = luExtension->ActiveLuRequest;
+ }
+
+ if (DeviceExtension->AdapterFlags & PD_SYNCHRONOUS_RESPONSE_SENT &&
+ DeviceExtension->MessageBuffer[0] != SCSIMESS_MESSAGE_REJECT) {
+
+ //
+ // The target did not reject our response so the synchronous
+ // transfer negotiation is done. Clear the adapter flags and
+ // set the logical unit flags indicating this. Continue processing
+ // the message which is unrelated to negotiation.
+ //
+
+ DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_RESPONSE_SENT;
+ luExtension->LuFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ }
+
+ //
+ // Save the adapter flags for later use.
+ //
+
+ savedAdapterFlags = DeviceExtension->AdapterFlags;
+
+ if (DeviceExtension->AdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT ) {
+
+ //
+ // The target is sending a message after a synchronous transfer
+ // request was sent. Valid responses are a MESSAGE REJECT or an
+ // extended synchronous message; any other message negates the
+ // fact that a negotiation was started. However, since extended
+ // messages are multi-byte, it is difficult to determine what the
+ // incoming message is. So at this point, the fact that a
+ // sychronous transfer was sent will be saved and cleared from the
+ // AdapterFlags. If the message looks like a synchronous transfer
+ // request, then restore this fact back into the AdapterFlags. If
+ // the complete message is not the one expected, then opening
+ // negotiation will be forgotten. This is an error by the target,
+ // but minor so nothing will be done about it. Finally, to prevent
+ // this cycle from reoccurring on the next request indicate that
+ // the negotiation is done.
+ //
+
+ DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
+ luExtension->LuFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ }
+
+ } else {
+ srb = luExtension->ActiveLuRequest;
+ }
+
+ switch (DeviceExtension->MessageBuffer[0]) {
+ case SCSIMESS_COMMAND_COMPLETE:
+
+ //
+ // For better or worse the command is complete. Process request which
+ // sets the SrbStatus and cleans up the device and logical unit states.
+ //
+
+ WdProcessRequestCompletion(DeviceExtension);
+
+ //
+ // Complete the request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ srb
+ );
+
+ //
+ // Everything is ok with the message so do not send one and set the
+ // state to DisconnectExpected.
+ //
+
+ DeviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
+ DeviceExtension->AdapterState = DisconnectExpected;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_DISCONNECT:
+
+ //
+ // The target wants to disconnect. Set the state to DisconnectExpected,
+ // and do not request a message-out.
+ //
+
+ DeviceExtension->AdapterState = DisconnectExpected;
+ DeviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_EXTENDED_MESSAGE:
+
+ //
+ // The format of an extended message is:
+ // Extended Message Code
+ // Length of Message
+ // Extended Message Type
+ // .
+ // .
+ //
+ // Until the entire message has been read in, just keep getting bytes
+ // from the target, making sure that the message buffer is not
+ // overrun.
+ //
+
+ extendedMessage = (PSCSI_EXTENDED_MESSAGE)
+ DeviceExtension->MessageBuffer;
+
+ if (DeviceExtension->MessageCount < 2 ||
+ (DeviceExtension->MessageCount < (UCHAR) MESSAGE_BUFFER_SIZE &&
+ DeviceExtension->MessageCount < (UCHAR) (extendedMessage->MessageLength + 2))
+ ) {
+
+ //
+ // Update the state and return; also restore the AdapterFlags.
+ //
+
+ DeviceExtension->AdapterFlags = savedAdapterFlags;
+ DeviceExtension->AdapterState = MessageAccepted;
+ return(FALSE);
+
+ }
+
+ //
+ // Make sure the length includes an extended op-code.
+ //
+
+ if (DeviceExtension->MessageCount < 3) {
+
+ //
+ // This is an illegal extended message. Send a MESSAGE_REJECT.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ }
+
+ //
+ // Determine the extended message type.
+ //
+
+ switch (extendedMessage->MessageType) {
+ case SCSIMESS_MODIFY_DATA_POINTER:
+
+ //
+ // Verify the message length.
+ //
+
+ if (extendedMessage->MessageLength != SCSIMESS_MODIFY_DATA_LENGTH) {
+
+ //
+ // Reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ }
+
+ //
+ // Calculate the modification to be added to the data pointer.
+ //
+
+ offset = 0;
+ for (i = 0; i < 4; i++) {
+ offset << 8;
+ offset += extendedMessage->ExtendedArguments.Modify.Modifier[i];
+ }
+
+ //
+ // Verify that the new data pointer is still within the range
+ // of the buffer.
+ //
+
+ if (DeviceExtension->ActiveDataLength - offset >
+ srb->DataTransferLength ||
+ ((LONG) DeviceExtension->ActiveDataLength - offset) < 0 ) {
+
+ //
+ // The new pointer is not valid, so reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+
+ return(TRUE);
+ }
+
+ //
+ // Everything has checked out, so update the pointer.
+ //
+
+ DeviceExtension->ActiveDataPointer += offset;
+ DeviceExtension->ActiveDataLength -= offset;
+
+ //
+ // Everything is ok, so accept the message as is.
+ //
+
+ DeviceExtension->MessageCount = 0;
+ DeviceExtension->AdapterState = MessageAccepted;
+ return(FALSE);
+
+ case SCSIMESS_SYNCHRONOUS_DATA_REQ:
+
+ //
+ // A SYNCHRONOUS DATA TRANSFER REQUEST message was received.
+ // Make sure the length is correct.
+ //
+
+ if ( extendedMessage->MessageLength !=
+ SCSIMESS_SYNCH_DATA_LENGTH) {
+
+ //
+ // The length is invalid reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ //
+ // If synchrouns negotiation has been disabled for this request,
+ // then reject any synchronous messages; however, when synchronous
+ // transfers are allowed then a new attempt can be made.
+ //
+
+ if (srb != NULL &&
+ !(savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT) &&
+ srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) {
+
+ //
+ // Reject the synchronous transfer message since synchonrous
+ // transfers are not desired at this time.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+
+ }
+
+ //
+ // Call WdDecodeSynchronousMessage to decode the message and
+ // formulate a response if necessary.
+ // WdDecodeSynchronousRequest will return FALSE if the
+ // message is not accepable and should be rejected.
+ //
+
+ if (!WdDecodeSynchronousRequest(
+ DeviceExtension,
+ luExtension,
+ (BOOLEAN) (!(savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT))
+ )) {
+
+ //
+ // Indicate that a negotiation has been done in the logical
+ // unit and clear the negotiation flags.
+ //
+
+ luExtension->LuFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ DeviceExtension->AdapterFlags &=
+ ~(PD_SYNCHRONOUS_RESPONSE_SENT|
+ PD_SYNCHRONOUS_TRANSFER_SENT);
+
+ //
+ // The message was not acceptable so send a MESSAGE_REJECT.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ //
+ // If a reponse was expected, then set the state for a message-out.
+ // Otherwise, WdDecodeSynchronousRequest has put a reponse
+ // in the message buffer to be returned to the target.
+ //
+
+ if (savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT){
+
+ //
+ // We initiated the negotiation, so no response is necessary.
+ //
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
+ luExtension->LuFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+ }
+
+ //
+ // Set up the state to send the reponse. The message count is
+ // still correct.
+ //
+
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->AdapterState = MessageOut;
+ DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
+ DeviceExtension->AdapterFlags |= PD_SYNCHRONOUS_RESPONSE_SENT;
+ return(TRUE);
+
+ case SCSIMESS_WIDE_DATA_REQUEST:
+
+ //
+ // A WIDE DATA TRANSFER REQUEST message was received.
+ // Make sure the length is correct.
+ //
+
+ if ( extendedMessage->MessageLength !=
+ SCSIMESS_WIDE_DATA_LENGTH) {
+
+ //
+ // The length is invalid reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ //
+ // Since this SCSI protocol chip only supports 8 bits, return
+ // a width of 0 which indicates an 8-bit-wide transfers. The
+ // MessageCount is still correct for the message.
+ //
+
+ extendedMessage->ExtendedArguments.Wide.Width = 0;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+
+ default:
+
+ //
+ // This is an unknown or illegal message, so send message REJECT.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ case SCSIMESS_INITIATE_RECOVERY:
+
+ //
+ // Save the fact that a INITIATE RECOVERY message was received.
+ //
+
+ luExtension->LuFlags |= PD_INITIATE_RECOVERY;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_LINK_CMD_COMP:
+
+ //
+ // A link command completed. Process the completion. Since the link
+ // FLAG was not set, do not call ScsiPortNotification. Get the next
+ // segment of the request and accept the message.
+ //
+
+ //
+ // Make sure that this is a linked command.
+ // Linked commands are not supported.
+ //
+
+ if (TRUE) {
+
+ //
+ // Something is messed up. Reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ WdProcessRequestCompletion(DeviceExtension);
+
+ luExtension->ActiveLuRequest = srb->NextSrb;
+
+ //
+ // Everything is ok with the message, so do not send one and set the
+ // state to MessageAccepted.
+ //
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_LINK_CMD_COMP_W_FLAG:
+
+ //
+ // A link command completed. Process the completion and get the next
+ // segment of the request. Since the link FLAG was set, call
+ // ScsiPortNotification to notify the class driver.
+ //
+
+ //
+ // Make sure that this is a linked command.
+ // Linked commands are not supported.
+ //
+
+ if (TRUE) {
+
+ //
+ // Something is messed up. Reject the message.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+
+ WdProcessRequestCompletion(DeviceExtension);
+
+ luExtension->ActiveLuRequest = srb->NextSrb;
+
+ //
+ // Complete the request.
+ //
+
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ srb
+ );
+
+ //
+ // Everything is ok with the message, so do not send one and set the
+ // state to MessageAccepted.
+ //
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_MESSAGE_REJECT:
+
+ //
+ // The last message we sent was rejected. If this was a send
+ // message request, then set the proper status and complete the
+ // request. Set the state to message accepted.
+ //
+
+ if (DeviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
+
+ //
+ // Complete the request with message rejected status.
+ //
+
+ WdCompleteSendMessage(
+ DeviceExtension,
+ SRB_STATUS_MESSAGE_REJECTED
+ );
+ }
+
+ //
+ // Check to see if a synchronous negotiation is in progress.
+ //
+
+ if (savedAdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT|
+ PD_SYNCHRONOUS_TRANSFER_SENT)) {
+
+ //
+ // The negotiation failed so use asynchronous data transfers.
+ // Indicate that the negotiation has been attempted and set
+ // the transfer for asynchronous. Clear the negotiation flags.
+ //
+
+ luExtension->LuFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ luExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ luExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ DeviceExtension->AdapterFlags &= ~(PD_SYNCHRONOUS_RESPONSE_SENT|
+ PD_SYNCHRONOUS_TRANSFER_SENT);
+
+ //
+ // Even though the negotiation appeared to go ok, there is no reason
+ // to try again, and some targets get messed up later, so do not try
+ // synchronous negotiation again.
+ //
+
+ /* TODO: Reconsider doing this. */
+
+ // luExtension->LuFlags |= PD_DO_NOT_NEGOTIATE;
+
+ }
+
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_RESTORE_POINTERS:
+
+ //
+ // Restore data pointer message. Just copy the saved data pointer
+ // and the length to the active data pointers.
+ //
+
+ DeviceExtension->ActiveDataPointer = luExtension->SavedDataPointer;
+ DeviceExtension->ActiveDataLength = luExtension->SavedDataLength;
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ case SCSIMESS_SAVE_DATA_POINTER:
+
+ //
+ // SAVE DATA POINTER message request that the active data pointer and
+ // length be copied to the saved location.
+ //
+
+ luExtension->SavedDataPointer = DeviceExtension->ActiveDataPointer;
+ luExtension->SavedDataLength = DeviceExtension->ActiveDataLength;
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+ return(FALSE);
+
+ default:
+
+ //
+ // An unrecognized or unsupported message: send message reject.
+ //
+
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
+ DeviceExtension->AdapterState = MessageOut;
+ return(TRUE);
+ }
+}
+
+BOOLEAN
+WdDecodeSynchronousRequest(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ OUT PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension,
+ IN BOOLEAN ResponseExpected
+ )
+/*++
+
+Routine Description:
+
+ This function decodes the synchronous data transfer request message from
+ the target. It will update the synchronous message in the buffer and the
+ synchronous transfer parameters in the logical unit extension. These
+ parameters are specific for the WD 53C9X protocol chip. The updated
+ message in the device extension message buffer might be returned to the
+ target.
+
+ This function should be called before the final byte of the message is
+ accepted from the SCSI bus.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the adapter-specific device
+ extension.
+
+ LuExtension - Supplies a pointer to the logical unit's device extension.
+ The synchronous transfer fields are updated in this structure to
+ reflect the new parameter in the message.
+
+ ResponseExpected - When set, indicates that the target initiated the
+ negotiation and that it expects a response.
+
+Return Value:
+
+ TRUE - Returned if the request is acceptable.
+
+ FALSE - Returned if the request should be rejected and asynchronous
+ transfer should be used.
+
+--*/
+
+{
+ PSCSI_EXTENDED_MESSAGE extendedMessage;
+ SCSI_SYNCHRONOUS scsiSynchronous;
+ LONG period;
+ LONG i;
+
+
+ extendedMessage = (PSCSI_EXTENDED_MESSAGE) DeviceExtension->MessageBuffer;
+
+ //
+ // Determine the transfer offset. It is the minimum of the SCSI protocol
+ // chip's maximum offset and the requested offset.
+ //
+
+ if (extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset >
+ SYNCHRONOUS_OFFSET) {
+
+ if (!ResponseExpected) {
+
+ //
+ // The negotiation failed for some reason, fall back to
+ // asynchronous data transfer.
+ //
+
+ LuExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ LuExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ return(FALSE);
+ }
+
+ extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset = SYNCHRONOUS_OFFSET;
+ LuExtension->SynchronousOffset = SYNCHRONOUS_OFFSET;
+
+ } else {
+
+ LuExtension->SynchronousOffset =
+ extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset;
+
+ }
+
+ //
+ // If the offset requests asynchronous transfers then set the default
+ // period and return.
+ //
+
+ if (extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset ==
+ ASYNCHRONOUS_OFFSET) {
+ LuExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ return(TRUE);
+ }
+
+ //
+ // Check to see if the period is less than the SCSI protocol chip can
+ // use. If it is then update the message with our minimum and return.
+ //
+
+ if (extendedMessage->ExtendedArguments.Synchronous.TransferPeriod < SYNCHRONOUS_PERIOD) {
+
+ if (!ResponseExpected) {
+
+ //
+ // The negotiation failed for some reason, fall back to
+ // asynchronous data transfer.
+ //
+
+ LuExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ LuExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ return(FALSE);
+ }
+
+ extendedMessage->ExtendedArguments.Synchronous.TransferPeriod = SYNCHRONOUS_PERIOD;
+ }
+
+ //
+ // The synchronous period uses the following formula to calculate the
+ // transfer period returned in the message:
+ //
+ // (SynchronousPeriod - 2) * 1000 * ClockDivide
+ // ---------------------------------------------
+ // Clock speed in Mhz * 2 * 4
+ //
+ // The 4 is the divisor is because the message byte is in units of 4 ns.
+ // For the WD53c93 the Synchronous period will be calculated by:
+ //
+ // (MessagePeriod - SYNCHRONOUS_PERIOD)
+ // SynchrounousPeriod = ------------------------------------
+ // SYNCHRONOUS_PERIOD_STEP
+ //
+ // Note that this must be rounded up. Since the range of SynchronousPeriod
+ // is only 3-6 a simple loop will handle this calculation.
+ //
+
+ period = extendedMessage->ExtendedArguments.Synchronous.TransferPeriod -
+ SYNCHRONOUS_PERIOD;
+
+ for (i = 3; i < 7; i++) {
+ if (period <= 0) {
+ break;
+ }
+ period -= SYNCHRONOUS_PERIOD_STEP;
+ }
+
+ if (i >= 7) {
+
+ //
+ // The requested transfer period is too long for the SCSI protocol
+ // chip. Fall back to synchronous and reject the request.
+ //
+
+ LuExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ LuExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+ return(FALSE);
+ } else {
+ LuExtension->SynchronousPeriod = (UCHAR)i;
+ }
+
+ //
+ // Set the synchronous data transfer parameter registers
+ // to the new values. These must be set before a data transfer
+ // is started. If a response message is received then the parameters
+ // must be reset.
+ //
+
+ /* Powerfail */
+
+ *((PCHAR) &scsiSynchronous) = 0;
+ scsiSynchronous.SynchronousPeriod = LuExtension->SynchronousPeriod;
+ scsiSynchronous.SynchronousOffset = LuExtension->SynchronousOffset;
+
+ SCSI_WRITE(
+ DeviceExtension->Adapter,
+ Synchronous,
+ *((PUCHAR) &scsiSynchronous)
+ );
+
+ return(TRUE);
+
+}
+
+VOID
+WdDumpState(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This function prints the interesting state information about the requested
+ SCSI bus adapter.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to device extension for the SCSI
+ bus adapter that should be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WdPrint((0, "WdDumpState: Specific device extension: 0x%.8X; Active Logical Unit: 0x%.8X;\n",
+ DeviceExtension,
+ DeviceExtension->ActiveLogicalUnit
+ ));
+ WdPrint((0, "WdDumpState: Adapter Status: 0x%.2X; Adapter Interrupt: 0x%.2X; Command Phase: 0x%.2X;\n",
+ *((PUCHAR) &DeviceExtension->AdapterStatus),
+ *((PUCHAR) &DeviceExtension->AdapterInterrupt),
+ DeviceExtension->CommandPhase
+ ));
+ WdPrint((0, "WdDumpState: Adapter flags: 0x%.4X; Adapter state: %d;\n",
+ DeviceExtension->AdapterFlags,
+ DeviceExtension->AdapterState
+ ));
+
+}
+
+
+BOOLEAN
+WdInitializeAdapter(
+ IN PVOID ServiceContext
+ )
+/*++
+
+Routine Description:
+
+ This function initializes the WD SCSI adapter chip. This function must
+ be called before any other operations are performed on the chip. It should
+ also be called after a power failure. This function does not cause any
+ interrupts; however, after it completes interrupts can occur.
+
+Arguments:
+
+ ServiceContext - Pointer to the specific device extension for this SCSI
+ bus.
+
+Return Value:
+
+ TRUE - Returns TRUE indicating that the initialization of the chip is
+ complete.
+
+ FALSE - Returns FALSE if the initialization failed.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ OWN_ID ownId;
+ SCSI_CONTROL control;
+ SCSI_STATUS interruptStatus;
+ AUXILIARY_STATUS auxiliaryStatus;
+ SOURCE_ID sourceId;
+ ULONG i;
+
+ //
+ // Initialize the card.
+ //
+
+ CARD_INITIALIZE(deviceExtension);
+
+ //
+ // If the SCSI protocol chip is interrupting, then clear the interrupt so
+ // that the reset command can be written to the chip.
+ //
+
+ *((PUCHAR) &auxiliaryStatus) = SCSI_READ_AUX(
+ deviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ if (auxiliaryStatus.Interrupt) {
+
+ //
+ // Read the status register to clear the interrupt.
+ //
+
+ *((PUCHAR) &interruptStatus) = SCSI_READ(
+ deviceExtension->Adapter,
+ Status
+ );
+
+ //
+ // Stall the required time to allow the interrupt to clear.
+ //
+
+ ScsiPortStallExecution(INTERRUPT_CLEAR_TIME);
+ }
+
+ //
+ // The OwnId register must be set when the SCSI protocol chip is reset.
+ // Initialize the ownId with the adapter's host ID, advanced features,
+ // and the correct clock frequency select. Note the CdbSize register is
+ // used as the OwnId register when a reset command is issued.
+ //
+
+ *((PUCHAR) &ownId) = 0;
+ ownId.InitiatorId = deviceExtension->InitiatorBusId;
+ ownId.AdvancedFeatures = 1;
+ ownId.FrequencySelect = CLOCK_CONVERSION_FACTOR;
+
+ SCSI_WRITE( deviceExtension->Adapter, CdbSize, *((PUCHAR) &ownId) );
+
+ //
+ // Issue a reset-chip command.
+ //
+
+ WdIssueCommand(deviceExtension, RESET_SCSI_CHIP, -1, 0);
+
+ //
+ // Wait for the reset to complete. A reset complete is indicated by an
+ // interrupt with none of the interrupt bits set. The PhaseState in the
+ // interruptStatus indicates whether the this chip supports advanced mode
+ // or not.
+ //
+
+ i = 0;
+ *((PUCHAR) &auxiliaryStatus) = SCSI_READ_AUX(
+ deviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ while (!auxiliaryStatus.Interrupt && i < INTERRUPT_STALL_TIME) {
+
+ ScsiPortStallExecution(1);
+ i++;
+
+ *((PUCHAR) &auxiliaryStatus) = SCSI_READ_AUX(
+ deviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ }
+
+#if DBG
+ if (WdDebug) {
+ WdPrint((0, "WdInitializeAdapter: Interrupt stall time for reset = %d\n", i));
+ }
+#endif
+
+ if (!auxiliaryStatus.Interrupt) {
+
+ //
+ // The SCSI protocol chip did not reset properly. Notify the OS port
+ // driver of the error.
+ //
+
+ WdPrint((0, "WdInitializeAdapter: SCSI chip reset failed. Aux Status: 0x%.2X.\n",
+ auxiliaryStatus
+ ));
+
+ return(FALSE);
+ }
+
+
+ //
+ // Dismiss the reset interrupt, and
+ // verify that the SCSI protocol chip reset correctly and that the
+ // advanced features were enabled.
+ //
+
+ *((PUCHAR) &interruptStatus) = SCSI_READ(deviceExtension->Adapter, Status);
+
+ if (interruptStatus.PhaseState != RESET_STATUS &&
+ interruptStatus.PhaseState != RESET_WITH_ADVANCED) {
+
+ WdPrint((0, "WdInitializeAdapter: SCSI chip reset failed. Status: 0x%.2X.\n",
+ *((PUCHAR) &interruptStatus)
+ ));
+
+ return(FALSE);
+ }
+
+ //
+ // Stall the required time to allow the interrupt to clear.
+ //
+
+ ScsiPortStallExecution(INTERRUPT_CLEAR_TIME);
+
+ //
+ // Initialize the control register for halt on parity error,
+ // intermediate disconnect interrupt, ending disconnect interrupt,
+ // and polled I/O mode.
+ //
+
+ *((PUCHAR) &control) = 0;
+ control.HaltOnParity = 1;
+ control.IntermediateDisconnectInt = 1;
+ control.EndingDisconnectInt = 1;
+
+ SCSI_WRITE(deviceExtension->Adapter, Control, *((PUCHAR) &control));
+
+ //
+ // Set the SelectTimeOut Register to 250ms. This value does not need to
+ // be reinitialized for each selection.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Timeout, SELECT_TIMEOUT_VALUE);
+
+ //
+ // Initialize the source register, in particular, enable reselection.
+ //
+
+ *((PUCHAR) &sourceId) = 0;
+ sourceId.EnableReselection = 1;
+
+ SCSI_WRITE(deviceExtension->Adapter, SourceId, *((PUCHAR) &sourceId));
+
+ return( TRUE );
+}
+
+BOOLEAN
+WdInterruptServiceRoutine(
+ PVOID ServiceContext
+ )
+/*++
+
+Routine Description:
+
+ The routine is the interrupt service routine for the WD 33C94 SCSI
+ protocol chip. It is the main SCSI protocol engine of the driver and
+ is driven by service requests from targets on the SCSI bus. This routine
+ also detects errors and performs error recovery. Generally, this routine
+ handles one interrupt per invokation.
+
+ The general flow of this routine is as follows:
+
+ Check for an interrupt.
+
+ Determine if there are any pending errors.
+
+ Determine what interrupt occurred.
+
+ Update the adapter state based on what has occurred.
+
+ Determine what the target wants to do next and program the chip
+ appropriately.
+
+ Check for the next interrupt.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension for the
+ interrupting adapter.
+
+Return Value:
+
+ TRUE - Indicates that an interrupt was found.
+
+ FALSE - Indicates the device was not interrupting.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ BOOLEAN setAttention;
+ BOOLEAN waitForInterrupt;
+ SCSI_STATUS interruptStatus;
+ SOURCE_ID sourceId;
+ TARGET_LUN targetLun;
+ ULONG waitCount;
+
+ /* POWERFAIL */
+
+ //
+ // Get the current chip state which includes the auxiliary status
+ // register, the command phase register and the SCSI status register.
+ // These registers are frozen until the interrupt register is read.
+ //
+
+ *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ_AUX(
+ deviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ //
+ // Make sure there is really an interrupt before reading the other
+ // registers, particularly, the interrupt register.
+ //
+
+ if (!deviceExtension->AdapterStatus.Interrupt) {
+ return(FALSE);
+ }
+
+NextInterrupt:
+
+ *((PUCHAR) &deviceExtension->CommandPhase) = SCSI_READ(
+ deviceExtension->Adapter,
+ CommandPhase
+ );
+
+ //
+ // This read will dismiss the interrupt.
+ //
+
+ *((PUCHAR) &interruptStatus) = SCSI_READ(
+ deviceExtension->Adapter,
+ Status
+ );
+
+ deviceExtension->AdapterInterrupt = interruptStatus;
+
+ //
+ // Intialize the logical unit extension pointer.
+ // Note that this may be NULL.
+ //
+
+ luExtension = deviceExtension->ActiveLogicalUnit;
+
+ if (luExtension != NULL) {
+ srb = luExtension->ActiveLuRequest;
+ } else {
+ srb = NULL;
+ }
+
+ //
+ // If data transfer is active,
+ // then update the active pointers.
+ // If a DMA data transfer is complete, then flush the DMA buffer.
+ //
+
+ if (deviceExtension->AdapterState == DataTransfer) {
+ ULONG transferCount;
+
+ //
+ // Get the number of bytes that didn't get transferred, if any.
+ //
+
+ SCSI_READ_TRANSFER_COUNT(deviceExtension->Adapter, transferCount);
+
+ //
+ // transferCount now contains the number of bytes that did not
+ // get transferred. Change it to the number of bytes that did get
+ // transferred.
+ //
+
+ transferCount = deviceExtension->ActiveDataLength - transferCount;
+
+ //
+ // Now figure out if anything remains to be transferred.
+ //
+
+ luExtension->MaximumTransferLength += transferCount;
+ deviceExtension->ActiveDataPointer += transferCount;
+ deviceExtension->ActiveDataLength = srb->DataTransferLength -
+ luExtension->MaximumTransferLength;
+ luExtension->SavedDataPointer = deviceExtension->ActiveDataPointer;
+ luExtension->SavedDataLength = deviceExtension->ActiveDataLength;
+
+ if (deviceExtension->AdapterFlags & PD_DMA_ACTIVE) {
+
+ //
+ // Flush the DMA buffer to ensure all the bytes are transferred.
+ //
+
+ ScsiPortFlushDma(deviceExtension);
+
+ //
+ // Shutdown DMA mode on the card.
+ //
+
+ CARD_DMA_TERMINATE( deviceExtension );
+
+ //
+ // Clear the DMA active flag.
+ //
+
+ deviceExtension->AdapterFlags &= ~(PD_DMA_ACTIVE | PD_PENDING_DATA_TRANSFER);
+
+ }
+ }
+
+ //
+ // Stall after the interrupt has been dismissed.
+ // This must be done before any commands issued.
+ //
+
+ ScsiPortStallExecution(INTERRUPT_CLEAR_TIME);
+
+#if DBG
+ if (WdDebug) {
+ WdPrint((0, "WdInterrupt: Adapter Status: 0x%.2X; Adapter Interrupt: %2x; Command Phase: 0x%.2X;\n",
+ *((PUCHAR) &deviceExtension->AdapterStatus),
+ *((PUCHAR) &interruptStatus),
+ *((PUCHAR) &deviceExtension->CommandPhase)
+ ));
+ }
+#endif
+
+ deviceExtension->InterruptCount++;
+ waitForInterrupt = FALSE;
+
+ //
+ // Check for major errors that should never occur.
+ //
+
+ if (deviceExtension->InterruptCount > MAX_INTERRUPT_COUNT) {
+
+ //
+ // Things are really messed up. Reset the bus, the chip and
+ // bail out.
+ //
+
+ WdPrint((0,
+ "WdInterruptServiceRoutine: Unexpected error. Interrupt Count=%d\n",
+ deviceExtension->InterruptCount
+ ));
+
+ WdDumpState(deviceExtension);
+
+ WdLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 1);
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+ }
+
+ //
+ // Check to see if a subsequent request can be made pending.
+ // Logically this happens when a select occurs that causes an
+ // already "pending" request to become an "active" request. A
+ // select of this type has occured if and only if the adapter
+ // state is either Select or SelectAndTransfer (attempting to
+ // select) and the reason for the SCSI protocol chip interrupt
+ // is something other than one of the following interrupt and
+ // PhaseState values:
+ //
+ // AbortedPaused PAUSED_DURING_RESELECT
+ // AbortedPaused PAUSED_RESELECT_OR_SELECT
+ // ServiceRequired SERVICE_RESELECTED
+ // ServiceRequired SERVICE_RESELECTED_IDENTIFY
+ // Terminated TERMINATE_SELECT_TIMEOUT
+ //
+
+ switch (deviceExtension->AdapterState) {
+ case Select:
+ case SelectAndTransfer:
+ if (!interruptStatus.PhaseStateValid) {
+ if (interruptStatus.AbortedPaused) {
+ if ((interruptStatus.PhaseState == PAUSED_DURING_RESELECT) ||
+ (interruptStatus.PhaseState == PAUSED_RESELECT_OR_SELECT)) {
+ break;
+ }
+ } else if (interruptStatus.ServiceRequired) {
+ if ((interruptStatus.PhaseState == SERVICE_RESELECTED) ||
+ (interruptStatus.PhaseState == SERVICE_RESELECTED_IDENTIFY)) {
+ break;
+ }
+ } else if (interruptStatus.Terminated) {
+ if (interruptStatus.PhaseState == TERMINATE_SELECT_TIMEOUT) {
+ break;
+ }
+ }
+ }
+
+ //
+ // A Select has completed or a SelectAndTransfer has begun.
+ // Set the adapter state appropriately.
+ //
+
+ if (deviceExtension->AdapterState == Select) {
+ deviceExtension->AdapterState = MessageOut;
+ } else {
+ deviceExtension->AdapterState = CommandOut;
+ }
+
+ //
+ // The "pending" srb has now become the active srb.
+ // Clear the deviceExtension information associated with
+ // the no longer pending condition and ask for another srb
+ // (if any) to be made the pending srb.
+ //
+
+ deviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
+ deviceExtension->NextSrbRequest = NULL;
+
+ ScsiPortNotification(
+ NextRequest,
+ deviceExtension,
+ NULL
+ );
+
+ break;
+ }
+
+
+ //
+ // Check for a successful completion interrupt.
+ //
+
+ if (interruptStatus.CommandComplete &&
+ !interruptStatus.PhaseStateValid) {
+
+ //
+ // Determine what completed based on the state in the interrupt status.
+ //
+
+ switch (interruptStatus.PhaseState) {
+ case COMPLETE_SELECT:
+
+ //
+ // This case was handled above.
+ //
+
+ waitForInterrupt = 1;
+ break;
+
+ case COMPLETE_SELECT_AND_TRANS:
+
+ //
+ // A select-and-transfer command completed. This implies that
+ // everything went normally. In particular, all of the data was
+ // transferred, a SCSI bus status byte was received, the
+ // command complete message was accepted and the target has
+ // disconnected. Simulate the state change which would normally
+ // occur if these events were individual interrupts.
+ //
+
+ srb = luExtension->ActiveLuRequest;
+
+ //
+ // Get the status value and indicate it has been received. The
+ // SCSI status value is saved in the TargetLun register.
+ //
+
+ srb->ScsiStatus = SCSI_READ(deviceExtension->Adapter, TargetLun);
+ luExtension->LuFlags |= PD_STATUS_VALID;
+
+ //
+ // Simulate the COMMAND COMPLETE message.
+ //
+
+ deviceExtension->MessageCount = 0;
+ deviceExtension->MessageBuffer[0] = SCSIMESS_COMMAND_COMPLETE;
+ WdMessageDecode(deviceExtension);
+
+ //
+ // Indicate that the bus is free.
+ // Clean up the adapter state to indicate the bus is now free,
+ // stop the PhaseTimer, and start any pending request.
+ //
+
+ deviceExtension->AdapterState = BusFree;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->ActiveLogicalUnit = NULL;
+
+ if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ //
+ // Call WdStartIo to start the pending request.
+ // Note that WdStartIo is idempotent when called with
+ // the same arguments.
+ //
+
+ WdStartIo(
+ deviceExtension,
+ deviceExtension->NextSrbRequest
+ );
+
+ }
+
+ waitForInterrupt = TRUE;
+ break;
+
+ default:
+
+ //
+ // Things are really messed up. Reset the bus, the chip and
+ // bail out.
+ //
+
+ WdLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 3);
+
+ WdPrint((0, "WdInterruptServiceRoutine: Unexpected command complete state.\n"));
+ WdDumpState(deviceExtension);
+
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+
+ }
+ } else if (interruptStatus.CommandComplete &&
+ interruptStatus.PhaseStateValid) {
+
+ //
+ // A transfer information command completed and the target is
+ // requesting another bus phase. Process the fact that the transfer
+ // completed based on the current state. The new request will be
+ // serviced later. Note that message-in transfers do not cause this
+ // type of interrupt, because the last byte of the transfer is not
+ // acknowleged by the SCSI protocol chip.
+ //
+
+ srb = luExtension->ActiveLuRequest;
+
+ //
+ // The following states are processed:
+ //
+ // CommandOut
+ // DataTransfer
+ // DataTransferComplete
+ // MessageOut
+ // StatusIn
+ //
+ //
+
+ switch (deviceExtension->AdapterState) {
+ case CommandOut:
+ case DataTransferComplete:
+ break;
+
+ case DataTransfer:
+
+ //
+ // A data transfer completed or is being suspended.
+ // If no longer in data transfer state,
+ // then change the state to say so.
+ //
+
+ switch (interruptStatus.PhaseState) {
+ case DATA_OUT:
+ case DATA_IN:
+ //
+ // The target device is still in data phase.
+ // This may be because an even length DMA transfer
+ // has just completed and an odd length byte still
+ // remains to be transferred. Check to see if this
+ // is the case: if so, stay in DataTransfer state
+ // to transfer the odd byte; else, we have a genuine
+ // data under run (our data transfer length is less
+ // than the target's expected data transfer length).
+ //
+
+ if (deviceExtension->ActiveDataLength == 1) {
+ break;
+ }
+
+ //
+ // else: fall through to next/default case
+ //
+
+ default:
+ deviceExtension->AdapterState = DataTransferComplete;
+ break;
+ }
+
+ break;
+
+ case MessageOut:
+
+ //
+ // The SCSI protocol chip indicates that the message has been sent;
+ // however, the target may need to reread the message or there
+ // may be more messages to send. This condition is indicated by a
+ // message-out bus phase; otherwise, the message has been accepted
+ // by the target. If message has been accepted then check to see
+ // if any special processing is necessary. Note that the driver
+ // state is set to MessageOut after the PD_DISCONNECT_EXPECTED is
+ // set, or after a selection. So it is only necessary to check for
+ // PD_DISCONNECT_EXPECTED when the driver state is currently in
+ // MessageOut.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED &&
+ interruptStatus.PhaseState != MESSAGE_OUT &&
+ interruptStatus.PhaseState != MESSAGE_IN) {
+
+ //
+ // If a disconnect was expected and a bus service interrupt
+ // was detected, then a SCSI protocol error has been
+ // detected and the SCSI bus should be reset to clear the
+ // condition.
+ //
+
+ WdLogError(deviceExtension, SP_PROTOCOL_ERROR, 4);
+
+ WdPrint((0, "WdInterruptServiceRoutine: Bus request while disconnect expected after message-out.\n"));
+ WdDumpState(deviceExtension);
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+
+ }
+
+ if (deviceExtension->AdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT &&
+ interruptStatus.PhaseState != MESSAGE_OUT &&
+ interruptStatus.PhaseState != MESSAGE_IN) {
+
+ //
+ // The controller ignored the synchronous transfer message.
+ // Treat it as a rejection and clear the necessary state.
+ //
+
+ deviceExtension->ActiveLogicalUnit->LuFlags |=
+ PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ deviceExtension->AdapterFlags &=
+ ~(PD_SYNCHRONOUS_RESPONSE_SENT|
+ PD_SYNCHRONOUS_TRANSFER_SENT);
+ }
+
+ if (deviceExtension->AdapterFlags & PD_SYNCHRONOUS_RESPONSE_SENT &&
+ interruptStatus.PhaseState != MESSAGE_OUT &&
+ interruptStatus.PhaseState != MESSAGE_IN) {
+
+ //
+ // The target controller accepted the negotiation. Set
+ // the done flag in the logical unit and clear the
+ // negotiation flags in the adapter.
+ //
+
+ deviceExtension->ActiveLogicalUnit->LuFlags |=
+ PD_SYNCHRONOUS_NEGOTIATION_DONE;
+ deviceExtension->AdapterFlags &=
+ ~(PD_SYNCHRONOUS_RESPONSE_SENT|
+ PD_SYNCHRONOUS_TRANSFER_SENT);
+
+ }
+
+ //
+ // Finally, update the message sent count to indicate that all of
+ // the current message bytes have been sent.
+ //
+
+ deviceExtension->MessageSent = deviceExtension->MessageCount;
+ break;
+
+ case StatusIn:
+
+ //
+ // Get the status value and indicate it has been received. The
+ // SCSI status value is data register.
+ //
+
+#if DBG
+ if (!deviceExtension->AdapterStatus.DataBufferReady) {
+ WdPrint((0, "WdInterruptServiceRoutine: Status in complete and data buffer not ready\n"));
+ WdDumpState(deviceExtension);
+ }
+#endif
+
+ srb->ScsiStatus = SCSI_READ(deviceExtension->Adapter, Data);
+ luExtension->LuFlags |= PD_STATUS_VALID;
+ break;
+
+ default:
+
+ //
+ // A function complete should not occur while in any other states.
+ //
+
+ WdLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 5);
+
+ WdPrint((0, "WdInterruptServiceRoutine: Unexpected function complete interrupt.\n"));
+ WdDumpState(deviceExtension);
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+
+ }
+
+
+ //
+ // Check for an Aborted or Paused interrupt.
+ //
+
+ } else if (interruptStatus.AbortedPaused &&
+ !interruptStatus.PhaseStateValid) {
+
+ //
+ // Determine the cause of this interrupt based on the state value.
+ //
+
+ switch (interruptStatus.PhaseState) {
+ case PAUSED_MESSAGE_IN_DONE:
+
+ //
+ // A message byte has been received.
+ // Call message decode to determine what to do. The message
+ // byte will either be accepted, or cause a message to be sent.
+ // A message-out is indicated to the target by setting the ATN
+ // line before sending the SCSI protocol chip the MESSAGE_ACCEPTED
+ // command.
+ //
+ // First determine if this is an IDENTIFY message for a reselect.
+ // If it is, then clear the disconnect expected flag and process
+ // the reselection. This block of code will respond the to message
+ // as necessary rather, than calling WdMessageDecode.
+ //
+
+ if (deviceExtension->MessageBuffer[0] & SCSIMESS_IDENTIFY &&
+ deviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED) {
+
+ //
+ // Process this message as a reselect.
+ //
+
+ deviceExtension->AdapterFlags &= ~PD_DISCONNECT_EXPECTED;
+ *((PUCHAR) &targetLun) = deviceExtension->MessageBuffer[0];
+
+ //
+ // Read in the target ID from the source register.
+ //
+
+ *((PUCHAR) &sourceId) = SCSI_READ(
+ deviceExtension->Adapter,
+ SourceId
+ );
+
+#if DBG
+ if (!sourceId.TargetIdValid || !targetLun.TargetLunValid) {
+
+ WdPrint((0, "WdInterruptServiceRoutine: Reselection data not valid.\n"));
+ WdPrint((0,
+ "WdInterruptServiceRoutine: Source ID: 0x%.2X; Target LUN: 0x%.2X;\n",
+ sourceId,
+ targetLun
+ ));
+ }
+
+#endif
+
+ WdProcessReselection(
+ deviceExtension,
+ (UCHAR)sourceId.TargetId,
+ (UCHAR)targetLun.LogicalUnitNumber
+ );
+
+ break;
+
+ }
+
+ if (WdMessageDecode( deviceExtension )) {
+
+ //
+ // WdMessageDecode returns TRUE if there is a message to be
+ // sent out. This message will normally be a MESSAGE REJECT
+ // or a SYNCHRONOUS DATA TRANSFER REQUEST. In any case, the
+ // message has been set up by WdMessageDecode. All that needs
+ // to be done here is to set the ATN signal and set
+ // PD_MESSAGE_OUT_VALID in the adapter flags.
+ //
+
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+ setAttention = TRUE;
+
+ } else {
+
+ setAttention = FALSE;
+
+ }
+
+ //
+ // In either case, tell the SCSI protocol chip to acknowlege or
+ // accept the message. The synchronous data transfer parameters
+ // do not need to be set.
+ //
+
+ WdAcceptMessage( deviceExtension, setAttention, FALSE);
+ waitForInterrupt = TRUE;
+ break;
+
+ case PAUSED_SAVE_POINTER_MESSAGE:
+
+ //
+ // A SAVE DATA POINTERS message was received. Perform the
+ // requested operation. Since this is a select-and-transfer
+ // operation it can be restarted from here.
+ // The data pointers are saved by copying the active pointers to
+ // their saved location in the logical unit extension.
+ //
+
+ luExtension->SavedDataPointer = deviceExtension->ActiveDataPointer;
+ luExtension->SavedDataLength = deviceExtension->ActiveDataLength;
+
+ //
+ // Restart the select-and-transfer command where it left off. All
+ // of the registers are in the correct state, but
+ // clear the transfer count so no DMA attempts occur. Finally,
+ // return.
+ //
+
+ WdIssueCommand(
+ deviceExtension, // Device Extension.
+ SELECT_ATN_AND_TRANSFER, // Command to issue.
+ 0, // New transfer count.
+ deviceExtension->CommandPhase // New CommandPhase.
+ );
+
+ return(TRUE);
+
+ case PAUSED_RESELECT_OR_SELECT:
+ case PAUSED_DURING_RESELECT:
+
+ //
+ // An abort during a selection or relection has occurred. The bus
+ // is free. Clean up the adapter state to indicate the bus
+ // is now free, and start any pending request.
+ //
+
+ deviceExtension->AdapterState = BusFree;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->ActiveLogicalUnit = NULL;
+
+ if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ //
+ // Call WdStartIo to start the pending request.
+ // Note that WdStartIo is idempotent when called with
+ // the same arguments.
+ //
+
+ WdStartIo(
+ deviceExtension,
+ deviceExtension->NextSrbRequest
+ );
+
+ }
+
+ break;
+
+ case PAUSED_NEW_TARGET_RESELECT:
+
+ //
+ // A new or different target has reselected the SCSI protocol chip.
+ // First processs the implied disconnect of the previous target by
+ // clearing the flags and saving the command phase. Then process
+ // the new reselecting target.
+ //
+
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ luExtension->SavedCommandPhase = deviceExtension->CommandPhase;
+
+ //
+ // Figure which target reselected. The target ID is in the source
+ // ID register and the logical unit number is in the target lun
+ // register.
+ //
+
+ *((PUCHAR) &sourceId) = SCSI_READ(
+ deviceExtension->Adapter,
+ SourceId
+ );
+
+ *((PUCHAR) &targetLun) = SCSI_READ(
+ deviceExtension->Adapter,
+ TargetLun
+ );
+
+#if DBG
+ if (!sourceId.TargetIdValid || !targetLun.TargetLunValid) {
+
+ WdPrint((0, "WdInterruptServiceRoutine: Reselection data not valid.\n"));
+ WdPrint((0,
+ "WdInterruptServiceRoutine: Source ID: 0x%.2X; Target LUN: 0x%.2X;\n",
+ sourceId,
+ targetLun
+ ));
+ }
+
+#endif
+
+ //
+ // Check that the message which was read in is a valid IDENTIFY
+ // message. If it is not reject the message.
+ //
+
+ if (!targetLun.TargetLunValid) {
+
+ //
+ // This is a bogus message and should be aborted.
+ // Send an abort message. Put the message in the buffer, set
+ // the state, indicate that a disconnect is expected after
+ // this, and set the attention signal.
+ //
+
+ deviceExtension->MessageBuffer[0] = SCSIMESS_ABORT;
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageSent = 0;
+ deviceExtension->AdapterState = MessageOut;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID |
+ PD_DISCONNECT_EXPECTED;
+
+ //
+ // The bus is waiting for the message to be accepted. The
+ // attention signal will be set since this is not a valid
+ // reselection. Finally, the synchronous data tranfer
+ // parameters need to be set in case a data transfer is done.
+ //
+
+ WdAcceptMessage(deviceExtension, TRUE, TRUE);
+ deviceExtension->InterruptCount = 0;
+ break;
+
+ }
+
+ WdProcessReselection(
+ deviceExtension,
+ (UCHAR)sourceId.TargetId,
+ (UCHAR)targetLun.LogicalUnitNumber
+ );
+
+ break;
+
+ default:
+
+ //
+ // A phased or abort interrupt should not occur with any other
+ // state values.
+ //
+
+ WdLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 6);
+
+ WdPrint((0, "WdInterruptServiceRoutine: Unexpected paused/aborted interrupt.\n"));
+ WdDumpState(deviceExtension);
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+
+ }
+
+ //
+ // Look for a service required interrupt.
+ //
+
+ } else if (interruptStatus.ServiceRequired &&
+ !interruptStatus.PhaseStateValid) {
+
+ //
+ // A service-required interrupt has occurred. Determine what happened
+ // based on the PhaseState code.
+ //
+
+ switch (interruptStatus.PhaseState) {
+ case SERVICE_RESELECTED:
+
+ //
+ // A target reselected; however, the IDENTIFY message has not been
+ // received. Indicate that a disconnect is expected. This will
+ // only allow the target to perform a message-in or a message-out.
+ // When the IDENTIFY message is actually received then the disconnect
+ // expected flag will be cleared.
+ //
+
+ deviceExtension->MessageCount = 0;
+ deviceExtension->AdapterFlags &= ~PD_MESSAGE_OUT_VALID;
+ deviceExtension->AdapterState = MessageOut;
+ deviceExtension->InterruptCount = 0;
+ deviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
+ waitForInterrupt = TRUE;
+
+ break;
+
+ case SERVICE_RESELECTED_IDENTIFY:
+
+ //
+ // A target reselected, and an IDENTIFY message has been received.
+ // The target ID is in the SourceId register and the IDENTIFY
+ // message is in the Data register. Get these values and process
+ // the reselection. Note that the format of the identify message
+ // is identical to that of the TargetId register.
+ //
+
+ *((PUCHAR) &sourceId) = SCSI_READ(
+ deviceExtension->Adapter,
+ SourceId
+ );
+
+ *((PUCHAR) &targetLun) = SCSI_READ(
+ deviceExtension->Adapter,
+ Data
+ );
+
+#if DBG
+ if (!sourceId.TargetIdValid || !targetLun.TargetLunValid) {
+
+ WdPrint((0, "WdInterruptServiceRoutine: Reselection data not valid.\n"));
+ WdPrint((0,
+ "WdInterruptServiceRoutine: Source ID: 0x%.2X; Target LUN: 0x%.2X;\n",
+ sourceId,
+ targetLun
+ ));
+ }
+
+#endif
+ //
+ // Check that the message which was read in is a valid IDENTIFY
+ // message. If it is not reject the message.
+ //
+
+ if (!targetLun.TargetLunValid) {
+
+ //
+ // This is a bogus message and should be aborted.
+ // Send an abort message. Put the message-in the buffer, set
+ // the state, indicate that a disconnect is expected after
+ // this, and set the attention signal.
+ //
+
+ deviceExtension->MessageBuffer[0] = SCSIMESS_ABORT;
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageSent = 0;
+ deviceExtension->AdapterState = MessageOut;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID |
+ PD_DISCONNECT_EXPECTED;
+
+ //
+ // The bus is waiting for the message to be accepted. The
+ // attention signal will be set since this is not a valid
+ // reselection. Finally, the synchronous data tranfer
+ // parameters need to be set in case a data transfer is done.
+ //
+
+ WdAcceptMessage(deviceExtension, TRUE, TRUE);
+ deviceExtension->InterruptCount = 0;
+ break;
+
+ }
+
+ WdProcessReselection(
+ deviceExtension,
+ (UCHAR)sourceId.TargetId,
+ (UCHAR)targetLun.LogicalUnitNumber
+ );
+
+ break;
+
+ case SERVICE_DISCONNECTED:
+
+ //
+ // A disconnect has occurred. Clean up the state and check for
+ // pending requests.
+ // Check to see if this was a send-message request which is
+ // completed when the disconnect occurs.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
+
+ //
+ // Complete the request.
+ //
+
+ WdCompleteSendMessage( deviceExtension,
+ SRB_STATUS_SUCCESS
+ );
+ }
+
+ //
+ // Save the command phase for the logical unit.
+ //
+
+ luExtension->SavedCommandPhase = deviceExtension->CommandPhase;
+
+ //
+ // If this disconnect was not expected or the command phase is not
+ // correct for a legal disconnect, then this is a unexpected
+ // disconnect.
+ //
+
+ if (deviceExtension->CommandPhase != PHASE_LEGAL_DISCONNECT &&
+ !(deviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED)) {
+
+ //
+ // An unexpected disconnect occurred; make sure this is not
+ // related to a synchronous message.
+ //
+
+ if (deviceExtension->AdapterFlags &
+ (PD_SYNCHRONOUS_RESPONSE_SENT | PD_SYNCHRONOUS_TRANSFER_SENT |
+ PD_POSSIBLE_EXTRA_MESSAGE_OUT)) {
+
+ //
+ // This target cannot negotiate properly. Set a flag to
+ // prevent further attempts and set the synchronous
+ // parameters to use asynchronous data transfer.
+ //
+
+ /* TODO: Consider propagating this flag to all the Lus on this target. */
+ luExtension->LuFlags |= PD_DO_NOT_NEGOTIATE;
+ luExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ luExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+
+ }
+
+ WdPrint((0, "WdInterruptServiceRoutine: Unexpected bus disconnect\n"));
+ WdLogError(deviceExtension, SP_UNEXPECTED_DISCONNECT, 7);
+
+ }
+
+ //
+ // Clean up the adapter state to indicate the bus is now free, enable
+ // reselection, and start any pending request.
+ //
+
+ deviceExtension->AdapterState = BusFree;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->ActiveLogicalUnit = NULL;
+
+#if DBG
+ if (WdDebug) {
+ WdPrint((0, "WdInterruptServiceRoutine: DisconnectComplete.\n"));
+ }
+#endif
+
+ if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ //
+ // Call WdStartIo to start the pending request.
+ // Note that WdStartIo is idempotent when called with
+ // the same arguments.
+ //
+
+ WdStartIo(
+ deviceExtension,
+ deviceExtension->NextSrbRequest
+ );
+
+ }
+
+ break;
+
+ default:
+
+ //
+ // This interrupt should not occur with any other
+ // state values.
+ //
+
+ WdPrint((0, "WdInterruptServiceRoutine: Unexpected service required interrupt.\n"));
+ WdDumpState(deviceExtension);
+ WdLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 8);
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+ }
+
+
+ //
+ // Look for a terminated interrupt.
+ //
+
+ } else if (interruptStatus.Terminated &&
+ !interruptStatus.PhaseStateValid) {
+
+ //
+ // A terminated interrupt occurred. Decode the state information to
+ // determine why this happened.
+ //
+
+ switch (interruptStatus.PhaseState) {
+ case TERMINATE_INVALID_COMMAND:
+
+ //
+ // The chip detected an invalid command. This may occur during
+ // normal operation if a select is attempted at the same time that
+ // a reselect occurred.
+ //
+
+#if DBG
+ WdPrint((0, "WdInterruptServiceRoutine: Invalid command interrupt occurred\n"));
+ WdDumpState(deviceExtension);
+#endif
+
+ WdLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 9);
+
+ //
+ // Things appear to be messed up. Reset the bus and the chip.
+ //
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+ break;
+
+ case TERMINATE_UNEXPECTED_DISC:
+
+ //
+ // An unexpected disconnect occurred; make sure this is not
+ // related to a synchronous message.
+ //
+
+ if (deviceExtension->AdapterFlags &
+ (PD_SYNCHRONOUS_RESPONSE_SENT | PD_SYNCHRONOUS_TRANSFER_SENT |
+ PD_POSSIBLE_EXTRA_MESSAGE_OUT)) {
+
+ //
+ // This target cannot negotiate properly. Set a flag to
+ // prevent further attempts and set the synchronous
+ // parameters to use asynchronous data transfer.
+ //
+
+ /* TODO: Consider propagating this flag to all the Lus on this target. */
+ luExtension->LuFlags |= PD_DO_NOT_NEGOTIATE;
+ luExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ luExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+
+ }
+
+ //
+ // An unexpected disconnect has occurred. Log the error. It is
+ // not clear if the device will respond again, so let the time-out
+ // code clean up the request if necessary.
+ //
+
+ WdPrint((0, "WdInterruptServiceRoutine: Unexpected bus disconnect\n"));
+ WdLogError(deviceExtension, SP_UNEXPECTED_DISCONNECT, 10);
+
+
+
+ //
+ // Clean up the adapter state to indicate the bus is now free,
+ // and start any pending request.
+ //
+
+ deviceExtension->AdapterState = BusFree;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->ActiveLogicalUnit = NULL;
+
+#if DBG
+ if (WdDebug) {
+ WdPrint((0, "WdInterruptServiceRoutine: DisconnectComplete.\n"));
+ }
+#endif
+
+ if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ //
+ // Call WdStartIo to start the pending request.
+ // Note that WdStartIo is idempotent when called with
+ // the same arguments.
+ //
+
+ WdStartIo(
+ deviceExtension,
+ deviceExtension->NextSrbRequest
+ );
+
+ }
+
+ break;
+
+ case TERMINATE_SELECT_TIMEOUT:
+
+ //
+ // The target selection failed. Log the error. If the retry
+ // count is not exceeded then retry the selection; otherwise
+ // fail the request.
+ //
+
+ if (luExtension->RetryCount++ >= RETRY_SELECTION_LIMIT) {
+
+ //
+ // Clear the Active request in the logical unit.
+ //
+
+ if (deviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
+ luExtension->ActiveSendRequest = NULL;
+ } else {
+ luExtension->ActiveLuRequest = NULL;
+ }
+
+ luExtension->RetryCount = 0;
+ deviceExtension->NextSrbRequest->SrbStatus =
+ SRB_STATUS_SELECTION_TIMEOUT;
+
+ ScsiPortNotification(
+ RequestComplete,
+ deviceExtension,
+ deviceExtension->NextSrbRequest
+ );
+
+ deviceExtension->NextSrbRequest = NULL;
+ deviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
+
+ ScsiPortNotification(
+ NextRequest,
+ deviceExtension,
+ NULL
+ );
+ }
+
+ //
+ // Clean up the adapter state to indicate the bus is now free,
+ // and start any pending request.
+ //
+
+ deviceExtension->AdapterState = BusFree;
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ deviceExtension->ActiveLogicalUnit = NULL;
+
+#if DBG
+ if (WdDebug) {
+ WdPrint((0, "WdInterruptServiceRoutine: DisconnectComplete.\n"));
+ }
+#endif
+
+ if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
+
+ //
+ // Call WdStartIo to start the pending request.
+ // Note that WdStartIo is idempotent when called with
+ // the same arguments.
+ //
+
+ WdStartIo(
+ deviceExtension,
+ deviceExtension->NextSrbRequest
+ );
+
+ }
+
+ break;
+
+ case TERMINATE_PARITY_NO_ATN:
+ case TERMINATE_PARITY_STATUS_IN:
+ case TERMINATE_PARITY_WITH_ATN:
+
+ //
+ // The SCSI protocol chip has set not ATN; we expect the target to
+ // go into message-out so that a error message can be sent and the
+ // operation retried. After the error has been noted, continue
+ // processing the interrupt. The message sent depends on whether a
+ // message was being received: if the adapter
+ // state is currently message-in then send-message PARITY ERROR;
+ // otherwise, send INITIATOR DETECTED ERROR.
+ //
+
+ WdPrint((0, "WdInterruptServiceRoutine: Parity error detected.\n"));
+ WdDumpState(deviceExtension);
+
+ if (!(deviceExtension->AdapterFlags & PD_PARITY_ERROR)) {
+
+ //
+ // Only log one parity error per request.
+ //
+
+ WdLogError(deviceExtension, SP_BUS_PARITY_ERROR, 11);
+ }
+
+ //
+ // If the ATN single has not been set then set it and clear the ACK
+ // signal.
+ //
+
+ if (!(interruptStatus.PhaseState == TERMINATE_PARITY_WITH_ATN)) {
+
+ //
+ // The ATN signal must be set.
+ //
+
+ WdAcceptMessage(deviceExtension, TRUE, FALSE);
+
+ } else {
+
+ //
+ // ATN is already set so just clear ACK.
+ //
+
+ WdAcceptMessage(deviceExtension, FALSE, FALSE);
+
+ }
+
+
+ deviceExtension->MessageBuffer[0] =
+ deviceExtension->AdapterState == MessageIn ?
+ SCSIMESS_MESS_PARITY_ERROR : SCSIMESS_INIT_DETECTED_ERROR;
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageSent = 0;
+ deviceExtension->AdapterState = MessageOut;
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID | PD_PARITY_ERROR;
+
+ break;
+
+ case TERMINATE_NEW_TRAGET_NO_ID:
+
+ //
+ // First processs the implied disconnect of the previous target by
+ // clearing the flags and saving the command phase. Then process
+ // the new reselecting target.
+ //
+
+ deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ luExtension->SavedCommandPhase = deviceExtension->CommandPhase;
+
+ //
+ // A new target as reselected; however, the IDENTIFY message has
+ // not been received yet. The target Id is in the destination
+ // register. Indicate that a disconnect is expected. This will
+ // only allow the target to perform a message-in or the message-out.
+ // When the IDENTIFY message is actually received then the disconnect
+ // expected flag will be cleared.
+ //
+
+ deviceExtension->MessageCount = 0;
+ deviceExtension->AdapterFlags &= ~PD_MESSAGE_OUT_VALID;
+ deviceExtension->AdapterState = MessageOut;
+ deviceExtension->InterruptCount = 0;
+ deviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
+ waitForInterrupt = TRUE;
+
+ break;
+
+
+ default:
+
+ //
+ // This interrupt should not occur with any other
+ // state values.
+ //
+
+ WdLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 12);
+
+ WdPrint((0, "WdInterruptServiceRoutine: Unexpected terminated interrupt.\n"));
+ WdDumpState(deviceExtension);
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+
+ }
+
+ } else if (interruptStatus.Terminated &&
+ interruptStatus.PhaseStateValid) {
+
+ //
+ // A select-and-transfer command was halted because of an unexpected
+ // phase or because a simple transfer command was not completed because
+ // the target switched to a new phase.
+ // If this was part of a synchronous negotiation and the phase is
+ // message-out, then the target do not read all of the message bytes
+ // may later request extra bytes.
+ //
+
+ if (deviceExtension->AdapterState == MessageOut) {
+
+ ULONG count;
+
+ //
+ // Read the transfer counter to determine how many message bytes
+ // have been sent to the target and update the message sent count.
+ // This is necessary in case the message out needs to be restarted.
+ //
+
+ SCSI_READ_TRANSFER_COUNT(deviceExtension->Adapter, count);
+
+ deviceExtension->MessageSent = (UCHAR)(deviceExtension->MessageCount -
+ count);
+
+ if (deviceExtension->AdapterFlags & (PD_SYNCHRONOUS_TRANSFER_SENT |
+ PD_SYNCHRONOUS_RESPONSE_SENT)) {
+
+ //
+ // The target do not read all of the message bytes as it should
+ // have. This is not a problem except that some targets will
+ // come back later and try to read more bytes. Indicate that
+ // this is ok.
+ //
+
+ deviceExtension->AdapterFlags |= PD_POSSIBLE_EXTRA_MESSAGE_OUT;
+
+ }
+
+ }
+
+ //
+ // Based on the command phase determine if any data needs to be saved.
+ // The important cases are:
+ //
+ // Status byte read in.
+ // Command complete message read in.
+ //
+
+ switch (deviceExtension->CommandPhase) {
+ case PHASE_STATUS_RECEIVED:
+
+ //
+ // Get the status value and indicate it has been received. The
+ // SCSI status value is TargetLun.
+ //
+
+ srb->ScsiStatus = SCSI_READ(deviceExtension->Adapter, TargetLun);
+ luExtension->LuFlags |= PD_STATUS_VALID;
+ break;
+
+ case PHASE_COMPLETE_RECEIVED:
+
+ //
+ // The request is almost complete. A status has been received and
+ // the COMMAND COMPLETE message has been received; however, the
+ // target has not disconnected yet.
+ //
+
+ srb = luExtension->ActiveLuRequest;
+
+ //
+ // Get the status value and indicate it has been received. The
+ // SCSI status value is saved the the TargetLun register.
+ //
+
+ srb->ScsiStatus = SCSI_READ(deviceExtension->Adapter, TargetLun);
+ luExtension->LuFlags |= PD_STATUS_VALID;
+
+ //
+ // Simulate the COMMAND COMPLETE message.
+ //
+
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageBuffer[0] = SCSIMESS_COMMAND_COMPLETE;
+ WdMessageDecode(deviceExtension);
+
+ //
+ // The next thing which should occur is a disconnect; however, this
+ // point is reached when the target makes a new request after the
+ // COMMAND COMPLETE message. WdMessageDecode has set the
+ // AdapterState correct, so try and process the target's request.
+ // This usually occurs with screwy targets which are messed up by
+ // synchronous negotiation messages.
+ //
+
+ break;
+ }
+
+ //
+ // Check for a reset interrupt. This is indicated by an interrupt with
+ // no interrupt bits set.
+ //
+
+ } else if (!interruptStatus.PhaseStateValid) {
+
+ //
+ // The SCSI protocol chip was reset.
+ //
+
+ WdPrint((0, "WdInterruptServiceRoutine: The SCSI protocol chip was reset.\n"));
+ WdDumpState(deviceExtension);
+
+ if (interruptStatus.PhaseState != RESET_WITH_ADVANCED &&
+ interruptStatus.PhaseState != RESET_STATUS) {
+ WdPrint((0, "WdInterruptServiceRoutine: SCSI chip reset failed. Status: 0x%.2X.\n",
+ *((PUCHAR) &interruptStatus)
+ ));
+
+ WdLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 13);
+
+ }
+
+ if (interruptStatus.PhaseState == RESET_STATUS ) {
+
+ OWN_ID ownId;
+
+ //
+ // The OwnId register must be set when the SCSI protocol chip is reset.
+ // Initialize the ownId with the adapter's host ID, advanced features,
+ // and the correct clock frequency select. Note the CdbSize register is
+ // used as the OwnId register when a reset command is issued.
+ //
+
+ *((PUCHAR) &ownId) = 0;
+ ownId.InitiatorId = deviceExtension->InitiatorBusId;
+ ownId.AdvancedFeatures = 1;
+ ownId.FrequencySelect = CLOCK_CONVERSION_FACTOR;
+
+ SCSI_WRITE( deviceExtension->Adapter, CdbSize, *((PUCHAR) &ownId) );
+
+ //
+ // Issue a reset-chip command.
+ //
+
+ WdIssueCommand(deviceExtension, RESET_SCSI_CHIP, -1, 0);
+
+ return(TRUE);
+
+ } else {
+
+ SCSI_CONTROL control;
+
+ //
+ // Clean up the logical units and notify the port driver,
+ // then return.
+ //
+
+ WdCleanupAfterReset(deviceExtension, TRUE);
+ ScsiPortNotification(
+ ResetDetected,
+ deviceExtension,
+ NULL
+ );
+
+ //
+ // Set the control register for halt on parity error, halt on ATN, ending
+ // disconnect interrupt, and normal DMA mode.
+ //
+
+ *((PUCHAR) &control) = 0;
+ control.HaltOnParity = 1;
+ control.HaltOnAtn = 1;
+ control.IntermediateDisconnectInt = 1;
+ control.EndingDisconnectInt = 1;
+ control.DmaModeSelect = CARD_DMA_MODE;
+
+ SCSI_WRITE(deviceExtension->Adapter, Control, *((PUCHAR) &control));
+
+ //
+ // Set the SelectTimeOut Register to 250ms. This value does not need to
+ // be reinitialized for each selection.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Timeout, SELECT_TIMEOUT_VALUE);
+
+ //
+ // Initialize the source register, in particular, enable reselection.
+ //
+
+ *((PUCHAR) &sourceId) = 0;
+ sourceId.EnableReselection = 1;
+
+ SCSI_WRITE(deviceExtension->Adapter, SourceId, *((PUCHAR) &sourceId));
+
+ //
+ // DO NOT REMOVE THE FOLLOWING SCSI_WRITE( )!
+ // It may look superfluous, but it is not.
+ // It is here to keep another driver in the system that
+ // is erroneously outputting to I/O port address 0x361
+ // during setup from triggering an unexpected interrupt
+ // from the Maynard card and hence crashing this driver.
+ //
+
+ SCSI_WRITE(deviceExtension->Adapter, Data, 0);
+
+ deviceExtension->AdapterState = BusFree;
+ deviceExtension->ActiveLogicalUnit = NULL;
+
+ return(TRUE);
+
+ }
+
+ }
+
+ //
+ // Check for to see if the traget is
+ // is requesting some form of bus-transfer. The bus transfer type is
+ // determined by the bus phase. This is indicated by the
+ // StatusPhaseValid
+ //
+
+ if (interruptStatus.PhaseStateValid) {
+
+ //
+ // The bus is changing phases or needs more data.
+ //
+
+ if (deviceExtension->AdapterState == MessageOut) {
+
+ //
+ // The adapter state indicates that a message has been
+ // sent. The target may need to reread it or there may
+ // be more messages to send: this condition is indicated
+ // by a message-out bus phase. Otherwise, the message has
+ // been accepted by the target. Note that the driver state
+ // is set to MessageOut after PD_DISCONNECT_EXPECTED is set,
+ // or after a selection. So it is only necessary to check
+ // for PD_DISCONNECT_EXPECTED when the driver state is
+ // MessageOut.
+ //
+
+ if ((deviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED) &&
+ (interruptStatus.PhaseState != MESSAGE_OUT) &&
+ (interruptStatus.PhaseState != MESSAGE_IN)) {
+
+ //
+ // If a disconnect was expected and a bus service
+ // interrupt was detected, then a SCSI protocol error
+ // has been detected and the SCSI bus should be reset
+ // to clear the condition.
+ //
+
+ WdLogError(deviceExtension, SP_PROTOCOL_ERROR, 14);
+ WdPrint((0, "WdInterruptServiceRoutine: Bus request while disconnect expected after message-out.\n"));
+ WdDumpState(deviceExtension);
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+
+ }
+ }
+
+ //
+ // Decode the current bus phase.
+ //
+
+ switch (interruptStatus.PhaseState) {
+
+ case COMMAND_OUT:
+
+ //
+ // Transfer the SCSI command block to the chip.
+ //
+
+ deviceExtension->AdapterState = CommandOut;
+
+ WdTransferInformation(
+ deviceExtension,
+ srb->Cdb,
+ srb->CdbLength,
+ TRUE
+ );
+
+ break;
+
+ case STATUS_IN:
+
+ //
+ // Setup of the SCSI protocol chip to read in the status, read the
+ // following message byte, and wait for the final disconnect and
+ // set the adapter state.
+ //
+
+ deviceExtension->AdapterState = MessageAccepted;
+
+
+ //
+ // Clear the transfer counter registers. This is necessary for the
+ // chip to really believe that the transfer has completed.
+ // Set the CommandPhase register to resume with a status-in phase,
+ // and command the SCSI protocol chip to resume a
+ // select-and-transfer command.
+ //
+
+ WdIssueCommand(
+ deviceExtension, // Device Extension.
+ SELECT_ATN_AND_TRANSFER, // Command to issue.
+ 0, // New transfer count.
+ PHASE_DATA_TRANSFER_DONE // New CommandPhase.
+ );
+
+ break;
+
+ case MESSAGE_OUT:
+
+ //
+ // The target is requesting a message-out. There are four
+ // possible cases:
+ //
+ // 1. ATN has been asserted (because of a data under
+ // run condition) to force the target out of data
+ // transfer phase and into message out phase.
+ //
+ // 2. The target is improperly requesting a message.
+ //
+ // 3. A message has been sent, but the target could not
+ // read it properly.
+ //
+ // 4. It is a "normal" message out: all or the remainder
+ // of a message is ready and waiting to be sent.
+ //
+
+ //
+ // The first case is indicated when the adapter state is
+ // DataTransferComplete.
+ //
+
+ if (deviceExtension->AdapterState == DataTransferComplete) {
+
+ //
+ // The target was trying to go into, or stay in,
+ // data transfer phase, but we did not expect it
+ // to do so. Complete the request here and now
+ // and send an abort message to tell the target
+ // to abort the transfer.
+ //
+
+ srb->ScsiStatus = SCSISTAT_GOOD;
+ luExtension->LuFlags &= ~PD_STATUS_VALID;
+ WdProcessRequestCompletion(deviceExtension);
+ ScsiPortNotification(
+ RequestComplete,
+ deviceExtension,
+ srb
+ );
+
+ deviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+ deviceExtension->MessageBuffer[0] = SCSIMESS_ABORT;
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageSent = 0;
+ }
+
+ //
+ // The second case is indicated when the MessageCount is
+ // zero or the message-out flag is not set.
+ //
+
+ if ( deviceExtension->MessageCount == 0 ||
+ !(deviceExtension->AdapterFlags & PD_MESSAGE_OUT_VALID)
+ ) {
+
+ //
+ // If extra message-outs are possible then just send a NOP
+ // message.
+
+ if (deviceExtension->AdapterFlags &
+ PD_POSSIBLE_EXTRA_MESSAGE_OUT) {
+
+ //
+ // Set the message to NOP and clear the extra message
+ // flag. This is a hack for controllers that do not
+ // properly read the entire message.
+ //
+
+ deviceExtension->MessageBuffer[0] = SCSIMESS_NO_OPERATION;
+ deviceExtension->AdapterFlags &=
+ ~PD_POSSIBLE_EXTRA_MESSAGE_OUT;
+ } else {
+
+ //
+ // Send an INITIATOR DETECTED ERROR message.
+ //
+
+ deviceExtension->MessageBuffer[0] =
+ SCSIMESS_INIT_DETECTED_ERROR;
+
+ WdLogError(deviceExtension, SP_PROTOCOL_ERROR, 15);
+
+ WdPrint((0, "WdInterruptServiceRoutine: Unexpected message-out request\n"));
+ WdDumpState(deviceExtension);
+
+ }
+
+ deviceExtension->AdapterState = MessageOut;
+ deviceExtension->MessageCount = 1;
+ deviceExtension->MessageSent = 0;
+
+ }
+
+ //
+ // The third case is indicated when MessageCount and MessageSent
+ // are equal and nonzero (note: MessageCount can't be zero at
+ // this point because of the first or second case above).
+ //
+
+ if (deviceExtension->MessageCount == deviceExtension->MessageSent){
+
+ //
+ // The message needs to be re-sent, so clear MessageSent
+ // and fall through to the next case.
+ //
+
+ deviceExtension->MessageSent = 0;
+ }
+
+ //
+ // The fourth case and/or fallout from the cases above is
+ // taken care of by default hereinafter.
+ //
+
+ //
+ // Clear the parity error flag.
+ //
+
+ deviceExtension->AdapterFlags &= ~PD_PARITY_ERROR;
+
+ //
+ // Tell the SCSI protocol chip to "go" and
+ // transfer the message to the data register.
+ //
+
+ deviceExtension->AdapterState = MessageOut;
+ SCSI_WRITE(deviceExtension->Adapter, Command, ASSERT_ATN);
+ WdTransferInformation(
+ deviceExtension,
+ &deviceExtension->MessageBuffer[deviceExtension->MessageSent],
+ deviceExtension->MessageCount - deviceExtension->MessageSent,
+ TRUE
+ );
+
+ break;
+
+ case MESSAGE_IN:
+
+ //
+ // If this is the first byte of the message then initialize
+ // MessageCount and the adapter state. The message buffer
+ // cannot overflow because the message decode function will
+ // take care of the message before the buffer is full.
+ // The SCSI protocol chip will interrupt for each message
+ // byte.
+ //
+
+ if ( deviceExtension->AdapterState != MessageIn &&
+ deviceExtension->AdapterState != MessageAccepted ) {
+
+ deviceExtension->AdapterFlags &= ~PD_MESSAGE_OUT_VALID;
+ deviceExtension->MessageCount = 0;
+ }
+
+ deviceExtension->AdapterState = MessageIn;
+ waitForInterrupt = TRUE;
+
+ //
+ // Set the transfer counter registers to one byte and write
+ // the command register.
+ //
+
+ WdTransferInformation(
+ deviceExtension,
+ &deviceExtension->MessageBuffer[deviceExtension->MessageCount++],
+ 1,
+ FALSE
+ );
+
+ break;
+
+ case DATA_OUT:
+ case DATA_IN:
+
+ if (deviceExtension->AdapterState == CommandOut) {
+ //
+ // Check that the transfer direction is ok.
+ //
+
+ if ((!(srb->SrbFlags & SRB_FLAGS_DATA_IN) &&
+ (interruptStatus.PhaseState == DATA_IN)) ||
+
+ (!(srb->SrbFlags & SRB_FLAGS_DATA_OUT) &&
+ (interruptStatus.PhaseState == DATA_OUT))) {
+
+ //
+ // The data direction is incorrect.
+ // Reset the bus to clear things up.
+ //
+
+ WdPrint((0, "WdInterruptServiceRoutine: Illegal transfer direction.\n"));
+ WdDumpState(deviceExtension);
+
+ WdLogError(deviceExtension, SP_PROTOCOL_ERROR, 16);
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+ return(TRUE);
+ }
+ }
+
+ if (deviceExtension->ActiveDataLength == 0) {
+ WdPrint((0, "WdInterruptServiceRoutine: Data underrun!\n"));
+
+ //
+ // We have a data under run condition!
+ // The target is trying to go into, or stay in,
+ // data transfer phase, but we did not expect it
+ // to do so. Set ATN to force the target out of
+ // data phase and into message out phase in order
+ // to tell the target to abort the data transfer.
+ //
+
+ deviceExtension->InterruptCount--;
+ deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+ SCSI_WRITE(deviceExtension->Adapter, Command, ASSERT_ATN);
+ WdTransferInformation(
+ deviceExtension,
+ &deviceExtension->MessageBuffer[MESSAGE_BUFFER_SIZE-1],
+ 1,
+ (BOOLEAN)((interruptStatus.PhaseState == DATA_OUT)? TRUE : FALSE)
+ );
+ waitForInterrupt = TRUE;
+
+ } else if (deviceExtension->ActiveDataLength == 1) {
+
+ //
+ // We have a final (or only), odd length byte to transfer.
+ //
+
+ deviceExtension->AdapterState = DataTransfer;
+ WdTransferInformation(
+ deviceExtension,
+ (PUCHAR)deviceExtension->ActiveDataPointer,
+ 1,
+ (BOOLEAN) ((interruptStatus.PhaseState == DATA_OUT)? TRUE : FALSE)
+ );
+
+ waitForInterrupt = TRUE;
+
+ } else {
+
+ //
+ // Setup a DMA data transfer.
+ //
+
+ deviceExtension->DmaPhase = 0;
+ deviceExtension->DmaCommand = TRANSFER_INFORMATION;
+ deviceExtension->AdapterState = DataTransfer;
+ deviceExtension->AdapterFlags |= PD_DMA_ACTIVE |
+ PD_PENDING_DATA_TRANSFER;
+ deviceExtension->ActiveDataLength &= ~((ULONG)1);
+
+ ScsiPortIoMapTransfer(
+ deviceExtension,
+ srb,
+ (PVOID) deviceExtension->ActiveDataPointer,
+ deviceExtension->ActiveDataLength
+ );
+ }
+ return(TRUE);
+ break;
+
+ default:
+
+ //
+ // This phase is illegal and indicates a serious error. Reset the
+ // bus to clear the problem.
+ //
+
+ WdLogError(deviceExtension, SP_PROTOCOL_ERROR, 17);
+
+ WdPrint((0, "WdInterruptServiceRoutine: Illegal bus state detected.\n"));
+ WdDumpState(deviceExtension);
+
+ WdResetScsiBusInternal(deviceExtension, 0);
+
+ return(TRUE);
+ }
+ }
+
+ //
+ // If an interrupt is expected, then wait a short time for it.
+ //
+
+ if (waitForInterrupt) {
+
+ for (waitCount = 0; waitCount < INTERRUPT_STALL_TIME; waitCount++) {
+
+ ScsiPortStallExecution(1);
+
+ //
+ // Read the auxilary status register to determine if the there is
+ // an interrupt.
+ //
+
+ *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ_AUX(
+ deviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ //
+ // If there is an interrupt, then start to process it.
+ //
+
+ if (deviceExtension->AdapterStatus.Interrupt) {
+ goto NextInterrupt;
+ }
+ }
+ }
+
+ return(TRUE);
+}
+
+VOID
+WdLogError(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG ErrorCode,
+ IN ULONG UniqueId
+ )
+/*++
+
+Routine Description:
+
+ This routine logs an error.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension for the
+ port adapter to which the completing target controller is connected.
+
+ ErrorCode - Supplies the error code to log with the error.
+
+ UniqueId - Supplies the unique error identifier.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PSCSI_REQUEST_BLOCK srb;
+
+ //
+ // Look for a current request in the device extension.
+ //
+
+ if (DeviceExtension->ActiveLogicalUnit != NULL) {
+
+ if (DeviceExtension->ActiveLogicalUnit->ActiveLuRequest != NULL) {
+
+ srb = DeviceExtension->ActiveLogicalUnit->ActiveLuRequest;
+
+ } else {
+
+ srb = DeviceExtension->ActiveLogicalUnit->ActiveSendRequest;
+
+ }
+ } else {
+
+ srb = DeviceExtension->NextSrbRequest;
+
+ }
+
+ //
+ // If the srb is NULL, then log the error against the host adapter address.
+ //
+
+ if (srb == NULL) {
+
+ ScsiPortLogError(
+ DeviceExtension, // HwDeviceExtension,
+ NULL, // Srb
+ 0, // PathId,
+ DeviceExtension->InitiatorBusId, // TargetId,
+ 0, // Lun,
+ ErrorCode, // ErrorCode,
+ UniqueId // UniqueId
+ );
+
+ } else {
+
+ ScsiPortLogError(
+ DeviceExtension, // HwDeviceExtension,
+ srb, // Srb
+ srb->PathId, // PathId,
+ srb->TargetId, // TargetId,
+ srb->Lun, // Lun,
+ ErrorCode, // ErrorCode,
+ UniqueId // UniqueId
+ );
+
+ }
+
+}
+
+VOID
+WdProcessRequestCompletion(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
+ )
+/*++
+
+Routine Description:
+
+ This routine does all of checking and state updating necessary when a
+ request terminates normally. It determines what the SrbStatus
+ should be and updates the state in the DeviceExtension, the
+ logicalUnitExtension and the srb.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension for the
+ port adapter to which the completing target controller is connected.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK srb;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+
+ luExtension = DeviceExtension->ActiveLogicalUnit;
+ srb = luExtension->ActiveLuRequest;
+
+ if ( srb->ScsiStatus != SCSISTAT_GOOD &&
+ srb->ScsiStatus != SCSISTAT_CONDITION_MET &&
+ srb->ScsiStatus != SCSISTAT_INTERMEDIATE &&
+ srb->ScsiStatus != SCSISTAT_INTERMEDIATE_COND_MET ) {
+
+ //
+ // Indicate an abnormal status code.
+ //
+
+ srb->SrbStatus = SRB_STATUS_ERROR;
+
+ //
+ // Add in the INITIATE RECOVERY flag if it was received. This
+ // indicates to the class driver that it must send a TERMINATE
+ // RECOVERY message before the logical unit will resume normal
+ // operation.
+ //
+
+#ifdef SRB_INITIATE_RECOVERY
+ if (DeviceExtension->ActiveLogicalUnit->LuFlags &
+ PD_INITIATE_RECOVERY) {
+
+ //
+ // Modify the SrbStatus.
+ //
+
+ srb->SrbStatus |= SRB_INITIATE_RECOVERY;
+ }
+#endif
+
+ //
+ // If this is a check condition, then clear the synchronous negotiation
+ // done flag. This is done in case the controller was power cycled.
+ //
+
+ if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) {
+
+ luExtension->LuFlags &= ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
+
+ }
+
+ } else {
+
+ //
+ // Everything looks correct so far.
+ //
+
+ srb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ //
+ // Make sure that status is valid.
+ //
+
+ if (!(luExtension->LuFlags & PD_STATUS_VALID)) {
+
+ //
+ // The status byte is not valid.
+ //
+
+ srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+
+ //
+ // Log the error.
+ //
+
+ WdLogError(DeviceExtension, SP_PROTOCOL_ERROR, 20);
+
+ }
+
+ }
+
+ //
+ // Check that data was transferred to the end of the buffer.
+ //
+
+ if ( luExtension->MaximumTransferLength != srb->DataTransferLength ){
+
+ //
+ // The entire buffer was not transferred. Update the length
+ // and update the status code.
+ //
+
+#if DBG
+ if (srb->SrbStatus == SRB_STATUS_SUCCESS) {
+
+ WdPrint((1, "WdProcessRequestCompletion: Short transfer, Actual: %lu; Expected: %lu;\n",
+ luExtension->MaximumTransferLength,
+ srb->DataTransferLength
+ ));
+
+ }
+#endif
+ srb->DataTransferLength = luExtension->MaximumTransferLength;
+
+ //
+ // If the request was ok upto this point then over write the status
+ // with data overrun.
+ //
+
+ if (srb->SrbStatus == SRB_STATUS_SUCCESS) {
+
+ srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ }
+ }
+
+#if DBG
+ if (srb->SrbStatus != SRB_STATUS_SUCCESS) {
+ WdPrint((1, "WdProcessRequestCompletion: Request failed. ScsiStatus: 0x%.2X, SrbStatus: 0x%.2X\n",
+ srb->ScsiStatus,
+ srb->SrbStatus
+ ));
+ }
+#endif
+
+ //
+ // Clear the request but not the ActiveLogicalUnit since the target has
+ // not disconnected from the SCSI bus yet.
+ //
+
+ luExtension->ActiveLuRequest = NULL;
+ luExtension->RetryCount = 0;
+ luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
+}
+
+BOOLEAN
+WdProcessReselection(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR TargetId,
+ IN UCHAR LogicalUnitNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This function updates the device extension and the logical unit extension
+ when target reselects. If necessary, the DMA is set up. This routine
+ should be called before the identify message has been accepted. The SCSI
+ protocol chip will be restarted with either a select-and-transfer command
+ or a message accept.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+ TargetId - Supplies the target id of the reselecting target.
+
+ LogicalUnitNumber - Supplies the logical unit number of the reselecting
+ target.
+
+Return Value:
+
+ TRUE - Returned if the reselection is valid.
+
+ FALSE - Returned if the reselection is invalid and ATN should be set.
+
+--*/
+
+{
+ LONG pathId = 0;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ DESTINATION_ID destinationId;
+ SCSI_SYNCHRONOUS scsiSynchronous;
+
+
+ DeviceExtension->InterruptCount = 0;
+
+ //
+ // Get the specific logical unit extension.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(
+ DeviceExtension,
+ (UCHAR)pathId,
+ TargetId,
+ LogicalUnitNumber
+ );
+
+ DeviceExtension->ActiveLogicalUnit = luExtension;
+
+ if (!luExtension || !luExtension->ActiveLuRequest) {
+
+ ScsiPortLogError(
+ DeviceExtension, // HwDeviceExtension,
+ NULL, // Srb
+ (UCHAR)pathId, // PathId,
+ TargetId, // TargetId,
+ LogicalUnitNumber, // Lun,
+ SP_INVALID_RESELECTION, // ErrorCode,
+ 18 // UniqueId
+ );
+
+
+ WdPrint((0, "WdProcessReselection: Reselection Failed.\n"));
+ WdDumpState(DeviceExtension);
+
+ //
+ // Send an abort message. Put the message-in the buffer, set the
+ // state, indicate that a disconnect is expected after this, and
+ // set the attention signal.
+ //
+
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_ABORT;
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->AdapterState = MessageOut;
+ DeviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
+ DeviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID |
+ PD_DISCONNECT_EXPECTED;
+
+
+ //
+ // The target and logical unit specified are not valid. A
+ // MESSAGE REJECT message has been set up. Set ATN and accept the
+ // message.
+ //
+
+ WdAcceptMessage(DeviceExtension, TRUE, FALSE);
+
+ return(FALSE);
+
+ }
+
+ srb = luExtension->ActiveLuRequest;
+
+ //
+ // A reselection has been completed. Set the active logical unit,
+ // restore the active data pointer, set the state.
+ // In addition, any adapter flags set by a pending select must be
+ // cleared using the disconnect mask.
+ //
+
+ DeviceExtension->ActiveDataPointer = luExtension->SavedDataPointer;
+ DeviceExtension->ActiveDataLength = luExtension->SavedDataLength;
+ DeviceExtension->AdapterState = MessageAccepted;
+ DeviceExtension->MessageCount = 0;
+
+ //
+ // Determine if the DMA needs to be done then set the synchronous transfer
+ // register.
+ //
+
+ if (luExtension->SavedDataLength) {
+
+ //
+ // Set the synchronous data transfer parameter registers in case a
+ // data transfer will be done. These must be set before a data transfer
+ // is started.
+ //
+
+ *((PUCHAR) &scsiSynchronous) = 0;
+ scsiSynchronous.SynchronousOffset = luExtension->SynchronousOffset;
+ scsiSynchronous.SynchronousPeriod = luExtension->SynchronousPeriod;
+
+ SCSI_WRITE(
+ DeviceExtension->Adapter,
+ Synchronous,
+ *((PUCHAR) &scsiSynchronous)
+ );
+
+ }
+
+ //
+ // Set the destination id register; this register will allow the target to
+ // reselect later without an interrupt, and tell the SCSI protocol chip the
+ // direction of the data transfer.
+ //
+
+ *((PUCHAR) &destinationId) = 0;
+ destinationId.TargetId = TargetId;
+ destinationId.DataDirection = srb->SrbFlags & SRB_FLAGS_DATA_OUT ? 0 : 1;
+
+ SCSI_WRITE( DeviceExtension->Adapter, DestinationId, *((PUCHAR) &destinationId));
+
+ //
+ // Its not clear what state the target is in so just handle
+ // the rest of this request one phase at a time.
+ // Clear the saved comand phase.
+ //
+
+ luExtension->SavedCommandPhase = 0;
+
+ //
+ // Accept the IDENTIFY message and wait for the next interrupt.
+ // Note that WdProcessReselect set the synchronous transfer
+ // registers if the DMA was set up.
+ //
+
+ WdAcceptMessage(DeviceExtension, FALSE, FALSE);
+
+
+ return(TRUE);
+
+}
+
+BOOLEAN
+WdResetScsiBus(
+ IN PVOID ServiceContext,
+ IN ULONG PathId
+ )
+/*++
+
+Routine Description:
+
+ This function resets the SCSI bus and calls the reset cleanup function.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the specific device extension.
+
+ PathId - Supplies the path id of the bus to be reset.
+
+Return Value:
+
+ TRUE - Indicating that the reset has completed.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+
+ WdPrint((0, "WdResetScsiBus: Resetting the SCSI bus.\n"));
+
+ //
+ // Tell the chip to disconnect from the bus.
+ //
+
+ WdIssueCommand(deviceExtension, DISCONNECT_FROM_BUS, -1, 0);
+
+ //
+ // Reset the SCSI bus.
+ //
+
+ SCSI_RESET_BUS(deviceExtension);
+
+ //
+ // Reset the adapter.
+ //
+
+ WdInitializeAdapter(deviceExtension);
+
+ WdCleanupAfterReset(deviceExtension, FALSE);
+
+ return TRUE;
+}
+
+VOID
+WdResetScsiBusInternal(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG PathId
+ )
+/*++
+
+Routine Description:
+
+ This function resets the SCSI bus, notifies the port driver of the reset
+ and calls the reset cleanup function.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the specific device extension.
+
+ PathId - Supplies the path id of the bus to be reset.
+
+Return Value:
+
+ None
+
+--*/
+{
+ ScsiPortNotification(
+ ResetDetected,
+ DeviceExtension,
+ NULL
+ );
+
+ WdResetScsiBus(DeviceExtension, 0);
+}
+
+
+VOID
+WdSelectTarget(
+ IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the hardware to select a target. If a valid message
+ is in the message buffer, it will be sent to the target. If the request
+ includes a SCSI command descriptor block, it will also be passed to the
+ target.
+
+Arguments:
+
+ DeviceExtension - Supplies the device extension for this HBA adapter.
+
+ LuExtension - Supplies the logical unit extension for the target being
+ selected.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ AUXILIARY_STATUS auxiliaryStatus;
+ PSCSI_REQUEST_BLOCK srb;
+ TARGET_LUN targetLun;
+ DESTINATION_ID destinationId;
+ SCSI_SYNCHRONOUS scsiSynchronous;
+ ULONG i;
+
+ srb = DeviceExtension->NextSrbRequest;
+ DeviceExtension->ActiveLogicalUnit = LuExtension;
+
+#if DBG
+ if (WdDebug) {
+ WdPrint((0, "WdSelectTarget: Attempting target select.\n"));
+ }
+#endif
+ /* Powerfail Start */
+
+ //
+ // Set up the SCSI protocol chip to select the target, transfer the
+ // IDENTIFY message and the CDB. This can be done by following steps:
+ //
+ // setting the destination register,
+ // filling the registers with the IDENTIFY message and the CDB
+ // setting the command register
+ //
+ // Read the auxiliary status.
+ //
+
+ *((PUCHAR) &auxiliaryStatus) = SCSI_READ_AUX(DeviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ //
+ // If the SCSI protocol chip is interrupting or busy, just return.
+ //
+
+ if (auxiliaryStatus.Interrupt || auxiliaryStatus.ChipBusy) {
+
+ return;
+
+ }
+
+ //
+ // Ensure that the data transfer count is zero if no transfer is expected.
+ //
+
+ if (!(srb->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT))) {
+
+ //
+ // Clear the srb DataTransferLength and the SavedDataLength so chip
+ // won't transfer data if requested.
+ //
+
+ srb->DataTransferLength = 0;
+ LuExtension->SavedDataLength = 0;
+ }
+
+ //
+ // Set the destination ID, data direction and the target logical unit
+ // number. Note that setting the data direction flag indicates the
+ // transfer is in. The data direction flags will only be set if the
+ // transfer is really in.
+ //
+
+ *((PUCHAR) &destinationId) = 0;
+ destinationId.TargetId = srb->TargetId;
+ destinationId.DataDirection = srb->SrbFlags & SRB_FLAGS_DATA_OUT ? 0 : 1;
+ SCSI_WRITE(
+ DeviceExtension->Adapter,
+ DestinationId,
+ *((PUCHAR) &destinationId)
+ );
+
+ //
+ // Set the synchronous data transfer parameter registers in case a
+ // data transfer is done. These must be set before a data transfer
+ // is started.
+ //
+
+ *((PUCHAR) &scsiSynchronous) = 0;
+ scsiSynchronous.SynchronousOffset = LuExtension->SynchronousOffset;
+ scsiSynchronous.SynchronousPeriod = LuExtension->SynchronousPeriod;
+
+ SCSI_WRITE(
+ DeviceExtension->Adapter,
+ Synchronous,
+ *((PUCHAR) &scsiSynchronous)
+ );
+
+ //
+ // Determine if this srb has a Cdb with it and whether the message is
+ // such that the message and the Cdb can be loaded into the registers;
+ // otherwise, just select the target with ATN.
+ //
+
+ if ((srb->Function == SRB_FUNCTION_EXECUTE_SCSI) &&
+ (DeviceExtension->MessageCount == 1)) {
+
+ //
+ // Update the message-sent count to indicate that the IDENTIFY
+ // message has been sent.
+ //
+
+ DeviceExtension->MessageSent++;
+
+ //
+ // Initialize the target logical unit register.
+ //
+
+ *((PUCHAR) &targetLun) = 0;
+ targetLun.LogicalUnitNumber = srb->Lun;
+
+ SCSI_WRITE( DeviceExtension->Adapter,
+ TargetLun,
+ *((PUCHAR) &targetLun)
+ );
+
+ //
+ // Copy the CDB into the registers.
+ //
+
+ for (i = 0; i < srb->CdbLength; i++) {
+ SCSI_WRITE( DeviceExtension->Adapter,
+ Cdb[i],
+ srb->Cdb[i]
+ );
+ }
+
+ SCSI_WRITE( DeviceExtension->Adapter,
+ CdbSize,
+ srb->CdbLength
+ );
+
+ //
+ // Initialize the CommandPhase in the logical unit.
+ //
+
+ LuExtension->SavedCommandPhase = 0;
+
+ //
+ // Since the chip may automatically start a data transfer after the
+ // selection, restore the data pointers.
+ //
+
+ DeviceExtension->ActiveDataPointer = LuExtension->SavedDataPointer;
+ DeviceExtension->ActiveDataLength = LuExtension->SavedDataLength;
+
+ //
+ // Set the adapter state for subsequent processing.
+ //
+
+ DeviceExtension->AdapterState = SelectAndTransfer;
+
+ //
+ // Issue select-with-ATN-and-transfer command: the transfer
+ // count is set to zero in order to cause an interrupt to occur
+ // if/when the target requests a data transfer phase.
+ //
+
+ WdIssueCommand(
+ DeviceExtension, // Device Extension.
+ SELECT_ATN_AND_TRANSFER, // Command to issue.
+ 0, // New transfer count.
+ 0 // New CommandPhase.
+ );
+
+ } else {
+
+ //
+ // Set the adapter state for subsequent processing.
+ //
+
+ DeviceExtension->AdapterState = Select;
+
+ //
+ // Select the target with ATN
+ //
+
+ WdIssueCommand(DeviceExtension, SELECT_WITH_ATN, -1, 0);
+
+ }
+
+ /* Powerfail release */
+
+ //
+ // Indicate that a message out can be or is being sent.
+ // Start the phase timer.
+ //
+
+ DeviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+ DeviceExtension->InterruptCount = 0;
+
+}
+
+
+VOID
+WdSendMessage(
+ PSCSI_REQUEST_BLOCK Srb,
+ PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to send the indicated message to the target
+ controller. There are three classes of messages:
+ Those which terminate a specific request and end in bus free.
+ Those which apply to a specific request and then proceed.
+ Those which end in bus free.
+
+ For those messages that apply to a specific request, check to see that
+ the request is currently being processed and an IDENTIFY message prefixed
+ the message.
+
+ It is possible that the destination logical unit is the active logical unit;
+ however, it would difficult to jump in and send the requested message, so
+ just wait for the bus to become free.
+
+ In the case where the target is not currently active, then set up the SCSI
+ protocol chip to select the target controller and send the message.
+
+Arguments:
+
+ Srb - Supplies the request to be started.
+
+ DeviceExtension - Supplies the extended device extension for this SCSI bus.
+
+ LuExtension - Supplies the logical unit extension for this request.
+
+Notes:
+
+ This routine must be synchronized with the interrupt routine.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PSCSI_REQUEST_BLOCK linkedSrb;
+ BOOLEAN impliesDisconnect;
+ UCHAR message;
+
+ impliesDisconnect = FALSE;
+
+ //
+ // Decode the type of message.
+ //
+
+ switch (Srb->Function) {
+
+ // case SCSIMESS_ABORT_WITH_TAG:
+ // case SCSIMESS_TERMINATE_IO_PROCESS:
+
+ /* TODO: Handle the previous two cases. */
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ //
+ // Verify that the request is being processed by the logical unit.
+ //
+
+ linkedSrb = ScsiPortGetNextLink( Srb );
+ if (linkedSrb != LuExtension->ActiveLuRequest) {
+
+ //
+ // The specified request is not here. Complete the request
+ // without error.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification(
+ NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ return;
+
+ }
+
+ message = SCSIMESS_ABORT;
+ impliesDisconnect = TRUE;
+ break;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ //
+ // Because of the way the chip works it is easiest to send an IDENTIFY
+ // message along with the BUS DEVICE RESET message. That is because
+ // there is no way to select a target with ATN and send one message
+ // byte. This IDENTIFY message is not necessary for the SCSI protocol,
+ // but it is legal and should not cause any problem.
+ //
+
+ message = SCSIMESS_BUS_DEVICE_RESET;
+ impliesDisconnect = TRUE;
+ break;
+
+/* case SCSIMESS_RELEASE_RECOVERY:
+ case SCSIMESS_CLEAR_QUEUE:
+
+ //
+ // These messages require an IDENTIFY message and imply a disconnect.
+ //
+
+ impliesDisconnect = TRUE;
+ break;
+ */
+ default:
+
+ //
+ // This is an unsupported message request. Fail the request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ ScsiPortNotification(
+ RequestComplete,
+ DeviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification(
+ NextRequest,
+ DeviceExtension,
+ NULL
+ );
+
+ return;
+
+ }
+
+ //
+ // Save away the parameters in case nothing can be done now.
+ //
+
+ DeviceExtension->NextSrbRequest = Srb;
+ DeviceExtension->AdapterFlags |= PD_PENDING_START_IO;
+ LuExtension->ActiveSendRequest = Srb;
+
+ //
+ // Check to see if the bus is free. If it is not, then return. Since
+ // the request parameters have been saved, indicate that the request has
+ // been accepted. The request will be processed when the bus becomes free.
+ //
+
+ if (DeviceExtension->AdapterState != BusFree) {
+ return;
+ }
+
+ //
+ // Create the identify command and copy the message to the buffer.
+ //
+
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_IDENTIFY_WITH_DISCON |
+ Srb->Lun;
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+
+ DeviceExtension->MessageBuffer[DeviceExtension->MessageCount++] = message;
+
+ //
+ // Attempt to select the target and update the adapter flags.
+ //
+
+ WdSelectTarget( DeviceExtension, LuExtension );
+
+ DeviceExtension->AdapterFlags |= impliesDisconnect ?
+ PD_DISCONNECT_EXPECTED | PD_SEND_MESSAGE_REQUEST
+ : PD_SEND_MESSAGE_REQUEST;
+
+}
+
+VOID
+WdSetupDma(
+ PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This function performs all of the operations necessary set up the SCSI
+ protocol card and chip for a data transfer. This function should be called
+ after the last access to chip. In particular, the transfer count is set and
+ the transfer is mapped. If the active transfer count is zero, then the
+ DMA is not started.
+
+Arguments:
+
+ ServiceContext - Supplies the extended device extension for this SCSI bus.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+
+ //
+ // If the data tranfer is no longer expected then ignore the notification.
+ //
+
+ if (!(deviceExtension->AdapterFlags & PD_PENDING_DATA_TRANSFER)) {
+
+ return;
+
+ }
+
+ luExtension = deviceExtension->ActiveLogicalUnit;
+ srb = luExtension->ActiveLuRequest;
+
+ //
+ // Setup the SCSI host adapter card.
+ //
+
+ CARD_DMA_INITIATE( deviceExtension, srb->SrbFlags & SRB_FLAGS_DATA_IN );
+
+ //
+ // Tell the chip to transfer the data.
+ //
+
+ WdIssueCommand(
+ deviceExtension, // Device Extension.
+ deviceExtension->DmaCommand, // Command to issue.
+ deviceExtension->ActiveDataLength, // New transfer count.
+ deviceExtension->DmaPhase // New CommandPhase.
+ );
+
+ deviceExtension->AdapterFlags &= ~PD_PENDING_DATA_TRANSFER;
+
+}
+
+
+VOID
+WdStartExecution(
+ PSCSI_REQUEST_BLOCK Srb,
+ PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure sets up the chip to select the target and notify it that
+ a request is available. For the WD chip, the chip is set up to select,
+ send the IDENTIFY message and send the command data block. A check is
+ made to determine if synchronous negotiation is necessary.
+
+Arguments:
+
+ Srb - Supplies the request to be started.
+
+ DeviceExtension - Supplies the extended device extension for this SCSI bus.
+
+ LuExtension - Supplies the logical unit extension for this request.
+
+Notes:
+
+ This routine must be synchronized with the interrupt routine.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PSCSI_EXTENDED_MESSAGE extendedMessage;
+
+ //
+ // Save away the parameters in case nothing can be done now.
+ //
+
+ LuExtension->ActiveLuRequest = Srb;
+ LuExtension->SavedDataPointer = (ULONG) Srb->DataBuffer;
+ LuExtension->SavedDataLength = Srb->DataTransferLength;
+ LuExtension->MaximumTransferLength = 0;
+ DeviceExtension->NextSrbRequest = Srb;
+ DeviceExtension->AdapterFlags |= PD_PENDING_START_IO;
+
+ //
+ // Check to see if the bus is free. If it is not, then return. Since
+ // the request parameters have been saved, indicate that the request has
+ // been accepted. The request will be processed when the bus becomes free.
+ //
+
+ if (DeviceExtension->AdapterState != BusFree) {
+ return;
+ }
+
+ //
+ // Create the identify command.
+ //
+
+ DeviceExtension->MessageBuffer[0] = SCSIMESS_IDENTIFY_WITH_DISCON | Srb->Lun;
+ DeviceExtension->MessageCount = 1;
+ DeviceExtension->MessageSent = 0;
+ DeviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
+
+ //
+ // Set the active data length and pointer in the specific device
+ // extension. These are used to program the DMA.
+ //
+
+ DeviceExtension->ActiveDataPointer = LuExtension->SavedDataPointer;
+ DeviceExtension->ActiveDataLength = LuExtension->SavedDataLength;
+
+ //
+ // Check to see if synchronous negotiation is necessary.
+ //
+
+ if (!(LuExtension->LuFlags &
+ (PD_SYNCHRONOUS_NEGOTIATION_DONE | PD_DO_NOT_NEGOTIATE)) &&
+ !(Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)) {
+
+ //
+ // Initialize the synchronous transfer register values to an
+ // asynchronous transfer, which is what will be used if anything
+ // goes wrong with the negotiation.
+ //
+
+ LuExtension->SynchronousOffset = ASYNCHRONOUS_OFFSET;
+ LuExtension->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
+
+ //
+ // Create the synchronous data transfer request message.
+ // The format of the message is:
+ //
+ // EXTENDED_MESSAGE op-code
+ // Length of message
+ // Synchronous transfer data request op-code
+ // Our Transfer period
+ // Our REQ/ACK offset
+ //
+ // The message is placed after the IDENTIFY message.
+ //
+
+ extendedMessage = (PSCSI_EXTENDED_MESSAGE)
+ &DeviceExtension->MessageBuffer[DeviceExtension->MessageCount];
+ DeviceExtension->MessageCount += 2 + SCSIMESS_SYNCH_DATA_LENGTH;
+
+ extendedMessage->InitialMessageCode = SCSIMESS_EXTENDED_MESSAGE;
+ extendedMessage->MessageLength = SCSIMESS_SYNCH_DATA_LENGTH;
+ extendedMessage->MessageType = SCSIMESS_SYNCHRONOUS_DATA_REQ;
+ extendedMessage->ExtendedArguments.Synchronous.TransferPeriod = SYNCHRONOUS_PERIOD;
+ extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset = SYNCHRONOUS_OFFSET;
+
+ //
+ // Attempt to select the target and update the adapter flags.
+ //
+
+ WdSelectTarget( DeviceExtension, LuExtension );
+
+ //
+ // Many controllers reject the first byte of a synchronous
+ // negotiation message. Since this is a multibyte message the
+ // ATN signal remains set after the first byte is sent. Some
+ // controllers remember this attempt to do a message-out
+ // later. Setting the PD_POSSIBLE_EXTRA_MESSAGE_OUT flag allows
+ // this extra message transfer to occur without error.
+ //
+
+ DeviceExtension->AdapterFlags |= PD_POSSIBLE_EXTRA_MESSAGE_OUT |
+ PD_SYNCHRONOUS_TRANSFER_SENT;
+
+ return;
+ }
+
+ WdSelectTarget( DeviceExtension, LuExtension );
+
+}
+
+BOOLEAN
+WdStartIo(
+ IN PVOID ServiceContext,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+/*++
+
+Routine Description:
+
+ This function is used by the OS dependent port driver to pass requests to
+ the HBA-dependent driver. This function begins the execution of the request.
+ Requests to reset the SCSI bus are handled immediately. Requests to send
+ a message or start a SCSI command are handled when the bus is free.
+
+Arguments:
+
+ ServiceContext - Supplies the device extension for the SCSI bus adapter.
+
+ Srb - Supplies the SCSI request block to be started.
+
+Return Value:
+
+ TRUE - If the request can be accepted at this time.
+
+ FALSE - If the request must be submitted later.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
+
+ switch (Srb->Function) {
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ WdPrint((0, "WdStartIo: execute scsi\n" ));
+
+ //
+ // Determine the logical unit that this request is for.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+ WdStartExecution(
+ Srb,
+ deviceExtension,
+ luExtension
+ );
+
+ return(TRUE);
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+ case SRB_FUNCTION_RESET_DEVICE:
+ case SRB_FUNCTION_TERMINATE_IO:
+
+ WdPrint((0, "WdStartIo: abort/reset/terminate\n" ));
+
+ //
+ //
+ // Determine the logical unit that this request is for.
+ //
+
+ luExtension = ScsiPortGetLogicalUnit(
+ deviceExtension,
+ Srb->PathId,
+ Srb->TargetId,
+ Srb->Lun
+ );
+ WdSendMessage(
+ Srb,
+ deviceExtension,
+ luExtension
+ );
+
+ return(TRUE);
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ WdPrint((0, "WdStartIo: reset bus\n" ));
+
+ //
+ // There is no logical unit so just reset the bus.
+ //
+
+ WdResetScsiBus( deviceExtension, 0 );
+ return(TRUE);
+
+ default:
+
+ WdPrint((0, "WdStartIo: default case -- bad function\n" ));
+
+ //
+ // Unknown function code in the request.
+ // Complete the request with an error and ask for the next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
+ ScsiPortNotification(
+ RequestComplete,
+ deviceExtension,
+ Srb
+ );
+
+ ScsiPortNotification(
+ NextRequest,
+ deviceExtension,
+ NULL
+ );
+
+ return(TRUE);
+ }
+}
+
+
+
+BOOLEAN
+WdTransferInformation(
+ PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
+ PUCHAR BufferPointer,
+ ULONG Count,
+ BOOLEAN TransferToChip
+ )
+/*++
+
+Routine Description:
+
+ This fucntion transfers data between memory and the SCSI protocol chip's
+ data registers. It is only used for non-data transfers. This operation
+ is done synchronously; however, since the chip has a 12-byte FIFO and this
+ function is used for small transfers, it will execute quickly.
+
+Arguments:
+
+ DeviceExtension - Supplies the device Extension for the SCSI bus adapter.
+
+ BufferPointer - Supplies a pointer to the data to be copied.
+
+ Count - Supplies the number of bytes to be transferred.
+
+ TransferToChip - Indicates the direction of the transfer.
+
+Return Value:
+
+ Returns the number of bytes actually transferred.
+
+--*/
+
+{
+ ULONG i;
+ ULONG j;
+ AUXILIARY_STATUS scsiStatus;
+
+ //
+ // Issue the transfer information command to the SCSI protocol chip.
+ //
+
+ WdIssueCommand(DeviceExtension, TRANSFER_INFORMATION, Count, 0);
+
+ for (i = 0; i < Count; i++ ) {
+
+ //
+ // Determine if the data buffer is ready.
+ //
+
+ *((PUCHAR) &scsiStatus) = SCSI_READ_AUX(
+ DeviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ j = 0;
+
+ while (!scsiStatus.DataBufferReady && j < DATA_BUS_READY_TIME) {
+
+ if (scsiStatus.Interrupt) {
+
+ //
+ // The SCSI protocol chip is interrupting so no more data
+ // will be transferred.
+ //
+
+ return(FALSE);
+ }
+
+ //
+ // Wait for the data buffer to become free.
+ //
+
+ ScsiPortStallExecution( 1 );
+ j++;
+
+ *((PUCHAR) &scsiStatus) = SCSI_READ_AUX(
+ DeviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ }
+
+ if (!scsiStatus.DataBufferReady) {
+
+ //
+ // The data buffer did not become free in time. Something is hung.
+ // Reset the controller and the bus, finally return FALSE.
+ //
+
+ WdLogError(DeviceExtension, SP_BUS_TIME_OUT, 21);
+
+ WdPrint((0,
+ "WdTransferInformation: The data buffer ready flag timed out. Transfer count = %lu.\n",
+ Count
+ ));
+
+ WdDumpState(DeviceExtension);
+ WdResetScsiBusInternal(DeviceExtension, 0);
+
+ return(FALSE);
+
+
+ }
+
+#if DBG
+ if (WdDebug && j > 1) {
+ WdPrint((0, "WdTransferInformation Data wait time: %d, Status: 0x%.2X\n",
+ j, DeviceExtension->AdapterInterrupt));
+ }
+#endif
+
+ //
+ // Move the data to the data register.
+ //
+
+ if (TransferToChip) {
+
+ SCSI_WRITE(DeviceExtension->Adapter, Data, *BufferPointer);
+ BufferPointer++;
+
+ } else {
+
+ *BufferPointer = SCSI_READ(DeviceExtension->Adapter, Data);
+ BufferPointer++;
+
+ }
+
+ }
+
+ return(TRUE);
+}
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Driver Object is passed to ScsiPortInitialize()
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ PUCHAR BufferPointer;
+ ULONG i;
+
+ WdPrint((1,"\nSCSI WD33C93A Miniport Driver\n"));
+
+ //
+ // Initialize the buffer to zero.
+ //
+
+ BufferPointer = (PUCHAR) &hwInitializationData;
+ for (i = 0; i < sizeof(hwInitializationData); i++) {
+ *BufferPointer++ = 0;
+ }
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ hwInitializationData.HwInitialize = WdInitializeAdapter;
+ hwInitializationData.HwStartIo = WdStartIo;
+ hwInitializationData.HwInterrupt = WdInterruptServiceRoutine;
+ hwInitializationData.HwFindAdapter = WdFindAdapter;
+ hwInitializationData.HwResetBus = WdResetScsiBus;
+ hwInitializationData.HwDmaStarted = WdSetupDma;
+ hwInitializationData.AdapterInterfaceType = SCSI_BUS_INTERFACE;
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.DeviceExtensionSize = sizeof(SPECIFIC_DEVICE_EXTENSION);
+ hwInitializationData.MapBuffers = TRUE;
+ hwInitializationData.SpecificLuExtensionSize =
+ sizeof(SPECIFIC_LOGICAL_UNIT_EXTENSION);
+
+ return ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, NULL);
+
+} // end DriverEntry()
+
+ULONG
+WdFindAdapter(
+ IN PVOID ServiceContext,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+/*++
+
+Routine Description:
+
+ This function fills in the configuration information structure and maps
+ the SCSI protocol chip for access. This routine is temporary until
+ the configuration manager supplies similar information.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension.
+
+ Context - Unused.
+
+ BusInformation - Unused.
+
+ ArgumentString - Unused.
+
+ ConfigInfo - Pointer to the configuration information structure to be
+ filled in.
+
+ Again - Returns back a request to call this function again.
+
+Return Value:
+
+ Returns a status value for the initialization.
+
+--*/
+
+{
+ PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
+ AUXILIARY_STATUS scsiStatus;
+ ULONG physicalBase;
+ SCSI_PHYSICAL_ADDRESS base;
+ UCHAR dataByte;
+ BOOLEAN found = FALSE;
+ BOOLEAN baseSupplied;
+
+ *Again = FALSE;
+
+ //
+ // Parse any supplied argument string.
+ //
+
+ if (ArgumentString != NULL) {
+
+ //
+ // Look for a base parameter.
+ //
+
+ physicalBase = WdParseArgumentString(ArgumentString, "BASE");
+
+ if (physicalBase != 0) {
+
+ base = ScsiPortConvertUlongToPhysicalAddress(physicalBase);
+ (*ConfigInfo->AccessRanges)[0].RangeStart = base;
+ }
+
+ //
+ // Look for interrupt level.
+ //
+
+ physicalBase = WdParseArgumentString(ArgumentString, "IRQ");
+
+ if (physicalBase != 0) {
+
+ ConfigInfo->BusInterruptVector = SCSI_VECTOR;
+ ConfigInfo->BusInterruptLevel = physicalBase;
+
+ }
+
+ //
+ // Look for interrupt level.
+ //
+
+ physicalBase = WdParseArgumentString(ArgumentString, "DMA");
+
+ if (physicalBase != 0) {
+
+ ConfigInfo->DmaChannel = physicalBase;
+
+ }
+
+
+ }
+
+ physicalBase = ScsiPortConvertPhysicalAddressToUlong(
+ (*ConfigInfo->AccessRanges)[0].RangeStart);
+ if (physicalBase != 0) {
+
+ baseSupplied = TRUE;
+
+ } else {
+
+ baseSupplied = FALSE;
+ physicalBase = SCSI_PHYSICAL_BASE;
+ }
+
+ //
+ // Get the system physical address for this card. The card uses I/O space.
+ //
+
+ base = ScsiPortConvertUlongToPhysicalAddress(physicalBase);
+ deviceExtension->Adapter = ScsiPortGetDeviceBase(
+ deviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ base,
+ sizeof(CARD_REGISTERS), // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+ if (deviceExtension->Adapter == NULL) {
+ WdPrint((0, "\nScsiPortInitialize: Failed to map SCSI device registers into system space.\n"));
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // Determine if the card is really installed in the system. First read the
+ // status register.
+ //
+
+ *((PUCHAR) &scsiStatus) = SCSI_READ_AUX(
+ deviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ //
+ // Make sure the reserved bits are zero.
+ //
+
+ if (scsiStatus.Reserved != 0) {
+
+ //
+ // The card is not here so clean up.
+ //
+
+ ScsiPortFreeDeviceBase(
+ deviceExtension,
+ deviceExtension->Adapter
+ );
+
+ } else {
+
+ //
+ // Write and read the command phase register. This is not a good thing to
+ // do for card detection, but there does not appear to be any other way.
+ //
+
+ dataByte = PHASE_STATUS_STARTED;
+ SCSI_WRITE(deviceExtension->Adapter, CommandPhase, dataByte);
+ dataByte = SCSI_READ(deviceExtension->Adapter, CommandPhase);
+ if (dataByte != PHASE_STATUS_STARTED) {
+
+ //
+ // This is not our card so clean up.
+ //
+
+ ScsiPortFreeDeviceBase(
+ deviceExtension,
+ deviceExtension->Adapter
+ );
+
+ } else {
+
+ found = TRUE;
+
+ }
+ }
+
+
+ if (!found && !baseSupplied) {
+
+#ifndef SCSI_SECOND_PHYSICAL_BASE
+
+ return(SP_RETURN_NOT_FOUND);
+
+#else
+ //
+ // Try an alternet address.
+ // Get the system physical address for this card. The card uses I/O space.
+ //
+
+ base = ScsiPortConvertUlongToPhysicalAddress(SCSI_SECOND_PHYSICAL_BASE);
+ deviceExtension->Adapter = ScsiPortGetDeviceBase(
+ deviceExtension, // HwDeviceExtension
+ ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
+ ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
+ base,
+ sizeof(CARD_REGISTERS), // NumberOfBytes
+ TRUE // InIoSpace
+ );
+
+ if (deviceExtension->Adapter == NULL) {
+ WdPrint((0, "\nScsiPortInitialize: Failed to map SCSI device registers into system space.\n"));
+ return(SP_RETURN_ERROR);
+ }
+
+ //
+ // Determine if the card is really installed in the system. First read the
+ // status register.
+ //
+
+ *((PUCHAR) &scsiStatus) = SCSI_READ_AUX(
+ deviceExtension->Adapter,
+ AuxiliaryStatus
+ );
+
+ //
+ // Make sure the reserved bits are zero.
+ //
+
+ if (scsiStatus.Reserved != 0) {
+
+ //
+ // The card is not here so clean up.
+ //
+
+ ScsiPortFreeDeviceBase(
+ deviceExtension,
+ deviceExtension->Adapter
+ );
+
+ return(SP_RETURN_NOT_FOUND);
+
+ }
+
+ //
+ // Write and read the command phase register. This is not a good thing to
+ // do for card detection, but there does not appear to be any other way.
+ //
+
+ dataByte = PHASE_STATUS_STARTED;
+ SCSI_WRITE(deviceExtension->Adapter, CommandPhase, dataByte);
+ dataByte = SCSI_READ(deviceExtension->Adapter, CommandPhase);
+ if (dataByte != PHASE_STATUS_STARTED) {
+
+ //
+ // This is not our card so clean up.
+ //
+
+ ScsiPortFreeDeviceBase(
+ deviceExtension,
+ deviceExtension->Adapter
+ );
+
+ return(SP_RETURN_NOT_FOUND);
+
+ }
+
+ found = TRUE;
+#endif
+ }
+
+ if (!found) {
+ return(SP_RETURN_NOT_FOUND);
+ }
+
+ //
+ // Set the defaults for any uninitialized values.
+ //
+
+ if (ConfigInfo->DmaChannel == SP_UNINITIALIZED_VALUE) {
+
+ ConfigInfo->DmaChannel = CARD_DMA_REQUEST;
+ }
+
+ if (ConfigInfo->BusInterruptLevel == 0 &&
+ ConfigInfo->BusInterruptVector == 0) {
+
+ ConfigInfo->BusInterruptLevel = SCSI_LEVEL;
+ ConfigInfo->BusInterruptVector = SCSI_VECTOR;
+
+ }
+
+ //
+ // Get the adapter object for this card.
+ //
+
+ ConfigInfo->MaximumTransferLength = 0x1000000;
+ ConfigInfo->DmaWidth = CARD_DMA_WIDTH;
+ ConfigInfo->DmaSpeed = CARD_DMA_SPEED;
+ ConfigInfo->NumberOfBuses = 1;
+
+ //
+ // Translate the DMA Channel values.
+ //
+
+ switch (ConfigInfo->DmaChannel) {
+ case 5:
+ deviceExtension->DmaCode = 1;
+ break;
+
+ case 6:
+ deviceExtension->DmaCode = 2;
+ break;
+
+ case 7:
+ deviceExtension->DmaCode = 3;
+ break;
+
+ default:
+ return(SP_RETURN_BAD_CONFIG);
+ }
+
+ //
+ // Translate interrupt level values.
+ //
+
+ switch (ConfigInfo->BusInterruptLevel) {
+ case 3:
+ deviceExtension->IrqCode = 1;
+ break;
+
+ case 4:
+ deviceExtension->IrqCode = 2;
+ break;
+
+ case 5:
+ deviceExtension->IrqCode = 3;
+ break;
+
+ case 10:
+ deviceExtension->IrqCode = 4;
+ break;
+
+ case 11:
+ deviceExtension->IrqCode = 5;
+ break;
+
+ case 12:
+ deviceExtension->IrqCode = 6;
+ break;
+
+ case 15:
+ deviceExtension->IrqCode = 7;
+ break;
+
+ default:
+ return(SP_RETURN_BAD_CONFIG);
+
+ }
+
+ //
+ // Get the SCSI bus Id from the configuration information if there
+ // is any.
+ //
+
+ if (ConfigInfo->InitiatorBusId[0] == (CCHAR) SP_UNINITIALIZED_VALUE) {
+ ConfigInfo->InitiatorBusId[0] = INITIATOR_BUS_ID;
+ deviceExtension->InitiatorBusId = INITIATOR_BUS_ID;
+ } else {
+ deviceExtension->InitiatorBusId = ConfigInfo->InitiatorBusId[0];
+ }
+
+ //
+ // Fill in the access array information.
+ //
+
+ (*ConfigInfo->AccessRanges)[0].RangeStart = base;
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(CARD_REGISTERS);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ return(SP_RETURN_FOUND);
+}
+
+ULONG
+WdParseArgumentString(
+ IN PCHAR String,
+ IN PCHAR KeyWord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will parse the string for a match on the keyword, then
+ calculate the value for the keyword and return it to the caller.
+
+Arguments:
+
+ String - The ASCII string to parse.
+ KeyWord - The keyword for the value desired.
+
+Return Values:
+
+ Zero if value not found
+ Value converted from ASCII to binary.
+
+--*/
+
+{
+ PCHAR cptr;
+ PCHAR kptr;
+ ULONG value;
+ ULONG stringLength = 0;
+ ULONG keyWordLength = 0;
+ ULONG index;
+
+ //
+ // Calculate the string length and lower case all characters.
+ //
+ cptr = String;
+ while (*cptr) {
+
+ if (*cptr >= 'A' && *cptr <= 'Z') {
+ *cptr = *cptr + ('a' - 'A');
+ }
+ cptr++;
+ stringLength++;
+ }
+
+ //
+ // Calculate the keyword length and lower case all characters.
+ //
+ cptr = KeyWord;
+ while (*cptr) {
+
+ if (*cptr >= 'A' && *cptr <= 'Z') {
+ *cptr = *cptr + ('a' - 'A');
+ }
+ cptr++;
+ keyWordLength++;
+ }
+
+ if (keyWordLength > stringLength) {
+
+ //
+ // Can't possibly have a match.
+ //
+ return 0;
+ }
+
+ //
+ // Now setup and start the compare.
+ //
+ cptr = String;
+
+ContinueSearch:
+ //
+ // The input string may start with white space. Skip it.
+ //
+ while (*cptr == ' ' || *cptr == '\t') {
+ cptr++;
+ }
+
+ if (*cptr == '\0') {
+
+ //
+ // end of string.
+ //
+ return 0;
+ }
+
+ kptr = KeyWord;
+ while (*cptr++ == *kptr++) {
+
+ if (*(cptr - 1) == '\0') {
+
+ //
+ // end of string
+ //
+ return 0;
+ }
+ }
+
+ if (*(kptr - 1) == '\0') {
+
+ //
+ // May have a match backup and check for blank or equals.
+ //
+
+ cptr--;
+ while (*cptr == ' ' || *cptr == '\t') {
+ cptr++;
+ }
+
+ //
+ // Found a match. Make sure there is an equals.
+ //
+ if (*cptr != '=') {
+
+ //
+ // Not a match so move to the next semicolon.
+ //
+ while (*cptr) {
+ if (*cptr++ == ';') {
+ goto ContinueSearch;
+ }
+ }
+ return 0;
+ }
+
+ //
+ // Skip the equals sign.
+ //
+ cptr++;
+
+ //
+ // Skip white space.
+ //
+ while ((*cptr == ' ') || (*cptr == '\t')) {
+ cptr++;
+ }
+
+ if (*cptr == '\0') {
+
+ //
+ // Early end of string, return not found
+ //
+ return 0;
+ }
+
+ if (*cptr == ';') {
+
+ //
+ // This isn't it either.
+ //
+ cptr++;
+ goto ContinueSearch;
+ }
+
+ value = 0;
+ if ((*cptr == '0') && (*(cptr + 1) == 'x')) {
+
+ //
+ // Value is in Hex. Skip the "0x"
+ //
+ cptr += 2;
+ for (index = 0; *(cptr + index); index++) {
+
+ if (*(cptr + index) == ' ' ||
+ *(cptr + index) == '\t' ||
+ *(cptr + index) == ';') {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
+ value = (16 * value) + (*(cptr + index) - '0');
+ } else {
+ if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
+ value = (16 * value) + (*(cptr + index) - 'a' + 10);
+ } else {
+
+ //
+ // Syntax error, return not found.
+ //
+ return 0;
+ }
+ }
+ }
+ } else {
+
+ //
+ // Value is in Decimal.
+ //
+ for (index = 0; *(cptr + index); index++) {
+
+ if (*(cptr + index) == ' ' ||
+ *(cptr + index) == '\t' ||
+ *(cptr + index) == ';') {
+ break;
+ }
+
+ if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
+ value = (10 * value) + (*(cptr + index) - '0');
+ } else {
+
+ //
+ // Syntax error return not found.
+ //
+ return 0;
+ }
+ }
+ }
+
+ return value;
+ } else {
+
+ //
+ // Not a match check for ';' to continue search.
+ //
+ while (*cptr) {
+ if (*cptr++ == ';') {
+ goto ContinueSearch;
+ }
+ }
+
+ return 0;
+ }
+}
+
diff --git a/private/ntos/miniport/wd33c93/wd33c93.h b/private/ntos/miniport/wd33c93/wd33c93.h
new file mode 100644
index 000000000..0fb684bab
--- /dev/null
+++ b/private/ntos/miniport/wd33c93/wd33c93.h
@@ -0,0 +1,305 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ wd33c93.h
+
+Abstract:
+
+ The module defines the structures, and defines for the Western Digital
+ WD33C93 host bus adapter chip.
+
+Author:
+
+ Jeff Havens (jhavens) 10-June-1991
+
+Revision History:
+
+
+--*/
+
+#ifndef _WD33C93_
+#define _WD33C93_
+
+//
+// SCSI host bus adapter Western Digital WD33C93 chip definitions.
+//
+
+//
+// Define the register type
+//
+typedef struct _SCSI_REGISTER{
+ UCHAR Value;
+}SCSI_REGISTER, *PSCSI_REGISTER;
+
+//
+// Define the chip registers.
+//
+typedef struct _SCSI_REGISTERS{
+ SCSI_REGISTER CdbSize;
+ SCSI_REGISTER Control;
+ SCSI_REGISTER Timeout;
+ SCSI_REGISTER Cdb[12];
+ SCSI_REGISTER TargetLun;
+ SCSI_REGISTER CommandPhase;
+ SCSI_REGISTER Synchronous;
+ SCSI_REGISTER TransferCountMsb;
+ SCSI_REGISTER TransferCount2;
+ SCSI_REGISTER TransferCountLsb;
+ SCSI_REGISTER DestinationId;
+ SCSI_REGISTER SourceId;
+ SCSI_REGISTER Status;
+ SCSI_REGISTER Command;
+ SCSI_REGISTER Data;
+ SCSI_REGISTER AuxiliaryStatus;
+}SCSI_REGISTERS, *PSCSI_REGISTERS;
+
+//
+// Define SCSI Auxiliary Status register structure.
+//
+
+typedef struct _AUXILIARY_STATUS{
+ ULONG DataBufferReady : 1;
+ ULONG ParityError : 1;
+ ULONG Reserved : 2;
+ ULONG CommandInProgress : 1;
+ ULONG ChipBusy : 1;
+ ULONG LastCommandIgnored : 1;
+ ULONG Interrupt : 1;
+}AUXILIARY_STATUS, *PAUXILIARY_STATUS;
+
+//
+// Define SCSI Own Id register structure.
+//
+
+typedef struct _OWN_ID{
+ ULONG InitiatorId : 3;
+ ULONG AdvancedFeatures : 1;
+ ULONG EnableHostParity : 1;
+ ULONG Reserved : 1;
+ ULONG FrequencySelect : 2;
+}OWN_ID, *POWN_ID;
+
+//
+// Define Frequency Select values.
+//
+
+#define CLOCK_10MHZ 0
+#define CLOCK_15MHZ 1
+#define CLOCK_16MHZ 2
+#define CLOCK_20MHZ 2
+
+//
+// Define SCSI control register structure.
+//
+typedef struct _SCSI_CONTROL{
+ ULONG HaltOnParity : 1;
+ ULONG HaltOnAtn : 1;
+ ULONG IntermediateDisconnectInt : 1;
+ ULONG EndingDisconnectInt : 1;
+ ULONG HaltOnHostParity : 1;
+ ULONG DmaModeSelect : 3;
+}SCSI_CONTROL, *PSCSI_CONTROL;
+
+//
+// Define SCSI DMA Mode Select values.
+//
+
+#define DMA_POLLED 0
+#define DMA_BURST 1
+#define DMA_WD_BUS 2
+#define DMA_NORMAL 4
+
+//
+// Define the SCSI Target LUN register structure.
+//
+
+typedef struct _TARGET_LUN{
+ ULONG LogicalUnitNumber : 3;
+ ULONG Reserved : 3;
+ ULONG DisconnectOk : 1;
+ ULONG TargetLunValid : 1;
+}TARGET_LUN, *PTARGET_LUN;
+
+//
+// Define the SCSI Synchronous Transfer register structure.
+//
+
+typedef struct _SCSI_SYNCHRONOUS{
+ ULONG SynchronousOffset : 4;
+ ULONG SynchronousPeriod : 3;
+ ULONG Reserved : 1;
+}SCSI_SYNCHRONOUS, *PSCSI_SYNCHRONOUS;
+
+//
+// Define SCSI Destination Id register.
+//
+
+typedef struct _DESTINATION_ID{
+ ULONG TargetId : 3;
+ ULONG Reserved : 3;
+ ULONG DataDirection : 1;
+ ULONG SelectCommandChain : 1;
+}DESTINATION_ID, *PDESTINATION_ID;
+
+//
+// Define SCSI Source Id register.
+//
+
+typedef struct _SOURCE_ID{
+ ULONG TargetId : 3;
+ ULONG TargetIdValid : 1;
+ ULONG Reserved : 1;
+ ULONG DisableParitySelect : 1;
+ ULONG EnableSelection : 1;
+ ULONG EnableReselection : 1;
+}SOURCE_ID, *PSOURCE_ID;
+
+//
+// Define the SCSI Status register structure.
+//
+
+typedef struct _SCSI_STATUS{
+ ULONG PhaseState : 3;
+ ULONG PhaseStateValid : 1;
+ ULONG CommandComplete : 1;
+ ULONG AbortedPaused : 1;
+ ULONG Terminated : 1;
+ ULONG ServiceRequired : 1;
+}SCSI_STATUS, *PSCSI_STATUS;
+
+//
+// Define SCSI protocol chip SCSI status PhaseState values for command complete
+// interrupts.
+//
+
+#define COMPLETE_RESELECT 0x00
+#define COMPLETE_SELECT 0x01
+#define COMPLETE_TARGET_COMMAND 0x03
+#define COMPLETE_TARGET_WITH_ATN 0x04
+#define COMPLETE_TRANSLATE_ADDRESS 0x05
+#define COMPLETE_SELECT_AND_TRANS 0x06
+
+//
+// Define SCSI protocol chip SCSI status PhaseState values for aborted paused
+// interrupts.
+//
+
+#define PAUSED_MESSAGE_IN_DONE 0x00
+#define PAUSED_SAVE_POINTER_MESSAGE 0x01
+#define PAUSED_RESELECT_OR_SELECT 0x02
+#define PAUSED_TARGET_TRANS_ERROR 0x03
+#define PAUSED_TRANS_WITH_ATN 0x04
+#define PAUSED_DURING_RESELECT 0x05
+#define PAUSED_NEW_TARGET_RESELECT 0x07
+
+//
+// Define SCSI protocol chip SCSI status PhaseState values for service required
+// interrupts.
+//
+
+#define SERVICE_RESELECTED 0x00
+#define SERVICE_RESELECTED_IDENTIFY 0x01
+#define SERVICE_SELECTED_NO_ATN 0x02
+#define SERVICE_SELECTED_WITH_ATH 0x03
+#define SERVICE_ATN_ASSERTED 0x04
+#define SERVICE_DISCONNECTED 0x05
+#define SERVICE_UNKNWON_CDB_TYPE 0x07
+
+//
+// Define SCSI protocol chip SCSI status PhaseState values for terminated
+// interrupts.
+//
+
+#define TERMINATE_INVALID_COMMAND 0x00
+#define TERMINATE_UNEXPECTED_DISC 0x01
+#define TERMINATE_SELECT_TIMEOUT 0x02
+#define TERMINATE_PARITY_NO_ATN 0x03
+#define TERMINATE_PARITY_WITH_ATN 0x04
+#define TERMINATE_BAD_ADDRESS 0x05
+#define TERMINATE_NEW_TRAGET_NO_ID 0x06
+#define TERMINATE_PARITY_STATUS_IN 0x07
+
+
+//
+// Define SCSI protocol chip SCSI status PhaseState values for reset
+// interrupts.
+//
+
+#define RESET_STATUS 0x00
+#define RESET_WITH_ADVANCED 0x01
+
+//
+// Define SCSI Phase Codes.
+//
+
+#define DATA_OUT 0x0
+#define DATA_IN 0x1
+#define COMMAND_OUT 0x2
+#define STATUS_IN 0x3
+#define MESSAGE_OUT 0x6
+#define MESSAGE_IN 0x7
+
+
+//
+// Define SCSI command register structure.
+//
+
+typedef struct _SCSI_COMMAND{
+ ULONG OpCode : 7;
+ ULONG SingleByte : 1;
+}SCSI_COMMAND, *PSCSI_COMMAND;
+
+//
+// Define SCSI OpCode command values.
+//
+
+#define RESET_SCSI_CHIP 0x00
+#define ABORT_SCSI_CHIP 0x01
+#define ASSERT_ATN 0x02
+#define NEGATE_ACK 0x03
+#define DISCONNECT_FROM_BUS 0x04
+#define RESELECT 0x05
+#define SELECT_WITH_ATN 0x06
+#define SELECT_WITHOUT_ATN 0x07
+#define SELECT_ATN_AND_TRANSFER 0x08
+#define SELECT_AND_TRANSFER 0x09
+#define RESELECT_AND_RECEIVE_DATA 0x0a
+#define RESELECT_AND_SEND_DATA 0x0b
+#define WAIT_FOR_SELECT_RECEIVE 0x0c
+#define SEND_STATUS_AND_COMPETE 0x0d
+#define SEND_DISCONNECT_MESSAGE 0x0e
+#define SET_DISCONNECT_INTERRUPT 0x0f
+#define RECEIVE_COMMAND 0x10
+#define RECEIVE_DATA 0x11
+#define RECEIVE_MESSEAG_OUT 0x12
+#define RECEIVE_UNSPECIFIED_OUT 0x13
+#define SEND_STATUS 0x14
+#define SEND_DATA 0x15
+#define SEND_MESSAGE_IN 0x16
+#define SEND_UNSPECIFIED_DATA_IN 0x17
+#define TRANSLATE_ADDRESS 0x18
+#define TRANSFER_INFORMATION 0x20
+
+//
+// Define SCSI protocol chip command phase values.
+//
+
+#define PHASE_NO_SELECT 0x00
+#define PHASE_SELECTED 0x10
+#define PHASE_IDENTIFY_SENT 0x20
+#define PHASE_COMMAND_OUT 0x30
+#define PHASE_SAVE_DATA_RECEIVED 0x41
+#define PHASE_DISCONNECT_RECEIVED 0x42
+#define PHASE_LEGAL_DISCONNECT 0x43
+#define PHASE_RESELECTED 0x44
+#define PHASE_IDENTIFY_RECEIVED 0x45
+#define PHASE_DATA_TRANSFER_DONE 0x46
+#define PHASE_STATUS_STARTED 0x47
+#define PHASE_STATUS_RECEIVED 0x50
+#define PHASE_COMPLETE_RECEIVED 0x60
+
+#endif
+
diff --git a/private/ntos/miniport/wd33c93/wd33c93.rc b/private/ntos/miniport/wd33c93/wd33c93.rc
new file mode 100644
index 000000000..63793a7ad
--- /dev/null
+++ b/private/ntos/miniport/wd33c93/wd33c93.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Western Digital SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "wd33c93.sys"
+#define VER_ORIGINALFILENAME_STR "wd33c93.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/miniport/wd7000ex/makefile b/private/ntos/miniport/wd7000ex/makefile
new file mode 100644
index 000000000..b4338519e
--- /dev/null
+++ b/private/ntos/miniport/wd7000ex/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT WINDOWS
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/miniport/wd7000ex/sources b/private/ntos/miniport/wd7000ex/sources
new file mode 100644
index 000000000..c43f0916e
--- /dev/null
+++ b/private/ntos/miniport/wd7000ex/sources
@@ -0,0 +1,35 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=miniport
+
+TARGETNAME=fd7000ex
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=MINIPORT
+
+INCLUDES=..\..\inc
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\scsiport.lib
+
+SOURCES=wd7000ex.c wd7000ex.rc
diff --git a/private/ntos/miniport/wd7000ex/wd7000ex.c b/private/ntos/miniport/wd7000ex/wd7000ex.c
new file mode 100644
index 000000000..6dfb8af32
--- /dev/null
+++ b/private/ntos/miniport/wd7000ex/wd7000ex.c
@@ -0,0 +1,1684 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ wd7000ex.c
+
+Abstract:
+
+ This is the port driver for the WD7000EX SCSI adapter.
+
+Authors:
+
+ Mike Glass
+ Shashir Shah (Western Digital)
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "miniport.h"
+#include "wd7000ex.h" // includes scsi.h
+
+//
+// The following structure is allocated
+// from noncached memory as data will be DMA'd to
+// and from it.
+//
+
+typedef struct _NONCACHED_EXTENSION {
+
+ //
+ // Internal Control Block
+ //
+
+ ICB Icb;
+
+ //
+ // Adapter inquiry buffer
+ //
+
+ ADAPTER_INQUIRY AdapterInquiry;
+
+} NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _HW_DEVICE_EXTENSION {
+
+ PEISA_CONTROLLER EisaController;
+
+ //
+ // Adapter parameters
+ //
+
+ CCHAR IdtVector;
+
+ //
+ // Adapter host adapter Id.
+ //
+
+ UCHAR HostTargetId;
+
+ //
+ // Real-Mode interrupt state.
+ //
+
+ UCHAR InterruptState;
+ UCHAR NumberOfBuses;
+
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+
+//
+// Function declarations
+//
+// Functions that start with 'Wd7000Ex' are entry points
+// for the OS port driver.
+//
+
+ULONG
+Wd7000ExFindAdapter(
+ IN PVOID DeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ );
+
+BOOLEAN
+Wd7000ExInitialize(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Wd7000ExStartIo(
+ IN PVOID DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+BOOLEAN
+Wd7000ExInterrupt(
+ IN PVOID DeviceExtension
+ );
+
+BOOLEAN
+Wd7000ExResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+ );
+
+//
+// This function is called from Wd7000ExStartIo.
+//
+
+VOID
+BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from BuildCcb.
+//
+
+VOID
+BuildSdl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ );
+
+//
+// This function is called from Wd7000Initialize.
+//
+
+BOOLEAN
+AdapterPresent(
+ IN PVOID HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount
+ );
+
+BOOLEAN
+SendCommand(
+ IN UCHAR Opcode,
+ IN ULONG Address,
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ );
+
+
+BOOLEAN
+Wd7000ExAdapterState(
+ IN PVOID DeviceExtension,
+ IN PVOID AdaptersFound,
+ IN BOOLEAN SaveState
+ )
+
+/*++
+
+Routine Description:
+
+ Saves/restores adapter's real-mode configuration state.
+
+Arguments:
+
+ DeviceExtension - Adapter object device extension.
+ AdaptersFound - Passed through from DriverEntry as additional
+ context for the call.
+ SaveState - TRUE = Save adapter state, FALSE = restore state.
+
+Return Value:
+
+ The spec did not intend for this routine to have a return value.
+ Whoever did the header file just forgot to change the BOOLEAN to
+ a VOID. We will just return FALSE to shot the compiler up.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = DeviceExtension;
+
+ if (SaveState) {
+
+ //
+ // Remember system interrupt state.
+ //
+ deviceExtension->InterruptState = ScsiPortReadPortUchar(
+ &deviceExtension->EisaController->SystemInterruptEnable);
+
+ } else {
+
+ //
+ // Restore system interrupt state.
+ //
+ ScsiPortWritePortUchar(&deviceExtension->EisaController->SystemInterruptEnable,
+ deviceExtension->InterruptState);
+
+ }
+
+ return FALSE;
+}
+
+
+ULONG
+DriverEntry (
+ IN PVOID DriverObject,
+ IN PVOID Argument2
+ )
+
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point for system.
+
+Arguments:
+
+ Driver Object
+ Argument2 - Not used.
+
+Return Value:
+
+ Status from ScsiPortInitialize()
+
+--*/
+
+{
+ HW_INITIALIZATION_DATA hwInitializationData;
+ ULONG AdapterCount = 0;
+ ULONG i;
+
+ DebugPrint((1,"\n\nSCSI WD7000EX MiniPort Driver\n"));
+
+ //
+ // Zero out structure.
+ //
+
+ for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
+ ((PUCHAR)&hwInitializationData)[i] = 0;
+ }
+
+ //
+ // Set size of hwInitializationData.
+ //
+
+ hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+ //
+ // Set entry points.
+ //
+
+ hwInitializationData.HwInitialize = Wd7000ExInitialize;
+ hwInitializationData.HwFindAdapter = Wd7000ExFindAdapter;
+ hwInitializationData.HwStartIo = Wd7000ExStartIo;
+ hwInitializationData.HwInterrupt = Wd7000ExInterrupt;
+ hwInitializationData.HwResetBus = Wd7000ExResetBus;
+ hwInitializationData.HwAdapterState = Wd7000ExAdapterState;
+
+ //
+ // Set number of access ranges and bus type.
+ //
+
+ hwInitializationData.NumberOfAccessRanges = 1;
+ hwInitializationData.AdapterInterfaceType = Eisa;
+
+ //
+ // Indicate no buffer mapping but will need physical addresses.
+ //
+
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+ //
+ // Specify size of extensions.
+ //
+
+ hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+
+ //
+ // Ask for SRB extensions for CCBs.
+ //
+
+ hwInitializationData.SrbExtensionSize = sizeof(CCB);
+
+ return ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &AdapterCount);
+
+} // end DriverEntry()
+
+
+BOOLEAN
+AdapterPresent(
+ IN PVOID HwDeviceExtension,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN OUT PULONG AdapterCount
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if WD7000EX SCSI adapter is installed in system
+ by reading the EISA board configuration registers for each
+ EISA slot looking for the correct signature.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+ ConfigInfo - Supplies the configuration information stucture. If an
+ adapter is found the access range is update.
+
+ AdapterCount - Supplies the count of slots which have already been checked.
+
+Return Value:
+
+ TRUE if adapter present.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ ULONG eisaSlotNumber;
+ PEISA_CONTROLLER eisaController;
+
+ //
+ // Check to see if adapter present in system.
+ //
+
+
+ for (eisaSlotNumber=*AdapterCount + 1; eisaSlotNumber<MAXIMUM_EISA_SLOTS; eisaSlotNumber++) {
+
+ //
+ // Update the adapter count.
+ //
+
+ (*AdapterCount)++;
+
+ //
+ // Get the system address for this card. The card uses I/O space.
+ // If ConfigInfo already has default information about this
+ // controller, use it. If not, then we derive our own. This
+ // is for Chicago compatibility.
+ //
+ if (ScsiPortConvertPhysicalAddressToUlong(
+ (*ConfigInfo->AccessRanges)[0].RangeStart) != 0) {
+
+ eisaController = ScsiPortGetDeviceBase(
+ deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ (*ConfigInfo->AccessRanges)[0].RangeStart,
+ (*ConfigInfo->AccessRanges)[0].RangeLength,
+ (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory));
+ } else {
+
+ eisaController = ScsiPortGetDeviceBase(
+ deviceExtension,
+ ConfigInfo->AdapterInterfaceType,
+ ConfigInfo->SystemIoBusNumber,
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
+ 0x1000,
+ TRUE);
+ }
+
+ eisaController =
+ (PEISA_CONTROLLER)((PUCHAR)eisaController + EISA_ADDRESS_BASE);
+
+ if ((ScsiPortReadPortUchar(&eisaController->BoardId[0]) == 0x5C) &&
+ (ScsiPortReadPortUchar(&eisaController->BoardId[1]) == 0x83) &&
+ (ScsiPortReadPortUchar(&eisaController->BoardId[2]) == 0x20)) {
+
+ deviceExtension->EisaController = eisaController;
+
+ return TRUE;
+ }
+
+ //
+ // The card is not here so clean up.
+ //
+
+ ScsiPortFreeDeviceBase(deviceExtension,
+ (PUCHAR)eisaController - EISA_ADDRESS_BASE);
+
+ } // end for (eisaSlotNumber ...
+
+ //
+ // Clear the adapter count for the next bus.
+ //
+
+ *AdapterCount = 0;
+
+ return FALSE;
+
+} // end AdapterPresent()
+
+
+ULONG
+Wd7000ExFindAdapter(
+ IN PVOID HwDeviceExtension,
+ IN PVOID Context,
+ IN PVOID BusInformation,
+ IN PCHAR ArgumentString,
+ IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ OUT PBOOLEAN Again
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the OS-specific port driver after
+ the necessary storage has been allocated, to gather information
+ about the adapter's configuration.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ ConfigInfo - Configuration information structure describing HBA
+
+Return Value:
+
+ TRUE if adapter present in system
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController;
+ PULONG adapterCount = Context;
+ PNONCACHED_EXTENSION ncExtension;
+ ULONG eisaSlotNumber;
+ PICB icb;
+ PADAPTER_INQUIRY adapterInquiry;
+ ULONG physicalIcb;
+ ULONG i;
+ ULONG length;
+ UCHAR status;
+
+ //
+ // Check to see if adapter present in system.
+ //
+ if (!AdapterPresent(deviceExtension, ConfigInfo, Context)) {
+ DebugPrint((1,"Wd7000EX: SCSI adapter not present\n"));
+ *Again = FALSE;
+ return SP_RETURN_NOT_FOUND;
+ }
+
+ //
+ // There is still more to look at.
+ //
+
+ *Again = FALSE;
+
+ //
+ // Fill in the access array information only if there are no
+ // default parameters already there.
+ //
+ if (ScsiPortConvertPhysicalAddressToUlong(
+ (*ConfigInfo->AccessRanges)[0].RangeStart) == 0) {
+
+ *Again = TRUE;
+ (*ConfigInfo->AccessRanges)[0].RangeStart =
+ ScsiPortConvertUlongToPhysicalAddress(0x1000 * (*((PULONG) Context)) + EISA_ADDRESS_BASE);
+ (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
+ (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
+
+ //
+ // Indicate maximum transfer length in bytes.
+ //
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_SIZE;
+
+ //
+ // Maximum number of physical segments is 32.
+ //
+ ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SDL_SIZE;
+
+ //
+ // Set the configuration parameters for this card.
+ //
+
+ ConfigInfo->NumberOfBuses = 1;
+ deviceExtension->NumberOfBuses = 1;
+ ConfigInfo->ScatterGather = TRUE;
+ ConfigInfo->Master = TRUE;
+
+ //
+ // Get a noncached extension for an adapter inquiry command.
+ //
+
+ ncExtension = ScsiPortGetUncachedExtension(
+ deviceExtension,
+ ConfigInfo,
+ sizeof(NONCACHED_EXTENSION));
+
+ if (ncExtension == NULL) {
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 6 << 16
+ );
+
+ return SP_RETURN_ERROR;
+ }
+
+ length = sizeof(NONCACHED_EXTENSION);
+
+ //
+ // Convert virtual to physical address.
+ //
+
+ physicalIcb = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension,
+ NULL,
+ ncExtension,
+ &length));
+
+ //
+ // Initialize the pointers.
+ //
+
+ icb = &ncExtension->Icb;
+ adapterInquiry = &ncExtension->AdapterInquiry;
+
+ //
+ // Create ICB for Adapter Inquiry Command.
+ //
+
+ icb->IcbFlags = 0;
+ icb->CompletionStatus = 0;
+ icb->Reserved = 0;
+ icb->DataBufferAddress = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(
+ deviceExtension,
+ NULL,
+ adapterInquiry,
+ &length));
+
+ icb->TransferCount = sizeof(ADAPTER_INQUIRY);
+
+ icb->OpCode = ADAPTER_INQUIRY_COMMAND;
+
+ //
+ // Get ICB physical address.
+ //
+
+ physicalIcb = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(
+ deviceExtension,
+ NULL,
+ icb,
+ &length));
+
+ //
+ // Disable system interrupts.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->EisaController->SystemInterruptEnable,
+ SYSTEM_INTERRUPTS_DISABLE);
+
+ //
+ // Write ICB physical address and command to mailbox.
+ //
+
+ SendCommand(PROCESS_ICB,
+ physicalIcb,
+ deviceExtension);
+
+ //
+ // Poll for ICB completion.
+ //
+
+ i = 0;
+ while ((status =
+ ScsiPortReadPortUchar(
+ &deviceExtension->EisaController->ResponseRegister)) == 0) {
+
+ i++;
+
+ if (i > 100000) {
+
+ break;
+ }
+
+ ScsiPortStallExecution(10);
+ }
+
+ if (status == 0) {
+
+ //
+ // The request timed out. Log an error and return.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 7 << 16
+ );
+ return SP_RETURN_ERROR;
+ }
+
+ DebugPrint((1, "Wd7000ExFindAdapter: Get configuration request time = %d.\n", i * 10));
+
+ //
+ // Acknowledge interrupt.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->EisaController->ResponseRegister, 0xFF);
+
+ //
+ // Enable system interrupts.
+ //
+
+ ScsiPortWritePortUchar(&deviceExtension->EisaController->SystemInterruptEnable,
+ SYSTEM_INTERRUPTS_ENABLE);
+
+ //
+ // Check returned status for success.
+ //
+
+ if (status != COMPLETE_SUCCESS) {
+
+ //
+ // Give up.
+ //
+
+ DebugPrint((1,"Wd7000Ex: Response register %x\n", status));
+ DebugPrint((1,"Wd7000Ex: Adapter inquiry failed\n"));
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ 0,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 8 << 16
+ );
+
+ return SP_RETURN_ERROR;
+ }
+
+ //
+ // NOTE: Delay here. I don't understand this latency between
+ // when the device interrupts and the status of the ICB
+ // is success and when the data is actually available in
+ // the buffer.
+ //
+
+ ScsiPortStallExecution(300);
+
+ if (adapterInquiry->AdapterInformation & DUAL_CHANNEL) {
+
+ //
+ // There are two buses on the adapter.
+ //
+
+ ConfigInfo->InitiatorBusId[1] =
+ (adapterInquiry->ChannelInformation >> 4) & BUS_ID_MASK;
+ ConfigInfo->NumberOfBuses = 2;
+ deviceExtension->NumberOfBuses = 2;
+ }
+
+ ConfigInfo->InitiatorBusId[0] =
+ adapterInquiry->ChannelInformation & BUS_ID_MASK;
+ ConfigInfo->BusInterruptLevel = adapterInquiry->Irq;
+ }
+ deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0];
+ return SP_RETURN_FOUND;
+} // end Wd7000ExFindAdapter()
+
+
+BOOLEAN
+Wd7000ExInitialize(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Inititialize adapter and mailbox.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE - if initialization successful.
+ FALSE - if initialization unsuccessful.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ BOOLEAN returnValue;
+
+ //
+ // Reset Wd7000Ex and SCSI bus.
+ //
+
+ returnValue = Wd7000ExResetBus(deviceExtension, 0);
+ ScsiPortNotification(
+ ResetDetected,
+ deviceExtension,
+ 0
+ );
+
+ if (deviceExtension->NumberOfBuses == 2) {
+
+ Wd7000ExResetBus(deviceExtension, 1);
+ ScsiPortNotification(
+ ResetDetected,
+ deviceExtension,
+ 1
+ );
+
+ }
+
+ if (!returnValue) {
+
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+
+} // end Wd7000ExInitialize()
+
+
+BOOLEAN
+Wd7000ExStartIo(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the SCSI port driver synchronized
+ with the kernel. The mailboxes are scanned for an empty one and
+ the CCB is written to it. Then the doorbell is rung and the
+ OS port driver is notified that the adapter can take
+ another request, if any are available.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+ Srb - IO request packet
+
+Return Value:
+
+ Nothing
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ PCCB ccb;
+ UCHAR opCode;
+ ULONG physicalCcb;
+ ULONG length;
+ ULONG i = 0;
+
+ DebugPrint((3,"Wd7000ExStartIo: Enter routine\n"));
+
+ //
+ // Get CCB from SRB.
+ //
+
+ if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
+
+ //
+ // Get CCB to abort.
+ //
+
+ ccb = Srb->NextSrb->SrbExtension;
+
+ //
+ // Set abort SRB for completion.
+ //
+
+ ccb->AbortSrb = Srb;
+
+ } else {
+
+ ccb = Srb->SrbExtension;
+
+ //
+ // Save SRB back pointer in CCB.
+ //
+
+ ccb->SrbAddress = Srb;
+ }
+
+ //
+ // Get CCB physical address.
+ //
+
+ physicalCcb =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(deviceExtension, NULL, ccb, &length));
+
+ //
+ // Assume physical address is contiguous for size of CCB.
+ //
+
+ ASSERT(length >= sizeof(CCB));
+
+ switch (Srb->Function) {
+
+ case SRB_FUNCTION_EXECUTE_SCSI:
+
+ //
+ // Build CCB.
+ //
+
+ BuildCcb(deviceExtension, Srb);
+
+ //
+ // Or in PathId.
+ //
+
+ opCode = PROCESS_CCB | Srb->PathId << 6;
+
+ break;
+
+ case SRB_FUNCTION_ABORT_COMMAND:
+
+ DebugPrint((1, "Wd7000ExStartIo: Abort request received\n"));
+
+ //
+ // NOTE: Race condition if aborts occur
+ // (what if CCB to be aborted
+ // completes after setting new SrbAddress?)
+ //
+
+ opCode = ABORT_CCB;
+
+ break;
+
+ case SRB_FUNCTION_RESET_BUS:
+
+ //
+ // Reset Wd7000Ex and SCSI bus.
+ //
+
+ DebugPrint((1, "Wd7000ExStartIo: Reset bus request received\n"));
+
+ Wd7000ExResetBus(deviceExtension,
+ Srb->PathId);
+
+ return TRUE;
+
+ case SRB_FUNCTION_RESET_DEVICE:
+
+ break;
+
+ default:
+
+ //
+ // Set error, complete request
+ // and signal ready for next request.
+ //
+
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+
+ ScsiPortNotification(RequestComplete,
+ deviceExtension,
+ Srb);
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+ } // end switch
+
+ SendCommand(opCode,
+ physicalCcb,
+ deviceExtension);
+
+ //
+ // Adapter ready for next request.
+ //
+
+ ScsiPortNotification(NextRequest,
+ deviceExtension,
+ NULL);
+
+ return TRUE;
+
+} // end Wd7000ExStartIo()
+
+
+BOOLEAN
+Wd7000ExInterrupt(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt service routine for the WD7000EX SCSI adapter.
+ It reads the interrupt register to determine if the adapter is indeed
+ the source of the interrupt and clears the interrupt at the device.
+ If the adapter is interrupting because a mailbox is full, the CCB is
+ retrieved to complete the request.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ TRUE if MailboxIn full
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PCCB ccb;
+ PSCSI_REQUEST_BLOCK srb;
+ PSCSI_REQUEST_BLOCK abortedSrb;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ ULONG logError = 0;
+ ULONG physicalCcb;
+ UCHAR srbStatus;
+ UCHAR response;
+
+ if (!(ScsiPortReadPortUchar(
+ &eisaController->SystemInterruptEnable) & SYSTEM_INTERRUPT_PENDING)) {
+
+ DebugPrint((2, "WD7000EX: Spurious interrupt\n"));
+ return FALSE;
+ }
+
+ //
+ // Get physical address of CCB.
+ //
+
+ physicalCcb = ScsiPortReadPortUlong(&eisaController->ResponseMailbox);
+
+ //
+ // Read status from response register.
+ //
+
+ response = ScsiPortReadPortUchar(&eisaController->ResponseRegister);
+
+ //
+ // Acknowledge interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResponseRegister, 0xFF);
+
+ //
+ // Get virtual CCB address.
+ //
+
+ ccb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalCcb));
+
+ //
+ // Make sure the ccb is valid, if it is supposed to be.
+ //
+
+ if (ccb == NULL &&
+ response != ABORT_COMMAND_COMPLETE &&
+ response != BUS_RESET &&
+ response != RESET_DEVICE_COMPLETE &&
+ response != ABORT_CCB_NOT_FOUND) {
+
+ ScsiPortLogError(
+ HwDeviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ (5 << 16) | response
+ );
+
+ return TRUE;
+ }
+
+ switch (response & STATUS_MASK) {
+
+ case COMPLETE_SUCCESS:
+ case REQUEST_SENSE_COMPLETE:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Command complete\n"));
+ srbStatus = SRB_STATUS_SUCCESS;
+
+ break;
+
+ case COMPLETE_ERROR:
+
+ DebugPrint((2, "Wd7000ExInterrupt: Command complete with error\n"));
+ srbStatus = SRB_STATUS_ERROR;
+
+ break;
+
+ case BUS_RESET:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Bus reset\n"));
+ srbStatus = SRB_STATUS_BUS_RESET;
+
+ return TRUE;
+
+ case ABORT_COMMAND_COMPLETE:
+
+ //
+ // This interrupt is not associated with a CCB.
+ //
+
+ DebugPrint((1, "Wd7000ExInterrupt: Command aborted\n"));
+
+ return TRUE;
+
+ case RESET_DEVICE_COMPLETE:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Device reset complete\n"));
+ srbStatus = SRB_STATUS_SUCCESS;
+
+ break;
+
+ case COMMAND_ABORTED:
+
+ DebugPrint((1, "Wd7000ExInterrupt: Abort command complete\n"));
+
+ //
+ // Get SRB from CCB.
+ //
+
+ srb = ccb->SrbAddress;
+
+ //
+ // Get aborted SRB.
+ //
+
+ abortedSrb = ccb->AbortSrb;
+
+ //
+ // Update the abort SRB status.
+ //
+
+ abortedSrb->SrbStatus = SRB_STATUS_SUCCESS;
+
+ //
+ // Call notification routine for the aborted SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ abortedSrb);
+
+ //
+ // Update status of the aborted SRB.
+ //
+
+ srbStatus = SRB_STATUS_TIMEOUT;
+
+ break;
+
+ case ABORT_CCB_NOT_FOUND:
+
+ //
+ // This normally occurs when the adapter has started processing
+ // the request. Drop it on the floor and let the abort time out.
+ //
+
+ DebugPrint((1, "Wd7000ExInterrupt: Abort command failed\n"));
+ return TRUE;
+
+ case ILLEGAL_STATUS:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Illegal status\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+
+ break;
+
+ case DEVICE_TIMEOUT:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Device timeout\n"));
+ srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
+
+ break;
+
+ case SHORT_RECORD_EXCEPTION:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Data record short\n"));
+
+ srb = ccb->SrbAddress;
+ if (ccb->ScsiDeviceStatus == SCSISTAT_CHECK_CONDITION) {
+ srbStatus = SRB_STATUS_ERROR;
+ } else {
+ srbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ //
+ // Update SRB with actual number of bytes transferred.
+ //
+
+ srb->DataTransferLength -= ccb->TransferCount;
+ }
+
+ break;
+
+ case LONG_RECORD_EXCEPTION:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Data overrun\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+
+ srbStatus = SRB_STATUS_DATA_OVERRUN;
+
+ break;
+
+ case PARITY_ERROR:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Parity error\n"));
+ logError = SP_BUS_PARITY_ERROR;
+ srbStatus = SRB_STATUS_PARITY_ERROR;
+
+ break;
+
+ case UNEXPECTED_BUS_FREE:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Unexpected bus free\n"));
+ logError = SP_UNEXPECTED_DISCONNECT;
+ srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
+
+ break;
+
+ case INVALID_STATE:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Phase sequence error\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
+
+ break;
+
+ case HOST_DMA_ERROR:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Host DMA error\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+
+ break;
+
+ case INVALID_COMMAND:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Invalid command\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+
+ break;
+
+ case INCORRECT_COMMAND_DIRECTION:
+ default:
+
+ DebugPrint((3, "Wd7000ExInterrupt: Incorrect command direction\n"));
+ logError = SP_INTERNAL_ADAPTER_ERROR;
+ srbStatus = SRB_STATUS_ERROR;
+
+ break;
+
+ } // end switch
+
+ //
+ // Get SRB from CCB.
+ //
+
+ srb = ccb->SrbAddress;
+
+ //
+ // Update SRB status.
+ //
+
+ srb->SrbStatus = srbStatus;
+
+ //
+ // Copy SCSI status from CCB to SRB.
+ //
+
+ srb->ScsiStatus = ccb->ScsiDeviceStatus;
+
+ if (logError != 0) {
+
+ //
+ // Log error.
+ //
+
+ ScsiPortLogError(
+ deviceExtension,
+ srb,
+ srb->PathId,
+ srb->TargetId,
+ srb->Lun,
+ logError,
+ 2 << 16 | response
+ );
+
+ }
+
+ //
+ // Call notification routine for the SRB.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)deviceExtension,
+ srb);
+
+ return TRUE;
+
+} // end Wd7000ExInterrupt()
+
+
+VOID
+BuildCcb(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ Build CCB for WD7000EX.
+
+Arguments:
+
+ DeviceExtenson
+ SRB
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PCCB ccb = Srb->SrbExtension;
+
+ DebugPrint((3,"BuildCcb: Enter routine\n"));
+
+ //
+ // Zero out CCB statuses.
+ //
+
+ ccb->CompletionStatus = 0;
+ ccb->ScsiDeviceStatus = 0;
+
+ //
+ // Set transfer direction bit.
+ //
+
+ if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+ ccb->CommandFlags = DIRECTION_WRITE | SCATTER_GATHER;
+ } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ ccb->CommandFlags = DIRECTION_READ | SCATTER_GATHER;
+ } else {
+ ccb->CommandFlags = 0;
+ }
+
+ //
+ // Check if disconnect explicity forbidden.
+ //
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)) {
+
+ ccb->CommandFlags |= DISCONNECTION;
+ }
+
+ //
+ // Check if synchronous data transfers are allowed.
+ //
+
+ if (!(Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)) {
+
+ ccb->CommandFlags |= SYNCHRONOUS_NEGOCIATION;
+
+ }
+
+ //
+ // Set target id and LUN.
+ // PathId is indicated in upper bits of command byte.
+ //
+
+ ccb->TargetId = Srb->TargetId;
+ ccb->Lun = Srb->Lun;
+
+ //
+ // Set CDB length and copy to CCB.
+ //
+
+ ScsiPortMoveMemory(ccb->Cdb, Srb->Cdb, Srb->CdbLength);
+
+ //
+ // Build SDL in CCB if data transfer.
+ //
+
+ if (Srb->DataTransferLength > 0) {
+ BuildSdl(DeviceExtension, Srb);
+ } else {
+ ccb->DataBufferAddress = 0;
+ ccb->TransferCount = 0;
+ }
+
+ return;
+
+} // end BuildCcb()
+
+
+VOID
+BuildSdl(
+ IN PHW_DEVICE_EXTENSION DeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine builds a scatter/gather descriptor list for the CCB.
+
+Arguments:
+
+ DeviceExtension
+ Srb
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PVOID dataPointer = Srb->DataBuffer;
+ ULONG bytesLeft = Srb->DataTransferLength;
+ PCCB ccb = Srb->SrbExtension;
+ PSDL sdl = &ccb->Sdl;
+ ULONG physicalSdl;
+ ULONG physicalAddress;
+ ULONG length;
+ ULONG descriptorCount = 0;
+
+ DebugPrint((3,"BuildSdl: Enter routine\n"));
+
+ //
+ // Get physical SDL address.
+ //
+
+ physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
+ sdl, &length));
+
+ //
+ // Assume physical memory contiguous for sizeof(SDL) bytes.
+ //
+
+ ASSERT(length >= sizeof(SDL));
+
+ //
+ // Create SDL segment descriptors.
+ //
+
+ do {
+
+ DebugPrint((3, "BuildSdl: Data buffer %lx\n", dataPointer));
+
+ //
+ // Get physical address and length of contiguous
+ // physical buffer.
+ //
+
+ physicalAddress =
+ ScsiPortConvertPhysicalAddressToUlong(
+ ScsiPortGetPhysicalAddress(DeviceExtension,
+ Srb,
+ dataPointer,
+ &length));
+
+ DebugPrint((3, "BuildSdl: Physical address %lx\n", physicalAddress));
+ DebugPrint((3, "BuildSdl: Data length %lx\n", length));
+ DebugPrint((3, "BuildSdl: Bytes left %lx\n", bytesLeft));
+
+ //
+ // If length of physical memory is more
+ // than bytes left in transfer, use bytes
+ // left as final length.
+ //
+
+ if (length > bytesLeft) {
+ length = bytesLeft;
+ }
+
+ sdl->Descriptor[descriptorCount].Address = physicalAddress;
+ sdl->Descriptor[descriptorCount].Length = length;
+
+ //
+ // Adjust counts.
+ //
+
+ dataPointer = (PUCHAR)dataPointer + length;
+ bytesLeft -= length;
+ descriptorCount++;
+
+ } while (bytesLeft);
+
+ //
+ // Write SDL length to CCB.
+ //
+
+ ccb->TransferCount = descriptorCount * sizeof(SG_DESCRIPTOR);
+
+ DebugPrint((3,"BuildSdl: SDL length is %d\n", descriptorCount));
+
+ //
+ // Write SDL address to CCB.
+ //
+
+ ccb->DataBufferAddress = physicalSdl;
+
+ DebugPrint((3,"BuildSdl: SDL address is %lx\n", sdl));
+
+ DebugPrint((3,"BuildSdl: CCB address is %lx\n", ccb));
+
+ return;
+
+} // end BuildSdl()
+
+
+BOOLEAN
+Wd7000ExResetBus(
+ IN PVOID HwDeviceExtension,
+ IN ULONG PathId
+)
+
+/*++
+
+Routine Description:
+
+ Reset Wd7000Ex SCSI adapter and SCSI bus.
+
+Arguments:
+
+ HwDeviceExtension - HBA miniport driver's adapter data storage
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
+ PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
+ UCHAR control;
+ ULONG i;
+
+ DebugPrint((2,"ResetBus: Reset Wd7000Ex and SCSI bus\n"));
+
+ //
+ // Disable system interrupts.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemInterruptEnable,
+ SYSTEM_INTERRUPTS_DISABLE);
+
+ //
+ // Set interrupt enable, SCSI bus reset bits in control register.
+ //
+
+ control = ADAPTER_INTERRUPT_ENABLE;
+ control += PathId == 0 ? SCSI_BUS_RESET_CHANNEL_0 : SCSI_BUS_RESET_CHANNEL_1;
+
+ ScsiPortWritePortUchar(&eisaController->ControlRegister, control);
+
+ //
+ // Wait 30 microseconds.
+ //
+
+ ScsiPortStallExecution(30);
+
+ //
+ // Reset adapter and clear SCSI bus reset.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ControlRegister,
+ ADAPTER_RESET + ADAPTER_INTERRUPT_ENABLE);
+
+ //
+ // Wait for up to 2 seconds.
+ //
+
+ for (i=0; i<20; i++) {
+
+ //
+ // Stall 100 milliseconds.
+ //
+
+ ScsiPortStallExecution(100 * 1000);
+
+ //
+ // Check status.
+ //
+
+ if (ScsiPortReadPortUchar(&eisaController->ResponseRegister) ==
+ COMPLETE_SUCCESS) {
+
+ break;
+ }
+ }
+
+ if (i==20) {
+
+ DebugPrint((1, "ResetBus: Reset failed\n"));
+
+ ScsiPortLogError(
+ deviceExtension,
+ NULL,
+ 0,
+ deviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 3 << 16
+ );
+
+ return FALSE;
+ }
+
+ //
+ // Acknowledge interrupt.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResponseRegister, 0xFF);
+
+ //
+ // Enable system interrupts.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->SystemInterruptEnable,
+ SYSTEM_INTERRUPTS_ENABLE);
+
+ //
+ // Enable response interrupt mask.
+ //
+
+ ScsiPortWritePortUchar(&eisaController->ResponseInterruptMask, 0xFF);
+
+ //
+ // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
+ //
+
+ ScsiPortCompleteRequest((PVOID) deviceExtension,
+ (UCHAR) PathId,
+ (UCHAR) 0xFF,
+ (UCHAR) 0xFF,
+ (UCHAR) SRB_STATUS_BUS_RESET);
+
+ return TRUE;
+
+} // end Wd7000ExResetBus()
+
+
+BOOLEAN
+SendCommand(
+ IN UCHAR Opcode,
+ IN ULONG Address,
+ IN PHW_DEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Send a command the the WD7000ex.
+
+Arguments:
+
+ Opcode - Operation code to send.
+
+ Address - Physical address for the operation.
+
+ DeviceExtension - Pointer to device extension.
+
+Return Value:
+
+ True if command sent.
+ False if adapter never reached 'ready for next command' state.
+
+--*/
+
+{
+
+ PEISA_CONTROLLER Registers = DeviceExtension->EisaController;
+ ULONG i;
+
+ for (i=0; i<1000; i++) {
+
+ UCHAR status;
+
+ status = ScsiPortReadPortUchar(&Registers->CommandRegister);
+
+ if (status == 0) {
+
+ //
+ // Adapter ready for next command.
+ //
+
+ break;
+
+ } else {
+
+ //
+ // Stall 1 microsecond before trying again.
+ //
+
+ ScsiPortStallExecution(1);
+ }
+ }
+
+ if (i == 100) {
+
+ //
+ // Timed out waiting for adapter to become ready.
+ // Do not complete this command. Instead, let it
+ // timeout so normal recovery will take place.
+ //
+
+ ScsiPortLogError(
+ DeviceExtension,
+ NULL,
+ 0,
+ DeviceExtension->HostTargetId,
+ 0,
+ SP_INTERNAL_ADAPTER_ERROR,
+ 4 << 16
+ );
+
+ return FALSE;
+ }
+
+ //
+ // Write the address and opcode to adapter.
+ //
+
+ ScsiPortWritePortUlong(&Registers->CommandMailbox, Address);
+ ScsiPortWritePortUchar(&Registers->CommandRegister, Opcode);
+
+ return TRUE;
+
+} // end SendCommand()
+
diff --git a/private/ntos/miniport/wd7000ex/wd7000ex.h b/private/ntos/miniport/wd7000ex/wd7000ex.h
new file mode 100644
index 000000000..4969f6cfe
--- /dev/null
+++ b/private/ntos/miniport/wd7000ex/wd7000ex.h
@@ -0,0 +1,218 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ wd7000.h
+
+Abstract:
+
+ This is the header file in support of the Western Digital
+ WD7000EX EISA SCSI adapter driver.
+
+Author:
+
+ mglass
+
+Notes:
+
+ The adapter supports up to 32 scatter gather descriptors.
+ But the system is tuned for up to 17 pages and allocating 32
+ descriptors out of noncached pool is expensive so the maximum
+ is set to 17.
+
+Revision History:
+
+--*/
+
+#include <scsi.h>
+
+#define MAXIMUM_EISA_SLOTS 0x08
+#define MAXIMUM_TRANSFER_SIZE 0xFFFFFFFF
+#define MAXIMUM_SDL_SIZE 0x11
+#define REQUEST_SENSE_BUFFER_SIZE 0x18
+#define EISA_SLOT_SHIFT 0x0C
+#define EISA_ADDRESS_BASE 0x0C80
+
+//
+// Scatter Gather descriptor list (SDL)
+//
+
+typedef struct _SG_DESCRIPTOR {
+ ULONG Address;
+ ULONG Length;
+} SG_DESCRIPTOR, *PSG_DESCRIPTOR;
+
+typedef struct _SDL {
+ SG_DESCRIPTOR Descriptor[MAXIMUM_SDL_SIZE];
+} SDL, *PSDL;
+
+//
+// Command Control Block (CCB)
+//
+
+typedef struct _CCB {
+
+ USHORT CommandFlags;
+ UCHAR CompletionStatus;
+ UCHAR ScsiDeviceStatus;
+ ULONG DataBufferAddress;
+ ULONG TransferCount;
+ ULONG LinkCommand;
+ ULONG RequestSenseAddress;
+ USHORT RequestSenseLength;
+ UCHAR Cdb[12];
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR Reserved[4];
+ PVOID SrbAddress;
+ PVOID AbortSrb;
+ SDL Sdl;
+ UCHAR RequestSenseBuffer[REQUEST_SENSE_BUFFER_SIZE];
+
+} CCB, *PCCB;
+
+//
+// Command Flag bit definitions
+//
+
+#define RETURN_CCB_STATUS 0x0080
+#define DIRECTION_WRITE 0x0000 + 0x0040
+#define DIRECTION_READ 0x0020 + 0x0040
+#define SCATTER_GATHER 0x0010
+#define AUTO_REQUEST_SENSE 0x0008
+#define DISCONNECTION 0x0004
+#define SYNCHRONOUS_NEGOCIATION 0x0002
+#define SUPPRESS_SHORT_RECORD_EXCEPTION 0x0001
+#define CHAINED_COMMAND 0x8000
+
+//
+// Internal Control Block (ICB)
+//
+
+typedef struct _ICB {
+ USHORT IcbFlags;
+ UCHAR CompletionStatus;
+ UCHAR Reserved;
+ ULONG DataBufferAddress;
+ ULONG TransferCount;
+ UCHAR OpCode;
+ UCHAR IcbCommand[15];
+} ICB, *PICB;
+
+//
+// ICB Operation code definitions
+//
+
+#define ADAPTER_INQUIRY_COMMAND 0x00
+
+//
+// Adapter Inquiry buffer
+//
+
+typedef struct _ADAPTER_INQUIRY {
+ USHORT HardwareRevisionLevel;
+ USHORT FirmwareRevisionLevel;
+ ULONG BiosBaseAddress;
+ UCHAR BusPreemptTime;
+ UCHAR Irq;
+ UCHAR AdapterInformation;
+ UCHAR ChannelInformation;
+ UCHAR ReservedBytes[8];
+ UCHAR VendorId[8];
+ UCHAR ProductId[8];
+} ADAPTER_INQUIRY, *PADAPTER_INQUIRY;
+
+//
+// Bus ID masks
+//
+
+#define BUS_ID_MASK 0x07
+
+#define DUAL_CHANNEL 0x02
+
+//
+// EISA Controller registers
+//
+
+typedef struct _EISA_CONTROLLER {
+
+ UCHAR BoardId[4]; // zC80
+ UCHAR Undefined1; // zC84
+ UCHAR AutoConfiguration[3]; // zC85
+ UCHAR Undefined2; // zC88
+ UCHAR SystemInterruptEnable; // zC89
+ UCHAR Undefined3[3]; // zC8A
+ UCHAR CommandRegister; // zC8D
+ UCHAR ResponseInterruptMask; // zC8E
+ UCHAR ResponseRegister; // zC8F
+ ULONG CommandMailbox; // zC90
+ ULONG ResponseMailbox; // zC94
+ UCHAR Undefined4[26]; // zC98
+ UCHAR ControlRegister; // zCB2
+
+} EISA_CONTROLLER, *PEISA_CONTROLLER;
+
+//
+// Command definitions
+//
+
+#define ILLEGAL_OPCODE 0x00
+#define PROCESS_CCB 0x01
+#define PROCESS_ICB 0x02
+#define RESET_DEVICE 0x03
+#define ABORT_CCB 0x04
+#define RESET_ACKNOWLEDGE 0x05
+
+//
+// Response Status
+//
+
+#define ILLEGAL_STATUS 0x00
+#define COMPLETE_SUCCESS 0x01
+#define COMPLETE_ERROR 0x02
+#define DEVICE_TIMEOUT 0x03
+#define BUS_RESET 0x04
+#define SHORT_RECORD_EXCEPTION 0x05
+#define LONG_RECORD_EXCEPTION 0x06
+#define PARITY_ERROR 0x07
+#define UNEXPECTED_BUS_FREE 0x08
+#define INVALID_STATE 0x09
+#define REQUEST_SENSE_COMPLETE 0x0A
+#define HOST_DMA_ERROR 0x0B
+#define INVALID_COMMAND 0x0C
+#define COMMAND_ABORTED 0x0D
+#define RESET_DEVICE_COMPLETE 0x0E
+#define ABORT_COMMAND_COMPLETE 0x0F
+#define ABORT_CCB_NOT_FOUND 0x10
+#define INCORRECT_COMMAND_DIRECTION 0x11
+
+//
+// System Interrupt Enable bits
+//
+
+#define SYSTEM_INTERRUPTS_DISABLE 0x00
+#define SYSTEM_INTERRUPTS_ENABLE 0x01
+#define SYSTEM_INTERRUPT_PENDING 0x02
+
+//
+// Control Register bit definitions
+//
+
+#define ADAPTER_RESET 0x01
+#define SCSI_BUS_RESET_CHANNEL_0 0x02
+#define ADAPTER_INTERRUPT_ENABLE 0x08
+#define SCSI_BUS_RESET_CHANNEL_1 0x10
+
+#define STATUS_MASK 0x3F
+
+//
+// Send ICB or CCB macro
+//
+
+#define SEND_COMMAND(Opcode, Address, Registers) { \
+ while (ScsiPortReadPortUchar(Registers->CommandRegister)); \
+ ScsiPortWritePortUlong(Registers->CommandMailbox, Address); \
+ ScsiPortWritePortUchar(Registers->CommandRegister, Opcode); \
+}
diff --git a/private/ntos/miniport/wd7000ex/wd7000ex.rc b/private/ntos/miniport/wd7000ex/wd7000ex.rc
new file mode 100644
index 000000000..217ff3689
--- /dev/null
+++ b/private/ntos/miniport/wd7000ex/wd7000ex.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Future Domain 7000ex SCSI Controller Driver"
+#define VER_INTERNALNAME_STR "fd7000ex.sys"
+#define VER_ORIGINALFILENAME_STR "fd7000ex.sys"
+
+#include "common.ver"
+