123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421 |
- MODULE ATADisks; (** AUTHOR "ml"; PURPOSE "ATA/ATAPI disk driver"; *)
- (*
- * Version based on Disks and ATADisks
- *
- * Aos ATA/ATAPI-6 disk driver with Busmaster suppport.
- *
- * Boot string parameters:
- *
- * ATADetect:
- *
- * Default -> Searches for PCI devices with classcodes for IDE, SATA
- * "legacy" -> Uses controller at addrss 1F0 and 170. No busmaster support.
- * "default" -> Searches for PCI devices with spezial vendor and device ID
- * "raid" -> Searches for PCI devices with classcodes for IDE, SATA, RAID
- * "other" -> Searches for PCI devices with classcodes for IDE, SATA, OTHER
- * "raid+other" -> Searches for PCI devices with classcodes for IDE, SATA, RAID, OTHER
- *
- * ATAForcePIO: Forces PIO mode for ATA devices if set to "1"
- * ATAPIForcePIO: Forces PIO mode for ATAPI devices if set to "1"
- *
- * ATATrace: Enable particular trace options, e.g. ATATrace=5 enables TraceInit, ATATrace=012345 enables all trace options
- * See TraceXXX constants below.
- *
- * dev=nodma Disable DMA transfers for the specified device, e.g. IDE0=nodma
- *
- * History:
- *
- * 05.04.2006 Made trace options accessible using config strings (staubesv)
- * 02.06.2006 Adapted to CD recorder software
- * 26.03.2007 Added NnofReads, NnofWrites, NnofOthers and NnofErrors statistics (staubesv)
- *)
- IMPORT SYSTEM, Machine, KernelLog, Modules, Kernel, Objects, Plugins, Disks, PCI;
- CONST
- Name = "IDE";
- MaxControllers = 10;
- MaxDevicesC = 2;
- MaxDevices = MaxDevicesC*MaxControllers;
- MaxTries = 5;
- MaxTriesDMA = 3;
- (* Enable compilation of trace/debug code? *)
- TraceVerbose = TRUE;
- (* Caution: If changing the constants value, adapt procedure GetOptions *)
- TraceCommands = {0}; (* trace commands *)
- TraceErrors = {1}; (* show error details *)
- TraceAtapi = {2}; (* trace atapi commands *)
- TraceSense = {3}; (* show atapi sense results *)
- TraceBuffer = {4};
- TraceInit = {5};
- TryReset = TRUE;
- InitDevices = TRUE; (* used for ATA-4 or older *)
- AllowManualEject = TRUE; (* Should manual media eject be allowed for devices that are open? *)
- SelectTimeout = 500; (* ms *)
- IOTimeout* = 10000; (* ms *)
- IdentifyTimeout = 2000; (* ms *)
- ResetTimeout = 30000; (* ms *)
- ATAPITimeout* = 5000; (* ms *)
- BS = 512;
- DMABufferSize = 256 * 2048; (* 512 kB *)
- MaxPRD = 32; (* <= 32 *)
- (* According "CF+ and CompactFlash Specification Version 1.4" by CompactFlash Association*)
- CompactFlashSignature = 848AH; (*CF*)
- PageSize = 4096;
- AtapiBit = 0; RemovableBit = 1; DMABit* = 2; LBABit = 3; RMSNBit = 4; Packet16Bit = 5; LBA48Bit = 6; FlushBit = 7;
- CompactFlash = 9; (*CF*)
- ATAPI_DirectAccess = 0; ATAPI_SequentialAccess = 1; ATAPI_Printer = 2; ATAPI_Processor = 3; ATAPI_WriteOnce = 4;
- ATAPI_CDRom = 5; ATAPI_Scanner = 6; ATAPI_OpticalMemory = 7; ATAPI_MediumChanger = 8; ATAPI_Communications = 9;
- Protocol_DMABit = 7; Protocol_No = {}; Protocol_NonData = {1}; Protocol_PIO = {2}; Protocol_PacketPIO* = {3}; Protocol_DeviceReset = {6};
- Protocol_DMA = Protocol_PIO + {Protocol_DMABit};
- Protocol_PacketDMA* = Protocol_PacketPIO + {Protocol_DMABit};
- Device_DEV = 4; Device_LBA = 6;
- Status_ERR = 0; Status_DRQ = 3; Status_DRDY = 6; Status_BSY = 7;
- Control_nIEN = 1; Control_SRST = 2;
- DMA_Start = 0; DMA_Read = 3; DMA_ERR = 1; DMA_IRQ = 2; DMA_Busy = 0;
- Ofs_Features = 1; Ofs_Error = 1; Ofs_Device = 6; Ofs_Status = 7; Ofs_Cmd = 7;
- Ofs_SectorCount = 2; Ofs_SectorNumber = 3; Ofs_CylinderLow = 4; Ofs_CylinderHigh = 5;
- Ofs_LBALow = 3; Ofs_LBAMid = 4; Ofs_LBAHigh = 5;
- Ofs_CountLow = 4; Ofs_CountHigh = 5;
- Ofs_AltStatus = 6; Ofs_Control = 6;
- Ofs_BMCmd = 0; Ofs_BMStatus = 2; Ofs_BMPRDT = 4;
- ATAPI_DMA* = 0;
- ATAPISig = 0EBX;
- Res_OK = 0; Res_Err = 1; Res_Timeout = 2;
- WriteAndVerify* = 3; (* Disks.Read = 1, Disks.Read = 2 *)
- TYPE
- LoadMsg* = RECORD (Disks.Message) END; (** load the media *)
- GetSenseMsg* = RECORD (Disks.Message) sense*, asc*, ascq*: LONGINT; fieldPointer*: ARRAY 3 OF CHAR; END;
- TestUnitReadyMsg* = RECORD (Disks.Message) enable*: BOOLEAN; END;
- WriteCacheMsg* = RECORD (Disks.Message) enable*: BOOLEAN; END;
- CHS = RECORD
- cyls, hds, spt: LONGINT
- END;
- ID* = RECORD
- type*: SET;
- ver, devtype: LONGINT;
- model: ARRAY 44 OF CHAR;
- dmamode, maxdmamode: LONGINT;
- majorVersion: LONGINT;
- END;
- PRDT = POINTER TO RECORD
- prd: ARRAY MaxPRD OF RECORD (* aligned on 32-byte boundary, see Intel 290550-002 sec. 2.7.3 *)
- physAdr, size: LONGINT
- END
- END;
- Command = POINTER TO CommandDesc;
- CommandDesc = RECORD
- dev, cmd, count*, size*, features: LONGINT;
- bufAdr*: ADDRESS;
- read*, buffered: BOOLEAN;
- protocol*: SET;
- prdtPhysAdr: LONGINT;
- prdt: PRDT;
- getResult: BOOLEAN;
- END;
- CommandCHS = POINTER TO CommandCHSDesc;
- CommandCHSDesc = RECORD (CommandDesc)
- sector, head, cylinder: LONGINT;
- END;
- CommandLBA = POINTER TO CommandLBADesc;
- CommandLBADesc = RECORD (CommandDesc)
- lba: LONGINT;
- END;
- CommandLBA48 = POINTER TO CommandLBA48Desc;
- CommandLBA48Desc = RECORD (CommandDesc)
- lbaHigh, lbaLow: LONGINT;
- END;
- CommandPacket = POINTER TO CommandPacketDesc;
- CommandPacketDesc = RECORD (CommandDesc)
- packet*: Packet;
- features*: SET;
- sense, packetLen: LONGINT;
- END;
- Packet = ARRAY 16 OF CHAR;
- TYPE
- Interrupt = OBJECT
- VAR
- int: LONGINT;
- interrupt, timeout: BOOLEAN;
- clock: Objects.Timer;
- PROCEDURE HandleInterrupt;
- BEGIN {EXCLUSIVE}
- interrupt := TRUE;
- INC(irqCount);
- END HandleInterrupt;
- PROCEDURE HandleTimeout;
- BEGIN {EXCLUSIVE}
- timeout := TRUE;
- END HandleTimeout;
- PROCEDURE Wait(ms: LONGINT): BOOLEAN;
- BEGIN {EXCLUSIVE}
- timeout := FALSE;
- Objects.SetTimeout(clock, SELF.HandleTimeout, ms); (* set or reset timeout *)
- AWAIT(interrupt OR timeout);
- Objects.CancelTimeout(clock);
- INC(expectedCount);
- interrupt := FALSE;
- RETURN ~timeout
- END Wait;
- PROCEDURE Reset;
- BEGIN
- interrupt := FALSE
- END Reset;
- PROCEDURE &Init*(irq: LONGINT);
- BEGIN
- interrupt := FALSE; int := Machine.IRQ0 + irq;
- NEW(clock);
- Objects.InstallHandler(SELF.HandleInterrupt, int)
- END Init;
- PROCEDURE Finalize;
- BEGIN
- Objects.RemoveHandler(HandleInterrupt, int);
- Objects.CancelTimeout(clock);
- END Finalize;
- END Interrupt;
- Controller = OBJECT
- VAR
- cmdbase, cnlbase, bmbase, irq: LONGINT;
- interrupt: Interrupt;
- ctrlID, state: LONGINT;
- nIEN: LONGINT;
- prdtPhysAdr: LONGINT;
- prdt: PRDT;
- buffer: POINTER TO ARRAY OF CHAR;
- bufferAdr: ADDRESS;
- PROCEDURE ExecuteCommand*(command: Command; ms: LONGINT; VAR status: SET): LONGINT;
- CONST
- PIO = SYSTEM.VAL(LONGINT, Protocol_PIO);
- DMA = SYSTEM.VAL(LONGINT, Protocol_DMA);
- PacketPIO = SYSTEM.VAL(LONGINT, Protocol_PacketPIO);
- PacketDMA = SYSTEM.VAL(LONGINT, Protocol_PacketDMA);
- DeviceReset = SYSTEM.VAL(LONGINT, Protocol_DeviceReset);
- NonData = SYSTEM.VAL(LONGINT, Protocol_NonData);
- VAR
- res: WORD;
- ch: CHAR;
- dma: BOOLEAN;
- BEGIN {EXCLUSIVE}
- IF state = 1 THEN
- Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
- IF ~(Status_BSY IN status) THEN
- state := 0;
- ELSE
- RETURN Res_Err;
- END;
- END;
- dma := Protocol_DMABit IN command.protocol;
- IF TraceVerbose & (trace * TraceCommands # {}) THEN
- KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC + command.dev, 1);
- KernelLog.String(" Issue: "); KernelLog.Hex(command.cmd, -3);
- IF command IS CommandPacket THEN
- KernelLog.String(", "); KernelLog.Hex(ORD(command(CommandPacket).packet[0]), -2);
- END;
- KernelLog.Ln;
- END;
- IF interrupt # NIL THEN
- interrupt.Reset;
- END;
- res := ProtIssueCommand(command, ms);
- IF res # Res_OK THEN
- (*IF dma THEN
- StopDMA();
- END;*)
- Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
- IF TraceVerbose & (trace * TraceErrors # {}) THEN
- KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC + command.dev, 1);
- KernelLog.String(" Error (issue): Command "); KernelLog.Hex(command.cmd, -2);
- IF command IS CommandPacket THEN
- KernelLog.String(", "); KernelLog.Hex(ORD(command(CommandPacket).packet[0]), -2);
- END;
- KernelLog.String(", Status = "); KernelLog.Hex(ORD(ch), -2); KernelLog.Ln;
- END;
- (*IF status * {Status_BSY, Status_DRQ} # {} THEN
- ignore := ProtSwReset(ResetTimeout);
- END;*)
- RETURN res;
- END;
- IF dma THEN
- res := SetupDMA(command);
- IF res # Res_OK THEN RETURN res; END;
- StartDMA();
- END;
- CASE SYSTEM.VAL(LONGINT, command.protocol) OF
- | NonData: res := ProtNonData(ms, status);
- | PIO: IF command.read THEN res := ProtPIOIn(command.bufAdr, command.count, ms, status);
- ELSE res := ProtPIOOut(command.bufAdr, command.count, ms, status); END;
- | DMA: res := ProtDMA(ms, status);
- | DeviceReset: res := ProtDeviceReset(ms, status);
- | PacketPIO: res := ProtPacketPIO(command(CommandPacket), command.read, command.bufAdr, command.size, ms, status);
- | PacketDMA: res := ProtPacketDMA(command(CommandPacket), ms, status);
- ELSE
- Show("Error invalid protocol"); KernelLog.Int(res, 0); KernelLog.Ln;
- END;
- IF dma THEN
- StopDMA();
- END;
- IF command.getResult THEN
- Show("Returning results not yet implemented"); KernelLog.Ln;
- HALT(Disks.Unsupported);
- END;
- IF res # Res_OK THEN
- Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
- IF TraceVerbose & (trace * TraceErrors # {}) THEN
- KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC + command.dev, 1);
- KernelLog.String(" Error (protocol): Command "); KernelLog.Hex(command.cmd, -2);
- IF command IS CommandPacket THEN
- KernelLog.String(", "); KernelLog.Hex(ORD(command(CommandPacket).packet[0]), -2);
- END;
- KernelLog.String(", Protocol = "); KernelLog.Hex(SYSTEM.VAL(LONGINT, command.protocol), -2);
- KernelLog.String(", Result = ");KernelLog.Int(res, 0);
- KernelLog.String(", Status = "); KernelLog.Hex(ORD(ch), -2);
- IF Status_ERR IN status THEN
- Machine.Portin8(cmdbase+Ofs_Error, ch);
- KernelLog.String(", Error = "); KernelLog.Hex(ORD(ch), -2);
- END;
- KernelLog.Ln;
- END;
- (*IF status * {Status_BSY, Status_DRQ} # {} THEN
- ignore := ProtSwReset(ResetTimeout);
- END;*)
- END;
- IF command.buffered THEN
- SYSTEM.MOVE(bufferAdr, command.bufAdr, command.size);
- END;
- RETURN res;
- END ExecuteCommand;
- PROCEDURE Reset(): LONGINT;
- BEGIN {EXCLUSIVE}
- RETURN ProtSwReset(ResetTimeout);
- END Reset;
- PROCEDURE SetupPRD(command: Command): LONGINT;
- VAR
- i, size, left: LONGINT; bufAdr, physAdr, tmp: ADDRESS;
- BEGIN
- IF TraceVerbose & (trace * TraceBuffer # {}) THEN
- KernelLog.String("bufAdr = "); KernelLog.Hex(command.bufAdr, 0);
- IF ~GetPhysAdr(command.bufAdr, command.size, tmp) THEN
- KernelLog.String(", Split buffer");
- END;
- KernelLog.Ln;
- END;
- (* create prdt *)
- command.prdt := prdt;
- command.prdtPhysAdr := prdtPhysAdr;
- (*IF ~GetPRDAdr(command) THEN KernelLog.String("Create PRD failed (GetPRDAdr)"); KernelLog.Ln; RETURN Res_Err; END;*)
- IF ODD(command.bufAdr) THEN
- command.buffered := TRUE;
- bufAdr := bufferAdr;
- ELSE
- bufAdr := command.bufAdr;
- END;
- size := command.size;
- i := 0;
- LOOP
- IF TraceVerbose & (trace * TraceBuffer # {}) THEN KernelLog.String(" "); KernelLog.Hex(bufAdr, 0); END;
- IF ~GetPhysAdr(bufAdr, 1, physAdr) THEN Show("Setup PRD failed (GetPhysAdr)"); KernelLog.Ln; RETURN Res_Err; END;
- command.prdt.prd[i].physAdr := Machine.Ensure32BitAddress (physAdr);
- IF TraceVerbose & (trace * TraceBuffer # {}) THEN KernelLog.String(", "); KernelLog.Hex(physAdr, 0); END;
- left := 65536 - Machine.Ensure32BitAddress (physAdr MOD 65536); (* should not cross 64k boundary (sec. 3.5.3) *)
- IF TraceVerbose & (trace * TraceBuffer # {})THEN KernelLog.String(", ("); KernelLog.Hex(left, 0); END;
- (* Calculate the max. contiguous physical memory *)
- WHILE ~GetPhysAdr(bufAdr, left, tmp) & (left > 0) DO
- (*left := (left-1) - ((left-1) MOD PageSize);*)
- DEC(left, PageSize);
- IF TraceVerbose & (trace * TraceBuffer # {})THEN KernelLog.String(", "); KernelLog.Hex(left, 0); END;
- END;
- IF TraceVerbose & (trace * TraceBuffer # {})THEN
- IF GetPhysAdr(bufAdr, left+1, tmp) THEN
- KernelLog.String("+");
- END;
- KernelLog.String("), "); KernelLog.Hex(left, 0);
- END;
- IF (left = 0) & (size > 0) THEN Show("Setup PRD failed"); KernelLog.Ln; RETURN Res_Err; END;
- IF left > size THEN left := size END;
- IF TraceVerbose & (trace * TraceBuffer # {})THEN KernelLog.String(", "); KernelLog.Hex(left, 0); KernelLog.Ln; END;
- DEC(size, left);
- IF size = 0 THEN
- command.prdt.prd[i].size := LONGINT(80000000H) + left; (* end marker *)
- EXIT
- END;
- command.prdt.prd[i].size := left;
- INC(bufAdr, left);
- INC(physAdr, left); INC(i);
- IF i = LEN(command.prdt.prd) THEN Show("Setup PRD failed (out of bounds)"); KernelLog.Ln; RETURN Res_Err; END;
- END;
- RETURN Res_OK;
- END SetupPRD;
- PROCEDURE SetupDMA(command: Command): LONGINT;
- VAR
- ch: CHAR;
- s: SET;
- res: WORD;
- BEGIN
- (* Clear Interrupt & Errror *)
- Machine.Portin8(bmbase + Ofs_BMStatus, ch); s := SYSTEM.VAL(SET, ORD(ch));
- s := s * {1..7};
- Machine.Portout8(bmbase + Ofs_BMStatus, CHR(SYSTEM.VAL(LONGINT, s)));
- res := SetupPRD(command);
- IF res # Res_OK THEN RETURN res; END;
- (* Write address of PRDT *)
- Machine.Portout32(bmbase + Ofs_BMPRDT, command.prdtPhysAdr);
- (* Set direction *)
- IF command.read THEN
- ch := CHR(ASH(1, DMA_Read));
- ELSE
- ch := 0X;
- END;
- Machine.Portout8(bmbase + Ofs_BMCmd, ch);
- RETURN Res_OK;
- END SetupDMA;
- PROCEDURE StartDMA;
- VAR ch: CHAR; s: SET;
- BEGIN
- (* START DMA *)
- Machine.Portin8(bmbase + Ofs_BMCmd, ch);
- s := SYSTEM.VAL(SET, ORD(ch));
- INCL(s, DMA_Start);
- Machine.Portout8(bmbase + Ofs_BMCmd, CHR(SYSTEM.VAL(LONGINT, s)));
- END StartDMA;
- PROCEDURE StopDMA;
- VAR ch: CHAR; s: SET;
- BEGIN
- (* Stop DMA *)
- Machine.Portin8(bmbase + Ofs_BMCmd, ch);
- s := SYSTEM.VAL(SET, ORD(ch));
- EXCL(s, DMA_Start);
- Machine.Portout8(bmbase + Ofs_BMCmd, CHR(SYSTEM.VAL(LONGINT, s)));
- (* Clear Interrupt & Errror *)
- Machine.Portin8(bmbase + Ofs_BMStatus, ch); s := SYSTEM.VAL(SET, ORD(ch));
- s := s * {1..7};
- Machine.Portout8(bmbase + Ofs_BMStatus, CHR(SYSTEM.VAL(LONGINT, s)));
- END StopDMA;
- PROCEDURE WaitStatus(mask, expect, bad: SET; ms: LONGINT; VAR status: SET): LONGINT;
- VAR t: Kernel.MilliTimer; ch: CHAR;
- BEGIN
- ASSERT(Status_BSY IN mask);
- Kernel.SetTimer(t, ms);
- LOOP
- Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
- IF ~(Status_BSY IN status) THEN
- IF status * mask = expect THEN EXIT; END;
- END;
- IF Kernel.Expired(t) THEN RETURN Res_Timeout; END;
- END;
- IF status * bad # {} THEN RETURN Res_Err; END;
- RETURN Res_OK;
- END WaitStatus;
- (* Software reset protocol
- States: HSR0(ISet_SRST), HSR1 (Clear_wait), HSR2 (Check_Status) *)
- PROCEDURE ProtSwReset(ms: LONGINT): LONGINT;
- VAR
- t: Kernel.MilliTimer;
- status: SET;
- res: WORD;
- BEGIN
- IF state = 1 THEN RETURN Res_Err; END;
- (* HSR0 *)
- Machine.Portout8(cnlbase+Ofs_Control, CHR(ASH(1, Control_SRST))); (* reset controller *)
- Kernel.SetTimer(t, 1); REPEAT UNTIL Kernel.Expired(t); (* wait > 4.8us *)
- (* HSR1 *)
- Machine.Portout8(cnlbase+Ofs_Control, 0X);
- Kernel.SetTimer(t, 3); REPEAT UNTIL Kernel.Expired(t); (* wait ~2ms *)
- (* HSR0 *)
- res := WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
- IF res # Res_OK THEN state := 1; END;
- RETURN res;
- END ProtSwReset;
- (* Bus idle protocol
- States: HI0(Host_Idle), HI1 (Check_Status), HI2 (Device_Select), HI3 (Write_parameters), HI4(Write_command) *)
- PROCEDURE ProtIssueCommand(cmd: Command; ms: LONGINT): LONGINT;
- VAR
- cmdCHS: CommandCHS;
- cmdLBA: CommandLBA;
- cmdLBA48: CommandLBA48;
- cmdPacket: CommandPacket;
- ch: CHAR;
- status, devReg: SET;
- res: WORD;
- BEGIN
- (* HI1 *)
- res := WaitStatus({Status_BSY, Status_DRQ}, {}, {}, ms, status);
- (*res := WaitStatus({Status_BSY}, {}, {}, ms, status);*)
- (*IF res # Res_OK THEN RETURN res; END;*)
- res := Res_OK;
- IF cmd.dev = 1 THEN devReg := {Device_DEV} ELSE devReg := {}; END;
- Machine.Portin8(cmdbase+Ofs_Device, ch);
- (* Change device? *)
- IF ((SYSTEM.VAL(SET, ORD(ch)) * {Device_DEV}) # devReg)
- (* OR (Status_BSY IN status)*) THEN
- IF TraceVerbose & (trace * TraceCommands # {}) THEN
- KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC + cmd.dev, 1);
- KernelLog.String(" Select device"); KernelLog.Ln;
- END;
- SetInterrupt(FALSE);
- (* HI2 *)
- Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
- (* HI1 *)
- res := WaitStatus({Status_BSY, Status_DRQ}, {}, {}, SelectTimeout, status);
- IF res # Res_OK THEN RETURN res; END;
- SetInterrupt(TRUE);
- END;
- (* HI3 *)
- IF cmd IS CommandCHS THEN
- cmdCHS := cmd(CommandCHS);
- Machine.Portout8(cmdbase+Ofs_Features, CHR(cmdCHS.features));
- Machine.Portout8(cmdbase+Ofs_SectorCount, CHR(cmdCHS.count));
- Machine.Portout8(cmdbase+Ofs_SectorNumber, CHR(cmdCHS.sector));
- Machine.Portout8(cmdbase+Ofs_CylinderLow, CHR(cmdCHS.cylinder MOD 100H));
- Machine.Portout8(cmdbase+Ofs_CylinderHigh, CHR(cmdCHS.cylinder DIV 100H));
- devReg := devReg + SYSTEM.VAL(SET, cmdCHS.head MOD 10H);
- Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
- ELSIF cmd IS CommandLBA THEN
- cmdLBA := cmd(CommandLBA);
- Machine.Portout8(cmdbase+Ofs_Features, CHR(cmdLBA.features));
- Machine.Portout8(cmdbase+Ofs_SectorCount, CHR(cmdLBA.count));
- Machine.Portout8(cmdbase+Ofs_LBALow, CHR(cmdLBA.lba MOD 100H));
- Machine.Portout8(cmdbase+Ofs_LBAMid, CHR((ASH(cmdLBA.lba, -8) MOD 100H)));
- Machine.Portout8(cmdbase+Ofs_LBAHigh, CHR((ASH(cmdLBA.lba, -16) MOD 100H)));
- INCL(devReg, Device_LBA);
- devReg := devReg + SYSTEM.VAL(SET, ASH(cmdLBA.lba, -24) MOD 10H);
- Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
- ELSIF cmd IS CommandLBA48 THEN
- cmdLBA48 := cmd(CommandLBA48);
- (* Previous *)
- Machine.Portout8(cmdbase+Ofs_SectorCount, CHR(ASH(cmdLBA48.count, -8) MOD 100H));
- Machine.Portout8(cmdbase+Ofs_LBALow, CHR((ASH(cmdLBA48.lbaLow, -24) MOD 100H)));
- Machine.Portout8(cmdbase+Ofs_LBAMid, CHR((cmdLBA48.lbaHigh MOD 100H)));
- Machine.Portout8(cmdbase+Ofs_LBAHigh, CHR((ASH(cmdLBA48.lbaHigh, -8) MOD 100H)));
- (* Current *)
- Machine.Portout8(cmdbase+Ofs_SectorCount, CHR(cmdLBA48.count));
- Machine.Portout8(cmdbase+Ofs_LBALow, CHR(cmdLBA48.lbaLow MOD 100H));
- Machine.Portout8(cmdbase+Ofs_LBAMid, CHR((ASH(cmdLBA48.lbaLow, -8) MOD 100H)));
- Machine.Portout8(cmdbase+Ofs_LBAHigh, CHR((ASH(cmdLBA48.lbaLow, -16) MOD 100H)));
- INCL(devReg, Device_LBA);
- Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
- ELSIF cmd IS CommandPacket THEN
- cmdPacket := cmd(CommandPacket);
- Machine.Portout8(cmdbase+Ofs_Features, CHR(SYSTEM.VAL(LONGINT, cmdPacket.features))); (* OVL, DMA *)
- Machine.Portout8(cmdbase+Ofs_SectorCount, 0X); (* tag 0 *)
- Machine.Portout8(cmdbase+Ofs_CountLow, 0FEX); (* byte count limit *)
- Machine.Portout8(cmdbase+Ofs_CountHigh, 0FFX);
- Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
- END;
- (* HI4 *)
- Machine.Portout8(cmdbase+Ofs_Cmd, CHR(cmd.cmd));
- RETURN res;
- END ProtIssueCommand;
- (* Non-data protocol
- States: HND0 (INTRQ_wait), HND1 (Check_Status) *)
- PROCEDURE ProtNonData(ms: LONGINT; VAR status: SET): LONGINT;
- BEGIN
- IF nIEN = 0 THEN
- (* HND0 *)
- IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;
- ELSE
- (* Wait 400ns when entering HND1 form state other than HND0 *)
- NanoDelay(400);
- END;
- (* HND1 *)
- RETURN WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
- END ProtNonData;
- (* PIO data-in protocol
- States: HPIOI0 (INTRQ_wait), HPIOI1 (Check_Status), HPIOI2 (Transfer_Data) *)
- PROCEDURE ProtPIOIn(bufAdr: ADDRESS; num: LONGINT; ms: LONGINT; VAR status: SET): LONGINT;
- VAR state, res: LONGINT; ch: CHAR;
- BEGIN
- res := Res_OK;
- IF nIEN = 1 THEN
- state := 1;
- (* Wait 400ns when entering HPIOI1 *)
- NanoDelay(400);
- END;
- REPEAT
- CASE state OF
- (* HPIOI0 *)
- | 0: BEGIN
- IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;
- state := 1;
- END;
- (* HPIOI1 *)
- | 1: BEGIN
- res := WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
- IF res # Res_OK THEN RETURN res; END;
- IF Status_DRQ IN status THEN
- state:= 2;
- ELSE
- RETURN Res_Err;
- END;
- END;
- (* HPIOI2 *)
- | 2: BEGIN
- RepInWord(cmdbase, bufAdr, BS DIV 2);
- INC(bufAdr, BS); DEC(num);
- IF num <= 0 THEN
- Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
- IF Status_ERR IN status THEN res := Res_Err; END;
- state := -1;
- ELSIF nIEN = 0 THEN
- state := 0;
- ELSE
- state := 1;
- (* Wait 1 PIO transfer cycle when entering HPIOI1 from HPIOI2 *)
- Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
- END;
- END;
- END;
- UNTIL state = -1;
- RETURN res;
- END ProtPIOIn;
- (* PIO data-out Protocol
- States: HPIOO0 (Check_Status), HPIOO1 (Transfer_Data), HPIOO2 (INTRQ_wait) *)
- PROCEDURE ProtPIOOut(bufAdr: ADDRESS; num: LONGINT; ms: LONGINT; VAR status: SET): LONGINT;
- VAR
- state, res: LONGINT;
- ch: CHAR;
- BEGIN
- state := 0;
- REPEAT
- CASE state OF
- (* HPIOO0 *)
- | 0: BEGIN
- res := WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
- IF res # Res_OK THEN RETURN res; END;
- IF Status_DRQ IN status THEN
- state:= 1;
- ELSE
- state := -1;
- END;
- END;
- (* HPIOO1 *)
- | 1: BEGIN
- RepOutWord(cmdbase, bufAdr, BS DIV 2);
- INC(bufAdr, BS); DEC(num);
- IF nIEN = 0 THEN
- state := 2;
- ELSE
- state := 0;
- (* Wait 1 PIO transfer cycle when entering HPIOI1 from HPIOI2 *)
- Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
- END;
- END;
- (* HPIOO2 *)
- | 2: BEGIN
- IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;
- state := 0;
- END;
- END;
- UNTIL state = -1;
- RETURN res;
- END ProtPIOOut;
- (* DMA Protocol
- States: HDMA0 (Check_Status), HDMA1 (Transfer_Data), HDMA2 (INTRQ_wait) *)
- PROCEDURE ProtDMA(ms: LONGINT; VAR status: SET): LONGINT;
- VAR
- ch: CHAR;
- t: Kernel.MilliTimer;
- s: SET;
- BEGIN
- (* Wait 400ns when entering HDMA0 *)
- NanoDelay(400);
- Kernel.SetTimer(t, ms);
- REPEAT
- IF nIEN = 0 THEN
- IF ~interrupt.Wait(ms) THEN (*RETURN Res_Timeout;*) END;
- END;
- Machine.Portin8(bmbase + Ofs_BMStatus, ch); s := SYSTEM.VAL(SET, ORD(ch));
- (*UNTIL (s * {DMA_ERR, DMA_IRQ} # {}) OR Kernel.Expired(t);*)
- UNTIL ~(DMA_Busy IN s) OR Kernel.Expired(t);
- IF DMA_ERR IN s THEN RETURN Res_Err; END;
- (*IF Kernel.Expired(t) THEN RETURN Res_Timeout; END;*)
- REPEAT
- Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
- IF ~(Status_BSY IN status) THEN
- IF Status_ERR IN status THEN RETURN Res_Err; END;
- IF ~(Status_DRQ IN status) THEN RETURN Res_OK; END;
- END;
- (* Wait 1 PIO transfer cycle when entering HDMA0 *)
- Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
- UNTIL Kernel.Expired(t);
- RETURN Res_Timeout;
- END ProtDMA;
- (* Packet PIO Protocol
- States: HP0(Check_Status_A), HP1 (Send_Packet), HP2 (Check_Status_B), HP3 (INTRQ_wait), HP4 (Transfer_Data) *)
- PROCEDURE ProtPacketPIO(command: CommandPacket; read: BOOLEAN; bufAdr: ADDRESS; size: LONGINT; ms: LONGINT; VAR status: SET): LONGINT;
- VAR
- res, count: LONGINT;
- ch: CHAR;
- BEGIN
- (* Wait 400ns *)
- NanoDelay(400);
- (* HP0 *)
- res := WaitStatus({Status_BSY, Status_DRQ}, {Status_DRQ}, {Status_ERR}, ms, status);
- IF res # Res_OK THEN RETURN res; END;
- (* HP1 *)
- RepOutWord(cmdbase, ADDRESSOF(command.packet[0]), command.packetLen DIV 2);
- IF nIEN = 0 THEN
- (* HP3 *)
- (*IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;*)
- ELSE
- (* Wait 1 PIO transfer cycle when entering HP2 from HP1 *)
- Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
- END;
- LOOP
- (* HP2 *)
- res := WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
- IF res # Res_OK THEN EXIT; END;
- IF ~(Status_DRQ IN status) THEN EXIT; END;
- IF size = 0 THEN EXIT; END;
- (* HP4 *)
- Machine.Portin8(cmdbase+Ofs_CountLow, ch);
- count := ORD(ch);
- Machine.Portin8(cmdbase+Ofs_CountHigh, ch);
- INC(count, ASH(ORD(ch), 8));
- IF count > size THEN count := size END;
- (* IF count <= 0 THEN KernelLog.String("count <= 0, size = "); KernelLog.Int(size, 0); KernelLog.Ln; EXIT; END; *)
- IF read THEN
- RepInWord(cmdbase, bufAdr, count DIV 2);
- ELSE
- RepOutWord(cmdbase, bufAdr, count DIV 2);
- END;
- INC(bufAdr, count); DEC(size, count);
- IF nIEN = 0 THEN
- (* HP3 *)
- IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;
- END;
- END;
- IF (res = Res_OK) & (size > 0) THEN res := Res_Err; END;
- RETURN res;
- END ProtPacketPIO;
- (* Packet DMA Protocol
- States: HPD0(Check_Status_A), HPD1 (Send_Packet), HPD2 (Check_Status_B), HPD3 (INTRQ_wait), HPD4 (Transfer_Data) *)
- PROCEDURE ProtPacketDMA(command: CommandPacket; ms: LONGINT; VAR status: SET): LONGINT;
- VAR
- res: WORD;
- ch: CHAR;
- s: SET;
- t: Kernel.MilliTimer;
- BEGIN
- (* Wait 400ns *)
- NanoDelay(400);
- (* HPD0 *)
- res := WaitStatus({Status_BSY, Status_DRQ}, {Status_DRQ}, {Status_ERR}, ms, status);
- IF res # Res_OK THEN RETURN res; END;
- (* HPD1 *)
- RepOutWord(cmdbase, ADDRESSOF(command.packet[0]), command.packetLen DIV 2);
- IF nIEN = 0 THEN
- (* HPD3 *)
- Kernel.SetTimer(t, ms+2);
- REPEAT
- IF ~interrupt.Wait(ms) THEN (*KernelLog.String("***");*) (*RETURN Res_Timeout;*) END;
- Machine.Portin8(bmbase + Ofs_BMStatus, ch); s := SYSTEM.VAL(SET, ORD(ch));
- UNTIL (s * {DMA_ERR, DMA_IRQ} # {}) OR Kernel.Expired(t);
- (* UNTIL ~(DMA_Busy IN s) OR Kernel.Expired(t); *)
- IF DMA_ERR IN s THEN RETURN Res_Err; END;
- IF Kernel.Expired(t) THEN RETURN Res_Timeout; END;
- ELSE
- (* Wait 1 PIO transfer cycle when entering HPD2 from HPD1 *)
- Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
- END;
- (* HPD2 *)
- res := WaitStatus({Status_BSY, Status_DRQ}, {}, {Status_ERR}, ms, status);
- RETURN res;
- END ProtPacketDMA;
- (* Device reset protocol
- States: HDR0 (Wait), HDR1 (Check_Status) *)
- PROCEDURE ProtDeviceReset(ms: LONGINT; VAR status: SET): LONGINT;
- BEGIN
- (* HDR0 *)
- NanoDelay(400);
- (* HDR1 *)
- RETURN WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
- END ProtDeviceReset;
- PROCEDURE SetInterrupt(enable: BOOLEAN);
- VAR i : LONGINT;
- BEGIN
- (* Set nIEN *)
- IF enable & (interrupt # NIL) THEN nIEN := 0; ELSE nIEN := 1; END;
- i := ASH(nIEN, Control_nIEN);
- Machine.Portout8(cnlbase+Ofs_Control, CHR(i));
- END SetInterrupt;
- PROCEDURE CreateDevice(devNum: LONGINT): LONGINT;
- VAR status: SET;
- res: WORD; dev, devATA: Device; devATAPI: DeviceATAPI; ch: CHAR;
- buf: ARRAY BS DIV 2 OF INTEGER;
- command: Command;
- devReg: SET;
- c1, c2: CHAR;
- BEGIN
- (* Select device *)
- IF devNum = 1 THEN devReg := {Device_DEV} ELSE devReg := {}; END;
- Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
- res := WaitStatus({Status_BSY, Status_DRQ}, {}, {}, SelectTimeout, status);
- IF res # Res_OK THEN
- (* Most likely, there is no device .... Show("Could not select device"); KernelLog.Ln; *)
- END;
- (* Check if registers are valid. FAST DETECTION *)
- Machine.Portout8(cmdbase+Ofs_CountLow, 055X);
- NanoDelay(400);
- Machine.Portin8(cmdbase+Ofs_CountLow, c1);
- Machine.Portout8(cmdbase+Ofs_CountLow, 0AAX);
- NanoDelay(400);
- Machine.Portin8(cmdbase+Ofs_CountLow, c2);
- IF (c1 # 055X) OR (c2 # 0AAX) THEN
- IF TraceVerbose & (trace * (TraceErrors + TraceInit) # {}) THEN
- KernelLog.String(", device "); KernelLog.Int(devNum, 0); KernelLog.String(" not present");
- KernelLog.String(" "); KernelLog.Hex(ORD(c1), -2); KernelLog.Hex(ORD(c2), -3);
- END;
- RETURN Res_Err;
- END;
- IF TraceVerbose & (trace * TraceInit # {}) THEN
- KernelLog.String("Identify Device "); KernelLog.Int(devNum,1); KernelLog.Ln;
- END;
- NEW(command);
- command.dev := devNum; command.cmd := 0ECH; (* identify device *)
- command.protocol := Protocol_PIO; command.read := TRUE;
- command.bufAdr := ADDRESSOF(buf[0]); command.count := 1;
- res := ExecuteCommand(command, IdentifyTimeout, status);
- IF TraceVerbose & (trace * TraceInit # {}) THEN
- KernelLog.Ln;
- Show("Identify device commands, res: "); KernelLog.Int(res, 0); KernelLog.String(", status: "); KernelLog.Bits(status, 0, 32);
- KernelLog.Ln;
- END;
- (*IF ~(Status_DRDY IN status) THEN RETURN Res_Err; END;*)
- IF ~(Status_ERR IN status) THEN
- IF res # Res_OK THEN RETURN res; END;
- (* ATA device *)
- NEW(devATA, SELF, devNum, buf);
- dev := devATA;
- ELSE
- Machine.Portin8(cmdbase+Ofs_LBAHigh, ch); (* signature byte *)
- IF ch # ATAPISig THEN RETURN Res_Err; END;
- (* ATAPI device *)
- NEW(command);
- command.dev := devNum; command.cmd := 0A1H; (* identify packet device *)
- command.protocol := Protocol_PIO; command.read := TRUE;
- command.bufAdr := ADDRESSOF(buf[0]); command.count := 1;
- res := ExecuteCommand(command, IdentifyTimeout, status);
- IF TraceVerbose & (trace * TraceInit # {}) THEN
- Show("Identify packet device command, res: "); KernelLog.Int(res, 0); KernelLog.String(", status: "); KernelLog.Bits(status, 0, 32);
- END;
- IF res # Res_OK THEN RETURN res; END;
- NEW(devATAPI, SELF, devNum, buf);
- dev := devATAPI;
- END;
- RETURN res;
- END CreateDevice;
- PROCEDURE InitController;
- VAR p, res: LONGINT; status: SET;
- BEGIN
- res := ProtSwReset(IdentifyTimeout);
- (*IF res # Res_OK THEN
- KernelLog.String(", reset failed");
- SetInterrupt(FALSE);
- RETURN;
- END;*)
- IF bmbase # 0 THEN KernelLog.String(", Bus-master enabled"); END;
- (* Identify Devices *)
- FOR p:=0 TO MaxDevicesC-1 DO
- SetInterrupt(TRUE);
- res := CreateDevice(p);
- SetInterrupt(res = Res_OK);
- END;
- (* Select drive 0 if drive 1 is not present *)
- IF (device[ctrlID*MaxDevicesC] # NIL) & (device[ctrlID*MaxDevicesC + 1] = NIL) THEN
- IF TraceVerbose & (trace * TraceCommands # {}) THEN
- KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC, 1);
- KernelLog.String(".."); KernelLog.Int((ctrlID+1)*MaxDevicesC-1, 1);
- KernelLog.String(" Select device 0"); KernelLog.Ln;
- END;
- Machine.Portout8(cmdbase+Ofs_Device, 0X);
- res := WaitStatus({Status_BSY, Status_DRQ}, {}, {}, SelectTimeout, status);
- IF res # Res_OK THEN KernelLog.String("Select device 0 failed"); KernelLog.Ln; END;
- SetInterrupt(TRUE);
- END;
- END InitController;
- PROCEDURE &Create*(cmd_ba, cnl_ba, bm_ba, airq: LONGINT);
- VAR
- try: LONGINT;
- BEGIN
- cmdbase := cmd_ba; cnlbase := cnl_ba; bmbase := bm_ba; irq := airq;
- state := 0;
- (* init interrupt *)
- interrupt := NIL;
- IF (irq > 0) & (irq <= 15) THEN
- NEW(interrupt, irq);
- ELSE
- KernelLog.Ln; Show("Invalid IRQ assigned"); KernelLog.Ln;
- END;
- SetInterrupt(TRUE);
- (* create buffer *)
- NEW(buffer, DMABufferSize + 1);
- bufferAdr := ADDRESSOF(buffer[0]);
- INC(bufferAdr, 1-(bufferAdr+1) MOD 2);
- (* create PRDT *)
- try := 3;
- REPEAT
- NEW(prdt); (* must not cross page boundary, see Intel 290550-002 sec. 2.7.3 *)
- prdtPhysAdr := Machine.Ensure32BitAddress (Machine.PhysicalAdr(ADDRESSOF(prdt.prd[0]), MaxPRD*8));
- DEC(try);
- UNTIL (try = 0) OR ((prdtPhysAdr # Machine.NilAdr) &
- (prdtPhysAdr DIV PageSize = (prdtPhysAdr+MaxPRD*8-1) DIV PageSize));
- IF ~((prdtPhysAdr # Machine.NilAdr) & (prdtPhysAdr DIV PageSize = (prdtPhysAdr+MaxPRD*8-1) DIV PageSize)) THEN
- KernelLog.Ln; Show("Create PRD failed (GetPRDAdr)"); KernelLog.Ln;
- bmbase := 0;
- END;
- END Create;
- PROCEDURE Finalize;
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO MaxDevices-1 DO
- IF (device[i] # NIL) & (device[i].controller = SELF) THEN
- device[i].Finalize;
- device[i] := NIL;
- END
- END;
- IF interrupt # NIL THEN
- interrupt.Finalize;
- END;
- END Finalize;
- END Controller;
- Device* = OBJECT (Disks.Device)
- VAR
- controller*: Controller;
- dev: LONGINT; (* 0 or 1 *)
- size: LONGINT; (* total size *)
- maxTransfer: LONGINT;
- chs: CHS; (* for conversion LBA -> CHS *)
- getpar: CHS; (* for GetParams *)
- id*: ID;
- init: BOOLEAN; (* initialized? *)
- cmdCHS: CommandCHS;
- cmdLBA: CommandLBA;
- cmdLBA48: CommandLBA48;
- PROCEDURE Transfer*(op, block, num: LONGINT; VAR data: ARRAY OF CHAR; ofs: LONGINT; VAR res: WORD);
- VAR
- num1, try, ignore: LONGINT; bufAdr: ADDRESS;
- dma: BOOLEAN;
- BEGIN
- bufAdr := ADDRESSOF(data[ofs]);
- IF (block >= 0) & (num >= 0) & (block < size) & (block+num <= size) THEN
- ASSERT(num*blockSize <= LEN(data)-ofs); (* range check *)
- WHILE (res = Res_OK) & (num > 0) DO
- try := MaxTries;
- dma := DMABit IN id.type;
- num1 := maxTransfer;
- IF num1 > num THEN num1 := num; END;
- REPEAT
- res := TransferEx(op, block, num1, bufAdr, dma);
- DEC(try);
- IF (res = Disks.WriteProtected) OR (res = Disks.MediaMissing) OR (res = Disks.Unsupported) THEN
- try := 0;
- ELSIF (res # Res_OK) & (try = MaxTriesDMA) & dma THEN
- dma := FALSE;
- Show(name); KernelLog.String(" PIO fallback"); KernelLog.Ln;
- ELSIF (res # Res_OK) & (try = 0) & TryReset THEN
- ignore := Reset();
- END;
- UNTIL (res = Res_OK) OR (try = 0);
- IF Disks.Stats THEN
- BEGIN {EXCLUSIVE}
- IF op = Disks.Read THEN
- INC (NnofReads);
- IF (res = Res_OK) THEN INC (NbytesRead, num1 * blockSize);
- ELSE INC (NnofErrors);
- END;
- ELSIF op = Disks.Write THEN
- INC (NnofWrites);
- IF (res = Res_OK) THEN INC (NbytesWritten, num1 * blockSize);
- ELSE INC (NnofErrors);
- END;
- ELSE
- INC (NnofOthers);
- END;
- END;
- END;
- INC(block, num1); DEC(num, num1); INC(bufAdr, num1*blockSize);
- END;
- ELSE
- Show("ATA: out of range ");
- KernelLog.Address(block); KernelLog.Char(" "); KernelLog.Int(num, 1); KernelLog.Char(" ");
- KernelLog.Int(size, 1); KernelLog.Char(" "); KernelLog.String(name);
- res := 2826 (* transfer out of range *)
- END;
- END Transfer;
- PROCEDURE GetSize*(VAR size, res: LONGINT);
- BEGIN
- size := SELF.size;
- res := Disks.Ok;
- END GetSize;
- PROCEDURE Handle*(VAR msg: Disks.Message; VAR res: WORD);
- BEGIN
- res := Disks.Unsupported;
- IF msg IS Disks.GetGeometryMsg THEN
- WITH msg: Disks.GetGeometryMsg DO
- msg.cyls := getpar.cyls; msg.hds := getpar.hds; msg.spt := getpar.spt
- END;
- res := Disks.Ok
- ELSIF msg IS Disks.LockMsg THEN
- IF (RemovableBit IN id.type) & ~AllowManualEject THEN
- IF MediaLock(TRUE) = Res_OK THEN res := Res_OK; END;
- END;
- ELSIF (msg IS Disks.UnlockMsg) THEN
- IF (RemovableBit IN id.type) THEN
- IF MediaLock(FALSE) = Res_OK THEN res := Res_OK; END;
- END
- ELSIF (msg IS Disks.EjectMsg) THEN
- IF (RemovableBit IN id.type) THEN
- IF MediaEject(TRUE, FALSE) = Res_OK THEN res := Res_OK; END;
- END
- ELSIF (msg IS LoadMsg) THEN
- IF (RemovableBit IN id.type) THEN
- IF MediaEject(TRUE, TRUE) = Res_OK THEN res := Res_OK; END;
- END
- ELSIF (msg IS Disks.SavePowerMsg) THEN
- IF Powersave() = Res_OK THEN res := Res_OK; END;
- ELSIF (msg IS WriteCacheMsg) THEN
- IF SetWriteCache(msg(WriteCacheMsg).enable) THEN res := Res_OK; END;
- END;
- END Handle;
- PROCEDURE SetWriteCache(enable: BOOLEAN): BOOLEAN;
- VAR cmd: Command; status: SET;
- BEGIN {EXCLUSIVE}
- cmd := NewCommand(0EFH, Protocol_NonData);
- IF enable THEN
- cmd.features := 2;
- ELSE
- cmd.features := 82H;
- END;
- RETURN controller.ExecuteCommand(cmd, IOTimeout, status) = Res_OK;
- END SetWriteCache;
- PROCEDURE TransferEx(op: LONGINT; lba: HUGEINT; num: LONGINT; bufAdr: ADDRESS; dma: BOOLEAN): LONGINT;
- VAR command: Command; status: SET;
- BEGIN {EXCLUSIVE}
- IF (op # Disks.Read) & (op # Disks.Write) THEN RETURN Disks.Unsupported; END;
- IF (op = Disks.Write) & (Disks.ReadOnly IN flags) THEN RETURN Disks.WriteProtected; END;
- command := NewCommandTransfer(op, lba, num, bufAdr, dma);
- RETURN controller.ExecuteCommand(command, IOTimeout, status);
- END TransferEx;
- PROCEDURE Reset(): LONGINT;
- VAR res: WORD;
- BEGIN
- IF TraceVerbose & (trace * TraceCommands # {}) THEN Show(name); KernelLog.String(" reset controller"); KernelLog.Ln; END;
- res := controller.Reset();
- IF (TraceVerbose & (trace * TraceErrors # {})) & (res # Res_OK) THEN
- KernelLog.String(name); KernelLog.String(" reset failed"); KernelLog.Ln;
- ELSIF TraceVerbose THEN
- KernelLog.String(name); KernelLog.String(" reset done"); KernelLog.Ln;
- END;
- RETURN res;
- END Reset;
- (* Only for ATA 4 or older *)
- PROCEDURE InitDevice(): LONGINT;
- VAR command: CommandCHS; status: SET;
- BEGIN
- command := cmdCHS;
- command.dev := dev; command.cmd := 91H; command.protocol := Protocol_NonData;
- command.sector := chs.spt;
- command.head := chs.hds;
- RETURN controller.ExecuteCommand(command, IOTimeout, status);
- END InitDevice;
- PROCEDURE Flush(): LONGINT;
- VAR res: WORD;
- BEGIN
- res := Disks.Unsupported;
- IF FlushBit IN id.type THEN
- res := SendATACommand(0E7H, IOTimeout);
- END;
- RETURN res;
- END Flush;
- PROCEDURE MediaEject(immediate, load: BOOLEAN): LONGINT;
- BEGIN {EXCLUSIVE}
- IF ~(RemovableBit IN id.type) THEN RETURN Disks.Unsupported; END;
- RETURN SendATACommand(0EDH, IOTimeout); (* media eject *)
- END MediaEject;
- PROCEDURE MediaLock(lock: BOOLEAN): LONGINT;
- VAR
- command: CommandLBA;
- res: WORD;
- status: SET;
- BEGIN {EXCLUSIVE}
- IF RMSNBit IN id.type THEN
- command := NewCommandLBA(0EFH, 0, 0); (* set features *)
- IF lock THEN
- command.features := 95H; (* enable RMSN *)
- ELSE
- command.features := 31H; (* disable RMSN *)
- END;
- res := controller.ExecuteCommand(command, IOTimeout, status);
- ELSE
- IF lock THEN
- res := SendATACommand(0DEH, IOTimeout); (* media lock *)
- ELSE
- res := SendATACommand(0DFH, IOTimeout); (* media unlock *)
- END;
- END;
- RETURN res;
- END MediaLock;
- PROCEDURE Powersave(): LONGINT;
- BEGIN
- RETURN SendATACommand(0E0H, IOTimeout); (* standby immediate *)
- END Powersave;
- PROCEDURE SendATACommand(cmd, ms: LONGINT): LONGINT;
- VAR command: Command; status: SET;
- BEGIN {EXCLUSIVE}
- command := NewCommand(cmd, Protocol_NonData);
- RETURN controller.ExecuteCommand(command, ms, status);
- END SendATACommand;
- PROCEDURE NewCommand(cmd: LONGINT; protocol: SET): Command;
- VAR command: Command;
- BEGIN
- command := cmdLBA;
- ResetCommand(command, SIZEOF(CommandDesc));
- command.dev := dev; command.cmd := cmd; command.protocol := protocol;
- RETURN command;
- END NewCommand;
- PROCEDURE NewCommandTransfer(op: LONGINT; lba: HUGEINT; count: LONGINT; bufAdr: ADDRESS; dma: BOOLEAN): Command;
- VAR
- CMD: ARRAY 8 OF LONGINT;
- idx: LONGINT;
- command: Command;
- BEGIN
- (* mode std ext dma dma ext
- write 30 34 CA 35
- read 20 24 C8 25
- *)
- CMD[0] := 30H; CMD[1] := 34H; CMD[2] := 0CAH; CMD[3] := 35H;
- CMD[4] := 20H; CMD[5] := 24H; CMD[6] := 0C8H; CMD[7] := 25H;
- IF op = Disks.Read THEN
- INC(idx, 4);
- ELSIF op = Disks.Write THEN
- ELSE
- HALT(Disks.Unsupported);
- END;
- IF dma THEN
- INC(idx, 2);
- END;
- IF LBA48Bit IN id.type THEN
- INC(idx, 1);
- command := NewCommandLBA48(CMD[idx], lba, count);
- ELSIF LBABit IN id.type THEN
- command := NewCommandLBA(CMD[idx], SHORT(lba), count);
- ELSE
- command := NewCommandCHS(CMD[idx], SHORT(lba), count);
- END;
- command.read := op = Disks.Read;
- command.bufAdr := bufAdr;
- command.size := count*blockSize;
- IF dma THEN
- command.protocol := Protocol_DMA;
- ELSE
- command.protocol := Protocol_PIO;
- END;
- RETURN command;
- END NewCommandTransfer;
- PROCEDURE NewCommandCHS(cmd, lba, count: LONGINT): CommandCHS;
- VAR x: LONGINT; command: CommandCHS;
- BEGIN
- command := cmdCHS;
- ResetCommand(command, SIZEOF(CommandCHSDesc));
- command.dev := dev; command.cmd := cmd;
- command.count := count;
- command.sector := lba MOD chs.spt + 1; x := lba DIV chs.spt;
- command.head := x MOD chs.hds; command.cylinder := x DIV chs.hds;
- ASSERT((command.sector < 100H) & (command.cylinder < 10000H) & (command.head < 10H));
- RETURN command;
- END NewCommandCHS;
- PROCEDURE NewCommandLBA(cmd, lba, count: LONGINT): CommandLBA;
- VAR command: CommandLBA;
- BEGIN
- command := cmdLBA;
- ResetCommand(command, SIZEOF(CommandLBADesc));
- command.dev := dev; command.cmd := cmd;
- command.lba := lba; command.count := count;
- RETURN command;
- END NewCommandLBA;
- PROCEDURE NewCommandLBA48(cmd: LONGINT; lba: HUGEINT; count: LONGINT): CommandLBA48;
- VAR command: CommandLBA48;
- BEGIN
- command := cmdLBA48;
- ResetCommand(command, SIZEOF(CommandLBA48Desc));
- command.dev := dev; command.cmd := cmd;
- command.lbaHigh := SHORT(ASH(lba, -32));command.lbaLow := SHORT(lba); command.count := count;
- RETURN command;
- END NewCommandLBA48;
- (* Identify an ATA device. *)
- PROCEDURE IdentifyDevice(buf: ARRAY OF INTEGER): LONGINT;
- VAR res, size1, hsize: LONGINT;
- BEGIN
- (* ATA 4 or older *)
- chs.cyls := LONG(buf[1]) MOD 10000H;
- chs.hds := LONG(buf[3]) MOD 10000H;
- chs.spt := LONG(buf[6]) MOD 10000H;
- size := chs.cyls * chs.hds * chs.spt;
- maxTransfer := 256;
- IF IdentifyMajorVersion(buf, id) # Res_OK THEN RETURN Res_Err; END;
- (* LBA *)
- IF 9 IN SYSTEM.VAL(SET, buf[49]) THEN
- size1 := ASH(LONG(buf[61]) MOD 10000H, 16) + LONG(buf[60]) MOD 10000H;
- IF size < size1 THEN size := size1 END;
- INCL(id.type, LBABit);
- ELSE
- KernelLog.String(", LBA not supported");
- END;
- (* LBA 48 *)
- IF 10 IN SYSTEM.VAL(SET, buf[83]) THEN
- hsize := ASH(LONG(buf[103]) MOD 10000H, 16) + LONG(buf[102]) MOD 10000H;
- size1 := ASH(LONG(buf[101]) MOD 10000H, 16) + LONG(buf[100]) MOD 10000H;
- IF hsize > 0 THEN res := 2826; END; (* size only 32-bit *)
- IF size < size1 THEN size := size1 END;
- maxTransfer := 65536;
- INCL(id.type, LBA48Bit);
- END;
- getpar := chs;
- IF size > 16383*16*63 THEN
- getpar.cyls := size DIV (getpar.hds*getpar.spt);
- END;
- (* DMA support mandatory since ATA 4 except for CF *)
- IF ~ataForcePio & (8 IN SYSTEM.VAL(SET, buf[49])) THEN
- INCL(id.type, DMABit);
- res := IdentifyDMA(buf, id);
- ELSE
- KernelLog.String(", DMA not supported");
- END;
- IF SYSTEM.VAL(SET, LONG(buf[0])) * {6,7} = {7} THEN
- INCL(id.type, RemovableBit);
- IF (4 IN SYSTEM.VAL(SET, LONG(buf[83]))) OR (0 IN SYSTEM.VAL(SET, LONG(buf[127]))) THEN INCL(id.type, RMSNBit) END;
- END;
- (* flush cache *)
- IF 12 IN SYSTEM.VAL(SET, buf[83]) THEN
- INCL(id.type, FlushBit);
- END;
- IF LONG(buf[0]) MOD 10000H = CompactFlashSignature THEN (*CF*)
- INCL(id.type, CompactFlash);
- KernelLog.String(", Compact Flash"); KernelLog.Ln;
- END;
- GetATAString(buf, 27, 46, id.model);
- IF (buf[80] # -1) & (buf[81] # -1) THEN
- id.ver := ASH(LONG(buf[80]) MOD 10000H, 16) + LONG(buf[81]) MOD 10000H
- END;
- IF ~(LBABit IN id.type) & ~((chs.hds <= 16) & (chs.spt <= 255)) THEN
- KernelLog.String("2825 identify ata geometry bad"); KernelLog.Ln;
- res := 2825;
- END;
- IF maxTransfer > DMABufferSize DIV BS THEN maxTransfer := DMABufferSize DIV BS; END;
- RETURN res
- END IdentifyDevice;
- PROCEDURE ShowDevice;
- VAR
- i: LONGINT;
- BEGIN
- KernelLog.String(name); KernelLog.String(": ");
- KernelLog.Int(size DIV (1024*1024 DIV blockSize), 1); KernelLog.String("MB");
- IF LBABit IN id.type THEN
- IF LBA48Bit IN id.type THEN KernelLog.String(", LBA48") ELSE KernelLog.String(", LBA") END;
- ELSE
- KernelLog.String(", "); ShowCHS(chs);
- IF (getpar.cyls # chs.cyls) OR (getpar.hds # chs.hds) OR (getpar.spt # chs.spt) THEN
- KernelLog.String(", ("); ShowCHS(getpar); KernelLog.Char(")")
- END
- END;
- IF CompactFlash IN id.type THEN KernelLog.String(", CompactFlash") END; (*CF*)
- IF RemovableBit IN id.type THEN KernelLog.String(", removable") END;
- IF RMSNBit IN id.type THEN KernelLog.String(" (RMSN)") END;
- IF id.majorVersion > 0 THEN KernelLog.String(", ATA/ATAPI-"); KernelLog.Int(id.majorVersion, 0); END;
- IF DMABit IN id.type THEN
- (*IF id.maxdmamode < 10 THEN
- KernelLog.String(", MW DMA "); KernelLog.Int(id.maxdmamode, 1);
- ELSE
- KernelLog.String(", Ultra DMA "); KernelLog.Int(id.maxdmamode-10, 1);
- END;*)
- IF id.dmamode < 10 THEN
- KernelLog.String(", MW DMA "); KernelLog.Int(id.dmamode, 1);
- ELSE
- KernelLog.String(", Ultra DMA "); KernelLog.Int(id.dmamode-10, 1);
- END;
- ELSE
- KernelLog.String(", no DMA")
- END;
- KernelLog.String(", "); KernelLog.String(id.model);
- IF id.ver # 0 THEN
- KernelLog.String(", ver ");
- i := 30; WHILE (i # 16) & ~ODD(ASH(id.ver, -i)) DO DEC(i) END;
- KernelLog.Int(i-16, 1);KernelLog.Char(".");
- KernelLog.Int(id.ver MOD 10000H, 1)
- END;
- KernelLog.Ln;
- END ShowDevice;
- PROCEDURE &Create*(acontroller: Controller; adev: LONGINT; identifyDevice: ARRAY OF INTEGER);
- VAR
- name: Plugins.Name;
- str: ARRAY 32 OF CHAR;
- i, res: LONGINT;
- BEGIN
- name := Name;
- i := 0; WHILE name[i] # 0X DO INC(i) END;
- name[i] := CHR(48 + acontroller.ctrlID*MaxDevicesC + adev); name[i+1] := 0X;
- SetName(name);
- controller := acontroller; dev := adev; init := FALSE;
- NEW(cmdCHS); NEW(cmdLBA); NEW(cmdLBA48);
- blockSize := BS;
- res := IdentifyDevice(identifyDevice);
- COPY(id.model, desc);
- Machine.GetConfig(name, str);
- IF (controller.bmbase = 0) OR (str="nodma") THEN
- EXCL(id.type, DMABit);
- END;
- IF str="CHS" THEN
- EXCL(id.type, LBABit);
- EXCL(id.type, LBA48Bit);
- END;
- IF InitDevices & (res = Res_OK) & (id.type * {LBABit, AtapiBit} = {}) (*& (id.majorVersion > 0)*) & (id.majorVersion <= 4) THEN
- res := InitDevice();
- KernelLog.Ln; Show("InitDevice, res: "); KernelLog.Int(res, 0);
- END;
- device[acontroller.ctrlID*MaxDevicesC + adev] := SELF;
- (* register device *)
- flags := {};
- IF RemovableBit IN id.type THEN INCL(flags, Disks.Removable) END;
- IF str="ro" THEN INCL(flags, Disks.ReadOnly); END;
- IF res # Res_OK THEN INCL(flags, Disks.ReadOnly); KernelLog.Ln; Show("Error RO"); END;
- Disks.registry.Add(SELF, res);
- ASSERT(res = Plugins.Ok);
- END Create;
- PROCEDURE Finalize;
- VAR res: WORD;
- BEGIN
- (* unregister device *)
- Disks.registry.Remove(SELF);
- res := Flush();
- device[controller.ctrlID*MaxDevicesC + dev] := NIL;
- END Finalize;
- END Device;
- TYPE
- DeviceATAPI* = OBJECT (Device)
- VAR
- sense, asc, ascq: LONGINT;
- fieldPointer: ARRAY 3 OF CHAR;
- cmdPacket: CommandPacket;
- (* for writing audio tracks block size needs being set explicitely to 2352 *)
- PROCEDURE SetBlockSize*(size: LONGINT);
- BEGIN
- blockSize := size;
- END SetBlockSize;
- (* ReadCapacity returns 1 for empty disks *)
- PROCEDURE SetCapacity*(cap: LONGINT);
- BEGIN
- size := cap;
- END SetCapacity;
- PROCEDURE GetSize*(VAR asize, res: LONGINT);
- BEGIN
- res := Res_OK;
- IF RemovableBit IN id.type THEN
- BEGIN {EXCLUSIVE}
- res := WaitUntilReady();
- (*IF res # Res_OK THEN ProcessSense(res); RETURN; END;*)
- res := ReadCapacity(blockSize, size);
- IF (res = Res_OK) & (id.devtype = ATAPI_CDRom) & (blockSize # 2048) THEN blockSize := 2048 END; (* user data field only *)
- ProcessSense(res);
- END;
- END;
- IF res = Res_OK THEN
- GetSize^(asize, res);
- END;
- END GetSize;
- PROCEDURE Handle*(VAR msg: Disks.Message; VAR res: WORD);
- BEGIN
- res := Disks.Unsupported;
- IF msg IS Disks.GetGeometryMsg THEN
- ELSIF msg IS GetSenseMsg THEN
- ProcessSense(res);
- WITH msg: GetSenseMsg DO
- msg.sense := sense; msg.asc := asc; msg.ascq := ascq;
- COPY(fieldPointer, msg.fieldPointer);
- END;
- sense := -1;
- ELSIF msg IS TestUnitReadyMsg THEN
- res := TestUnitReady();
- ProcessSense(res);
- ELSE
- Handle^(msg, res);
- END
- END Handle;
- PROCEDURE ExecuteCommand*(read: BOOLEAN; VAR packet, data: ARRAY OF CHAR; ofs, size: LONGINT; dma: BOOLEAN): LONGINT;
- VAR
- command: CommandPacket;
- i, res: LONGINT;
- status: SET;
- BEGIN {EXCLUSIVE}
- ASSERT(LEN(packet) <= LEN(command.packet));
- ASSERT(size <= LEN(data)-ofs); (* range check *)
- command := cmdPacket;
- command.packetLen := LEN(packet);
- command.dev := dev; command.cmd := 0A0H;
- IF dma THEN
- command.protocol := Protocol_PacketDMA;
- ELSE
- command.protocol := Protocol_PacketPIO;
- END;
- command.read := read;
- command.bufAdr := ADDRESSOF(data[ofs]);
- command.size := size;
- FOR i:= 0 TO LEN(command.packet)-1 DO
- command.packet[i] := packet[i];
- END;
- res := controller.ExecuteCommand(command, ATAPITimeout, status);
- sense := -1;
- ProcessSense(res);
- RETURN res;
- END ExecuteCommand;
- PROCEDURE ProcessSense(VAR res: WORD);
- BEGIN
- IF res = Res_OK THEN
- sense := 0; asc := 0; ascq := 0;
- ELSIF res # Res_OK THEN
- res := 2831;
- IF sense <= 0 THEN
- IF RequestSense() = Res_OK THEN END;
- END;
- IF sense > 0 THEN
- res := 2832;
- IF (asc = 27H) THEN res := Disks.WriteProtected;
- ELSIF (asc = 28H) & (ascq = 0) THEN res := Disks.MediaChanged;
- ELSIF (asc = 3AH) THEN res := Disks.MediaMissing; END;
- END;
- END;
- END ProcessSense;
- PROCEDURE TransferEx*(op: LONGINT; lba: HUGEINT; num: LONGINT; bufAdr: ADDRESS; dma: BOOLEAN): LONGINT;
- VAR
- command: Command;
- res, timeout: LONGINT;
- status: SET;
- BEGIN {EXCLUSIVE}
- IF (op # Disks.Read) & (op # Disks.Write) & (op # WriteAndVerify) THEN RETURN Disks.Unsupported; END;
- IF ((op = Disks.Write) OR (op = WriteAndVerify)) & (Disks.ReadOnly IN flags) THEN RETURN Disks.WriteProtected; END;
- res := WaitUntilReady();
- command := NewCommandPacketTransfer(op, lba, num, bufAdr, num*blockSize, dma);
- IF op = Disks.Read THEN
- timeout := IOTimeout;
- ELSE
- (* first write needs more time on some drives *)
- timeout := 4*IOTimeout;
- END;
- res := controller.ExecuteCommand(command, timeout, status);
- sense := -1;
- ProcessSense(res);
- RETURN res;
- END TransferEx;
- PROCEDURE WaitUntilReady(): LONGINT;
- VAR res: WORD; retry: BOOLEAN;
- BEGIN
- REPEAT
- retry := FALSE;
- res := TestUnitReady();
- IF res # Res_OK THEN
- (*IF res = Res_Err THEN*)
- IF RequestSense() = Res_OK THEN
- retry := (asc = 29H) OR ((asc = 4) & (ascq = 1)) OR ((asc = 28H) & (ascq = 0));
- END;
- IF retry THEN Objects.Yield(); END;
- END;
- UNTIL ~retry;
- res := Res_OK;
- RETURN res;
- END WaitUntilReady;
- (* ATAPI funtions *)
- PROCEDURE Reset(): LONGINT;
- VAR
- i, res : LONGINT;
- status: SET;
- command: Command;
- BEGIN
- IF TraceVerbose & (trace * (TraceCommands + TraceAtapi) # {}) THEN
- KernelLog.String(name); KernelLog.String(" device reset"); KernelLog.Ln;
- END;
- command := NewCommand(8, Protocol_DeviceReset); (* Device Reset *)
- res := controller.ExecuteCommand(command, ResetTimeout, status); (* reset packet device *)
- sense := -1;
- IF TraceVerbose THEN
- IF (trace * TraceErrors # {}) & (res # Res_OK) THEN
- KernelLog.String(name); KernelLog.String(" reset failed"); KernelLog.Ln;
- ELSIF (trace * (TraceCommands + TraceAtapi) # {}) THEN
- KernelLog.String(name); KernelLog.String(" done"); KernelLog.Ln;
- END;
- END;
- IF RequestSense() # Res_OK THEN
- IF res # Res_OK THEN res := Reset^(); END;
- END;
- IF res # Res_OK THEN RETURN 2816; END;
- GetSize(i, i);
- (*undocumented: the first command after Reset Device shall be a PACKET command, other
- commands like Set Features otherwise abort.*)
- RETURN Res_OK;
- END Reset;
- PROCEDURE RequestSense*(): LONGINT;
- VAR
- command: CommandPacket;
- buf: ARRAY 18 OF CHAR;
- res: WORD;
- status: SET;
- BEGIN
- IF TraceVerbose & (trace * (TraceCommands + TraceAtapi) # {}) THEN
- Show(name); KernelLog.String(" request sense"); KernelLog.Ln;
- END;
- sense := -1;
- command := NewCommandPacket(03H);
- command.protocol := Protocol_PacketPIO;
- command.read := TRUE;
- command.bufAdr := ADDRESSOF(buf[0]);
- command.size := LEN(buf);
- command.packet[4] := CHR(LEN(buf));
- res := controller.ExecuteCommand(command, ATAPITimeout, status);
- IF TraceVerbose & (trace * (TraceErrors + TraceSense) # {}) & (res # Res_OK) THEN
- Show(name); KernelLog.String(" request sense failed"); KernelLog.Ln;
- END;
- IF res # Res_OK THEN RETURN res; END;
- sense := ORD(buf[2]) MOD 10H;
- asc := ORD(buf[12]);
- ascq := ORD(buf[13]);
- fieldPointer[0] := buf[15]; fieldPointer[1] := buf[16]; fieldPointer[2] := buf[17];
- IF TraceVerbose & (trace * TraceSense # {}) THEN
- KernelLog.String(name); KernelLog.String(" request sense: ");
- KernelLog.Hex(sense, -2); KernelLog.String(", ");
- KernelLog.Hex(asc, -2); KernelLog.String(", ");
- KernelLog.Hex(ascq, -2);
- KernelLog.String(", "); KernelLog.Int(res, 0);
- KernelLog.Ln;
- END;
- RETURN Res_OK;
- END RequestSense;
- PROCEDURE TestUnitReady*(): LONGINT;
- VAR
- command: CommandPacket;
- res: WORD;
- status: SET;
- BEGIN
- IF TraceVerbose & (trace * (TraceCommands + TraceAtapi) # {}) THEN
- Show(name); KernelLog.String(" test unit ready");KernelLog.Ln;
- END;
- command := NewCommandPacket(00H);
- command.protocol := Protocol_PacketPIO;
- command.read := TRUE;
- res := controller.ExecuteCommand(command, ATAPITimeout, status);
- sense := -1;
- IF TraceVerbose & (trace * TraceErrors # {}) & (res # Res_OK) THEN
- KernelLog.String(name); KernelLog.String(" not ready "); KernelLog.Int(res, 0); KernelLog.Ln;
- END;
- RETURN res;
- END TestUnitReady;
- PROCEDURE Flush(): LONGINT;
- BEGIN
- RETURN Flush^();
- END Flush;
- PROCEDURE MediaEject*(immediate, load: BOOLEAN): LONGINT;
- VAR
- command: CommandPacket;
- res, timeout: LONGINT;
- status: SET;
- BEGIN {EXCLUSIVE}
- command := NewCommandPacket(1BH); (* start/stop unit *)
- command.protocol := Protocol_PacketPIO;
- IF immediate THEN
- command.packet[1] := 1X; (* return immediately *)
- timeout := ATAPITimeout;
- ELSE
- timeout := 4*ATAPITimeout;
- END;
- IF load THEN
- command.packet[4] := 3X; (* load medium *)
- ELSE
- command.packet[4] := 2X; (* eject medium *)
- END;
- res := controller.ExecuteCommand(command, timeout, status);
- sense := -1;
- (*IF res # Res_OK THEN
- res := MediaEject^(load);
- END;*)
- ProcessSense(res);
- RETURN res;
- END MediaEject;
- PROCEDURE MediaLock*(lock: BOOLEAN): LONGINT;
- VAR
- command: CommandPacket;
- res: WORD;
- status: SET;
- BEGIN {EXCLUSIVE}
- command := NewCommandPacket(1EH); (* prevent/allow medium removal *)
- command.protocol := Protocol_PacketPIO;
- IF lock THEN
- command.packet[4] := 1X; (* 1: lock medium, 0: unlock medium *)
- END;
- res := controller.ExecuteCommand(command, ATAPITimeout, status);
- sense := -1;
- ProcessSense(res);
- RETURN res;
- END MediaLock;
- PROCEDURE Powersave(): LONGINT;
- VAR
- command: CommandPacket;
- res: WORD;
- status: SET;
- BEGIN {EXCLUSIVE}
- command := NewCommandPacket(1BH); (* start/stop unit *)
- command.protocol := Protocol_PacketPIO;
- command.packet[1] := 1X; (* return immediately *)
- command.packet[4] := 0X; (* stop medium *)
- res := controller.ExecuteCommand(command, ATAPITimeout, status);
- sense := -1;
- ProcessSense(res);
- RETURN res;
- END Powersave;
- PROCEDURE ReadCapacity*(VAR blkSize, size: LONGINT): LONGINT;
- VAR
- buf: ARRAY 2 OF LONGINT; res, sense: LONGINT;
- command: CommandPacket; status: SET;
- BEGIN
- IF TraceVerbose & (trace * (TraceCommands + TraceAtapi + TraceInit) # {}) THEN
- Show(name); KernelLog.String(" read capacity");KernelLog.Ln;
- END;
- command := NewCommandPacket(25H);
- command.protocol := Protocol_PacketPIO;
- command.read := TRUE;
- command.bufAdr := ADDRESSOF(buf[0]);
- command.size := 8;
- res := controller.ExecuteCommand(command, ATAPITimeout, status);
- sense := -1;
- IF TraceVerbose & (trace * (TraceErrors + TraceInit) # {}) & (res # Res_OK) THEN
- Show(name); KernelLog.String(" read capacity failed "); KernelLog.Int(res, 0); KernelLog.Ln;
- END;
- IF res # Res_OK THEN RETURN res; END;
- size := buf[0]; blkSize := buf[1];
- Swap(size); Swap(blkSize);
- INC(size); (*read capacity returns the last sector*)
- IF TraceVerbose & (trace * (TraceCommands + TraceAtapi + TraceInit) # {}) THEN
- Show(name); KernelLog.String(" read capacity ");
- KernelLog.Int(size*blkSize, 4); KernelLog.String(" Bytes"); KernelLog.Ln;
- END;
- RETURN res
- END ReadCapacity;
- PROCEDURE NewCommandPacketTransfer(op: LONGINT; lba: HUGEINT; count: LONGINT; bufAdr: ADDRESS; size: LONGINT; dma: BOOLEAN): CommandPacket;
- VAR
- command: CommandPacket;
- i, lbaLow, lbaHigh: LONGINT;
- BEGIN
- command := cmdPacket;
- ResetCommand(command, SIZEOF(CommandPacketDesc));
- FOR i:= 0 TO LEN(command.packet)-1 DO
- command.packet[i] := 0X;
- END;
- command.packetLen := 12;
- command.dev := dev; command.cmd := 0A0H;
- command.read := (op = Disks.Read);
- command.count := count;
- command.bufAdr := bufAdr;
- command.size := size;
- IF dma THEN
- command.protocol := Protocol_PacketDMA;
- INCL(command.features, ATAPI_DMA);
- ELSE
- command.protocol := Protocol_PacketPIO;
- END;
- CASE op OF
- Disks.Read: command.packet[0] := 28X; (* 0A8X *)
- | Disks.Write : command.packet[0] := 2AX; (* 0AAX *)
- | WriteAndVerify: command.packet[0] := 2EX;
- ELSE HALT(Disks.Unsupported);
- END;
- lbaLow := SHORT(lba);
- lbaHigh := SHORT(ASH(lba, -32));
- ASSERT((lbaHigh = 0) OR (lbaHigh = -1)); (* negative value possible for raw writing *)
- command.packet[2] := CHR(ASH(lbaLow, -24) MOD 100H);
- command.packet[3] := CHR(ASH(lbaLow, -16) MOD 100H);
- command.packet[4] := CHR(ASH(lbaLow, -8) MOD 100H);
- command.packet[5] := CHR(lbaLow MOD 100H);
- (* 28, 2A *)
- command.packet[7] := CHR(ASH(count, -8) MOD 100H);
- command.packet[8] := CHR(count MOD 100H);
- (* A8, AA *)
- (*command.packet[6] := CHR(ASH(count, -24) MOD 100H);
- command.packet[7] := CHR(ASH(count, -16) MOD 100H);
- command.packet[8] := CHR(ASH(count, -8) MOD 100H);
- command.packet[9] := CHR(count MOD 100H);*)
- RETURN command;
- END NewCommandPacketTransfer;
- PROCEDURE NewCommandPacket*(cmd: LONGINT): CommandPacket;
- VAR
- command: CommandPacket;
- i: LONGINT;
- BEGIN
- command := cmdPacket;
- ResetCommand(command, SIZEOF(CommandPacketDesc));
- FOR i:= 0 TO LEN(command.packet)-1 DO
- command.packet[i] := 0X;
- END;
- command.packetLen := 12;
- command.dev := dev; command.cmd := 0A0H;
- command.packet[0] := CHR(cmd);
- RETURN command;
- END NewCommandPacket;
- PROCEDURE IdentifyDevice(buf: ARRAY OF INTEGER): LONGINT;
- VAR res : WORD;
- BEGIN
- maxTransfer := 65535;
- IF 7 IN SYSTEM.VAL(SET, LONG(buf[0])) THEN (* removable *)
- INCL(id.type, RemovableBit);
- (* RMSN *)
- IF (4 IN SYSTEM.VAL(SET, LONG(buf[83]))) OR (0 IN SYSTEM.VAL(SET, LONG(buf[127]))) THEN INCL(id.type, RMSNBit) END;
- END;
- IF 0 IN SYSTEM.VAL(SET, LONG(buf[0])) THEN
- (* packet 16 byte *)
- INCL(id.type, Packet16Bit);
- END;
- IF ~atapiForcePio & ( 8 IN SYSTEM.VAL(SET, LONG(buf[49]))) THEN
- (* DMA *)
- INCL(id.type, DMABit);
- res := IdentifyDMA(buf, id);
- END;
- (* flush cache *)
- IF 12 IN SYSTEM.VAL(SET, buf[83]) THEN
- INCL(id.type, FlushBit);
- END;
- IF LONG(buf[0]) MOD 10000H = CompactFlashSignature THEN INCL(id.type, CompactFlash) END; (*CF*)
- GetATAString(buf, 27, 46, id.model);
- id.devtype := ASH(buf[0], -8) MOD 20H;
- IF (buf[80] # -1) & (buf[81] # -1) THEN
- id.ver := ASH(LONG(buf[80]) MOD 10000H, 16) + LONG(buf[81]) MOD 10000H
- END;
- IF Packet16Bit IN id.type THEN
- Show("2833 ATAPI: unsupported packet size"); KernelLog.Ln;
- res := 2833;
- ELSE
- res := Res_OK;
- END;
- IF maxTransfer > DMABufferSize DIV 2048 THEN maxTransfer := DMABufferSize DIV 2048; END;
- RETURN res
- END IdentifyDevice;
- PROCEDURE ShowDevice;
- VAR i: LONGINT;
- BEGIN
- KernelLog.String(name); KernelLog.String(": ");
- KernelLog.String("ATAPI");
- IF Packet16Bit IN id.type THEN KernelLog.String(" (16bit)") END;
- ShowDevType(id.devtype);
- IF CompactFlash IN id.type THEN KernelLog.String(", CompactFlash") END; (*CF*)
- IF RemovableBit IN id.type THEN KernelLog.String(", removable") END;
- IF RMSNBit IN id.type THEN KernelLog.String(" (RMSN)") END;
- IF id.majorVersion > 0 THEN KernelLog.String(", ATA/ATAPI-"); KernelLog.Int(id.majorVersion, 0); END;
- IF DMABit IN id.type THEN
- (*IF id.maxdmamode < 10 THEN
- KernelLog.String(", MW DMA "); KernelLog.Int(id.maxdmamode, 1);
- ELSE
- KernelLog.String(", Ultra DMA "); KernelLog.Int(id.maxdmamode-10, 1);
- END;*)
- IF id.dmamode < 10 THEN
- KernelLog.String(", MW DMA ");KernelLog.Int(id.dmamode, 1);
- ELSE
- KernelLog.String(", Ultra DMA "); KernelLog.Int(id.dmamode-10, 1);
- END;
- ELSE
- KernelLog.String(", no DMA")
- END;
- KernelLog.String(", "); KernelLog.String(id.model);
- IF id.ver # 0 THEN
- KernelLog.String(", ver ");
- i := 30; WHILE (i # 16) & ~ODD(ASH(id.ver, -i)) DO DEC(i) END;
- KernelLog.Int(i-16, 1); KernelLog.Char(".");
- KernelLog.Int(id.ver MOD 10000H, 1)
- END;
- KernelLog.Ln;
- END ShowDevice;
- PROCEDURE &Create*(acontroller: Controller; adev: LONGINT; identifyDevice: ARRAY OF INTEGER);
- VAR res: WORD;
- BEGIN
- INCL(id.type, AtapiBit);
- NEW(cmdPacket);
- Create^(acontroller, adev, identifyDevice);
- (* CD_ROM by default ReadOnly *)
- IF id.devtype = ATAPI_CDRom THEN INCL(flags, Disks.ReadOnly); END;
- res := Reset();
- init := TRUE;
- END Create;
- PROCEDURE Finalize;
- BEGIN
- Finalize^();
- END Finalize;
- END DeviceATAPI;
- VAR
- controller: ARRAY MaxControllers OF Controller;
- device: ARRAY MaxDevices OF Device;
- nofControllers: LONGINT;
- installed: BOOLEAN;
- irqCount, expectedCount: LONGINT;
- (* Options that can be set using boot config strings *)
- ataForcePio : BOOLEAN;
- atapiForcePio : BOOLEAN;
- trace* : SET;
- (* Block port input instruction. *)
- PROCEDURE -RepInWord(port, bufAdr: ADDRESS; len: SIZE);
- CODE {SYSTEM.AMD64}
- POP RCX
- POP RDI
- POP RDX
- CLD
- REP INSW
- END RepInWord;
- (* Block port out instruction. *)
- PROCEDURE -RepOutWord(port, bufAdr: ADDRESS; len: SIZE);
- CODE {SYSTEM.AMD64}
- POP RCX
- POP RSI
- POP RDX
- CLD
- REP OUTSW
- END RepOutWord;
- PROCEDURE ResetCommand(cmd: Command; size: SIZE);
- BEGIN
- ASSERT(cmd # NIL);
- ASSERT(size MOD 4 = 0);
- Machine.Fill32(SYSTEM.VAL(ADDRESS, cmd), size, 0);
- END ResetCommand;
- PROCEDURE GetPhysAdr(bufAdr: ADDRESS; size: LONGINT; VAR physAdr: ADDRESS): BOOLEAN;
- BEGIN
- physAdr := Machine.PhysicalAdr(bufAdr, size);
- RETURN physAdr # Machine.NilAdr
- END GetPhysAdr;
- (*PROCEDURE GetPRDAdr(VAR c: Command): BOOLEAN;
- VAR p: LONGINT;
- BEGIN
- NEW(c.prdt); (* must not cross page boundary, see Intel 290550-002 sec. 2.7.3 *)
- p := Machine.PhysicalAdr(ADDRESSOF(c.prdt.prd[0]), MaxPRD*8);
- c.prdtPhysAdr := p;
- RETURN (p # Machine.NilAdr) & (p DIV PageSize = (p+MaxPRD*8-1) DIV PageSize)
- END GetPRDAdr;*)
- (* NanoDelay - Delay at least ns nanoseconds. *)
- PROCEDURE NanoDelay(ns: LONGINT);
- BEGIN
- ns := ns*4;
- WHILE ns > 0 DO DEC(ns) END
- END NanoDelay;
- (* Swap a longint *)
- PROCEDURE Swap(VAR a: ARRAY OF SYSTEM.BYTE);
- VAR x: SYSTEM.BYTE;
- BEGIN
- x := a[0]; a[0] := a[3]; a[3] := x;
- x := a[1]; a[1] := a[2]; a[2] := x;
- END Swap;
- PROCEDURE KernelLogHex(x, j, w: LONGINT);
- VAR i: LONGINT; buf: ARRAY 10 OF CHAR;
- BEGIN
- IF j = 0 THEN
- IF w >= 0 THEN j := 8 ELSE j := 2; w := -w END;
- END;
- FOR i := j+1 TO w DO KernelLog.Char(" ") END;
- FOR i := j-1 TO 0 BY -1 DO
- buf[i] := CHR(x MOD 10H + 48);
- IF buf[i] > "9" THEN
- buf[i] := CHR(ORD(buf[i]) - 48 + 65 - 10)
- END;
- x := x DIV 10H
- END;
- buf[j] := 0X;
- KernelLog.String(buf)
- END KernelLogHex;
- (* Convert an ATA identify string to a readable format. *)
- PROCEDURE GetATAString(VAR buf: ARRAY OF INTEGER; from, to: LONGINT; VAR s: ARRAY OF CHAR);
- VAR i, j: LONGINT;
- BEGIN
- FOR i := from TO to DO
- s[2*(i-from)] := CHR(buf[i] DIV 100H MOD 100H);
- s[2*(i-from)+1] := CHR(buf[i] MOD 100H)
- END;
- s[2*(to-from+1)] := 0X;
- i := 0; j := 0;
- WHILE s[i] # 0X DO
- IF (s[i] >= 20X) & (s[i] <= 7EX) THEN s[j] := s[i]; INC(j) END;
- INC(i);
- IF (j # 0) & (s[j-1] = 20X) THEN
- WHILE s[i] = 20X DO INC(i) END
- END
- END;
- IF (j # 0) & (s[j-1] = 20X) THEN DEC(j) END;
- s[j] := 0X
- END GetATAString;
- PROCEDURE IdentifyMajorVersion(buf: ARRAY OF INTEGER; VAR id: ID): LONGINT;
- VAR
- a, i: LONGINT;
- BEGIN
- a := 0;
- IF buf[80] # -1 THEN
- i := 3;
- WHILE i < 15 DO
- IF i IN SYSTEM.VAL(SET, buf[80]) THEN a := i; END;
- INC(i);
- END;
- END;
- id.majorVersion := a;
- RETURN Res_OK;
- END IdentifyMajorVersion;
- PROCEDURE IdentifyDMA(buf: ARRAY OF INTEGER; VAR id: ID): LONGINT;
- VAR a, i: LONGINT;
- BEGIN
- (* Determine the maximum Multiword DMA mode supported *)
- a := -1; i := 0;
- WHILE i < 3 DO
- IF i IN SYSTEM.VAL(SET, buf[63]) THEN INC(a); END;
- INC(i);
- END;
- id.maxdmamode := a;
- (* Determine the currently selected Multiword DMA mode *)
- a:= -1; i := 8;
- WHILE i < 11 DO
- IF i IN SYSTEM.VAL(SET, buf[63]) THEN a := i-8; END;
- INC(i);
- END;
- id.dmamode := a;
- (* Are the fields reported in word 88 valid? *)
- IF 2 IN SYSTEM.VAL(SET, buf[53]) THEN
- (* Determine the maximum Ultra DMA mode supported *)
- a := -1; i := 0;
- WHILE i < 8 DO
- IF i IN SYSTEM.VAL(SET, buf[88]) THEN INC(a); END;
- INC(i);
- END;
- IF a >= 0 THEN
- id.maxdmamode := 10+a;
- END;
- (* Determine the currntly seleccted Ultra DMA mode *)
- a:= -1; i := 8;
- WHILE i < 16 DO
- IF i IN SYSTEM.VAL(SET, buf[88]) THEN a := i-8; END;
- INC(i);
- END;
- IF a >= 0 THEN
- id.dmamode := 10+a;
- END;
- END;
- RETURN Res_OK;
- END IdentifyDMA;
- PROCEDURE ShowCHS(chs: CHS);
- BEGIN
- KernelLog.Int(chs.cyls, 1);
- KernelLog.Char("*");
- KernelLog.Int(chs.hds, 1);
- KernelLog.Char("*");
- KernelLog.Int(chs.spt, 1)
- END ShowCHS;
- PROCEDURE ShowDevType(t: LONGINT);
- BEGIN
- CASE t OF
- | 0: KernelLog.String(" direct access")
- | 1: KernelLog.String(" sequential access")
- | 2: KernelLog.String(" printer")
- | 3: KernelLog.String(" processor")
- | 4: KernelLog.String(" write-once")
- | 5: KernelLog.String(" cd-rom")
- | 6: KernelLog.String(" scanner")
- | 7: KernelLog.String(" optical memory")
- | 8: KernelLog.String(" medium changer")
- | 9: KernelLog.String(" communications")
- ELSE KernelLog.String(" type "); KernelLog.Int(t, 1)
- END;
- KernelLog.String(" device")
- END ShowDevType;
- PROCEDURE ShowDevices;
- VAR dev: Device; nofDevices, i : LONGINT;
- BEGIN
- nofDevices := 0;
- FOR i := 0 TO MaxDevices-1 DO
- dev := device[i];
- IF dev # NIL THEN
- dev.ShowDevice();
- INC(nofDevices);
- END;
- END;
- IF (nofDevices = 0) THEN
- KernelLog.String("No devices found."); KernelLog.Ln;
- END;
- END ShowDevices;
- PROCEDURE AddController*(ctrl: Controller);
- VAR
- i, c: LONGINT;
- BEGIN {EXCLUSIVE}
- IF ctrl = NIL THEN RETURN; END;
- c := -1;
- FOR i:=0 TO nofControllers-1 DO
- IF controller[i] # NIL THEN
- IF ctrl.cmdbase = controller[i].cmdbase THEN
- Show("Resource conflict for controller "); KernelLog.Int(i, 0); KernelLog.Ln;
- c := i;
- END;
- END;
- END;
- IF c = -1 THEN
- Show("Adding controller ");
- ELSE
- controller[c].Finalize;
- Show("Replacing controller ");
- END;
- KernelLogHex(ctrl.cmdbase, 4, 0); KernelLog.String(", ");
- KernelLogHex(ctrl.cnlbase, 4, 0); KernelLog.String(", ");
- KernelLogHex(ctrl.bmbase, 4, 0); KernelLog.String(", ");
- KernelLog.String("IRQ: "); KernelLog.Int(ctrl.irq, 0);
- (* Add Controller *)
- IF ctrl.cmdbase = 1F0H THEN
- i := 0;
- ELSIF ctrl.cmdbase = 170H THEN
- i := 1;
- ELSE
- IF c = -1 THEN
- i := nofControllers;
- INC(nofControllers);
- ELSE
- i := c;
- END;
- END;
- controller[i] := ctrl;
- ctrl.ctrlID := i;
- KernelLog.String(": ");
- KernelLog.String(Name); KernelLog.Int(i*MaxDevicesC, 1);
- KernelLog.String(".."); KernelLog.Int((i+1)*MaxDevicesC-1, 1);
- (* Init Controller *)
- ctrl.InitController();
- KernelLog.Ln;
- END AddController;
- PROCEDURE IdentifyController*(bus, dev, fkt: LONGINT);
- VAR res, pcmd_ba, pcnl_ba, scmd_ba, scnl_ba, bm_ba, irq: LONGINT; s: SET;
- c: Controller;
- BEGIN
- res := PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr0Reg, pcmd_ba);
- IF ~((res = PCI.Done) & (ODD(pcmd_ba) OR (pcmd_ba = 0))) THEN RETURN; END; (* I/O mapped or leagacy *)
- DEC(pcmd_ba, pcmd_ba MOD 8);
- res := PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr1Reg, pcnl_ba);
- IF ~((res = PCI.Done) & (ODD(pcnl_ba) OR (pcnl_ba = 0))) THEN RETURN; END; (* I/O mapped or leagacy *)
- DEC(pcnl_ba, pcnl_ba MOD 8);
- res := PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr2Reg, scmd_ba);
- IF ~((res = PCI.Done) & (ODD(scmd_ba) OR (scmd_ba = 0))) THEN RETURN; END; (* I/O mapped or leagacy *)
- DEC(scmd_ba, scmd_ba MOD 8);
- res := PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr3Reg, scnl_ba);
- IF ~((res = PCI.Done) & (ODD(scnl_ba) OR (scnl_ba = 0))) THEN RETURN; END; (* I/O mapped or leagacy *)
- DEC(scnl_ba, scnl_ba MOD 8);
- IF PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr4Reg, bm_ba) # PCI.Done THEN RETURN; END;
- IF ~((res = PCI.Done) & (ODD(bm_ba) OR (bm_ba = 0))) THEN RETURN; END; (* I/O mapped or no BM *)
- DEC(bm_ba, bm_ba MOD 10H);
- IF bm_ba # 0 THEN
- (* InitBusMaster *)
- IF PCI.ReadConfigWord(bus, dev, fkt, PCI.CmdReg, SYSTEM.VAL(LONGINT, s)) # PCI.Done THEN RETURN; END;
- IF s*{2,0} = {0} THEN
- INCL(s, 2);
- IF PCI.WriteConfigWord(bus, dev, fkt, PCI.CmdReg, SYSTEM.VAL(LONGINT, s)) # PCI.Done THEN RETURN; END;
- END;
- IF s*{2,0} # {2,0} THEN bm_ba := 0; END;
- END;
- IF PCI.ReadConfigByte(bus, dev, fkt, PCI.IntlReg, irq) # PCI.Done THEN RETURN; END;
- IF ~((res = PCI.Done)) THEN RETURN; END;
- (* Primary Controller *)
- IF (pcmd_ba = 0) OR ((pcmd_ba = 1F0H) & (pcnl_ba = 3F0H)) THEN
- NEW(c, 1F0H, 3F0H, bm_ba, 14);
- ELSE
- NEW(c, pcmd_ba, pcnl_ba, bm_ba, irq);
- END;
- AddController(c);
- (* Secondary Controller *)
- IF bm_ba # 0 THEN
- bm_ba := bm_ba+8;
- END;
- IF (scmd_ba = 0) OR ((scmd_ba = 170H) & (scnl_ba = 370H)) THEN
- NEW(c, 170H, 370H, bm_ba, 15);
- ELSE
- NEW(c, scmd_ba, scnl_ba, bm_ba, irq);
- END;
- AddController(c);
- END IdentifyController;
- PROCEDURE ScanPCI(vendor, id: LONGINT);
- VAR idx, bus, dev, fkt: LONGINT;
- BEGIN
- idx := 0;
- WHILE PCI.FindPCIDevice(id, vendor, idx, bus, dev, fkt) = PCI.Done DO
- Show("Found PCI device "); KernelLogHex(vendor, 4, 0); KernelLog.String(":"); KernelLogHex(id, 4, 0); KernelLog.Ln;
- IdentifyController(bus, dev, fkt);
- INC(idx);
- END;
- END ScanPCI;
- PROCEDURE ScanPCIClass(class: LONGINT);
- VAR idx, bus, dev, fkt: LONGINT;
- BEGIN
- idx := 0;
- WHILE PCI.FindPCIClassCode(class, idx, bus, dev, fkt) = PCI.Done DO
- Show("Found PCI device on bus "); KernelLog.Int(bus, 0); KernelLog.String(", device "); KernelLog.Int(dev, 0);
- KernelLog.String(", function "); KernelLog.Int(fkt, 0); KernelLog.Ln;
- IdentifyController(bus, dev, fkt);
- INC(idx);
- END;
- END ScanPCIClass;
- PROCEDURE IdentifyControllers;
- VAR
- class: LONGINT;
- str: ARRAY 32 OF CHAR;
- c: Controller;
- BEGIN
- nofControllers := 2;
- Machine.GetConfig("ATADetect", str);
- IF str = "default" THEN
- Show("Scanning PCI bus for known ATA controllers..."); KernelLog.Ln;
- (* Intel *)
- ScanPCI(8086H, 24DBH); (* ICH5 IDE *)
- ScanPCI(8086H, 24D1H); (* ICH5 SATA (82801EB) *)
- ScanPCI(8086H, 24DFH); (* ICH5R SATA (82801ER) *)
- ScanPCI(8086H, 7111H); (* PIIX/4 EIDE, VMWare *)
- ScanPCI(8086H, 7010H); (* PIIX/3 (82371SB) *)
- ScanPCI(8086H, 2411H); (* 8xx Chipset IDE *)
- ScanPCI(8086H, 2421H); (* IDE (82801AB) *)
- ScanPCI(8086H, 244BH); (* IDE (82801E, U100) *)
- ScanPCI(8086H, 24CAH); (* ICH4-M (82801DBM) *)
- ScanPCI(8086H, 248AH); (* ICH3-M (82801CAM) *)
- ScanPCI(8086H, 2641H); (* ICH6-M (82801FBM) *)
- ScanPCI(8086H, 2651H); (* ICH6-W (82801 FB/FW SATA) *)
- ScanPCI(8086H, 266FH); (* ICH6 (82801 FB/FBM/FR/FW/FRW SATA *)
- (* Others *)
- ScanPCI(1106H, 0571H); (* Asus A7V IDE *)
- ScanPCI(105AH, 0D30H); (* Asus A7V Promise *)
- ScanPCI(1078H, 0102H); (* Cyrix IDE *)
- ScanPCI(1166H, 0211H); (* Serverworks *)
- ELSIF str = "legacy" THEN
- Show("Legacy mode..."); KernelLog.Ln;
- NEW(c, 1F0H, 3F0H, 0, 14);
- AddController(c);
- NEW(c, 170H, 370H, 0, 15);
- AddController(c);
- ELSE
- Show("Scanning PCI bus for IDE & SATA class devices ..."); KernelLog.Ln;
- FOR class := 010100H TO 0101FFH DO ScanPCIClass(class); END; (* IDE *)
- FOR class := 010600H TO 0106FFH DO ScanPCIClass(class); END; (* SATA *)
- IF (str = "raid") OR (str = "raid+other") THEN
- Show("Scanning PCI bus for RAID class devices..."); KernelLog.Ln;
- FOR class := 010400H TO 0104FFH DO ScanPCIClass(class); END; (* RAID *)
- END;
- IF (str = "other") OR (str = "raid+other") THEN
- Show("Scanning PCI bus for PCI mass storage class devices..."); KernelLog.Ln;
- FOR class := 018000H TO 0180FFH DO ScanPCIClass(class); END; (* Mass Storage *)
- END;
- END;
- END IdentifyControllers;
- PROCEDURE GetOptions;
- VAR str : ARRAY 32 OF CHAR;
- PROCEDURE CharacterInString(ch : CHAR; CONST string : ARRAY OF CHAR) : BOOLEAN;
- VAR i : LONGINT;
- BEGIN
- FOR i := 0 TO LEN(string)-1 DO
- IF string[i] = ch THEN RETURN TRUE; END;
- END;
- RETURN FALSE;
- END CharacterInString;
- BEGIN
- Machine.GetConfig("ATATrace", str);
- IF str # "" THEN
- Show("Trace option string: "); KernelLog.String(str); KernelLog.Ln;
- IF CharacterInString("0", str) THEN trace := trace + TraceCommands; END;
- IF CharacterInString("1", str) THEN trace := trace + TraceErrors; END;
- IF CharacterInString("2", str) THEN trace := trace + TraceAtapi; END;
- IF CharacterInString("3", str) THEN trace := trace + TraceSense; END;
- IF CharacterInString("4", str) THEN trace := trace + TraceBuffer; END;
- IF CharacterInString("5", str) THEN trace := trace + TraceInit; END;
- END;
- Machine.GetConfig("ATAForcePIO", str);
- IF str = "1" THEN
- ataForcePio := TRUE;
- Show("Force PIO mode for ATA devices"); KernelLog.Ln;
- END;
- Machine.GetConfig("ATAPIForcePIO", str);
- IF str = "1" THEN
- atapiForcePio := TRUE;
- Show("Force PIO mode for ATAPI devices"); KernelLog.Ln;
- END;
- END GetOptions;
- PROCEDURE Install*;
- BEGIN
- IF ~installed THEN
- installed := TRUE;
- GetOptions;
- IdentifyControllers;
- KernelLog.String("ATADisks: Detected devices:"); KernelLog.Ln;
- ShowDevices;
- ELSE
- KernelLog.String("ATADisks: Driver is already loaded, devices: "); KernelLog.Ln;
- ShowDevices;
- END;
- END Install;
- PROCEDURE ShowCounter*;
- BEGIN
- Show("IRQs: "); KernelLog.Int(irqCount, 0); KernelLog.Ln;
- KernelLog.String("IRQ-Waits: "); KernelLog.Int(expectedCount, 0); KernelLog.Ln;
- END ShowCounter;
- PROCEDURE ResetCounter*;
- BEGIN
- Show("Reset Counter"); KernelLog.Ln;
- irqCount := 0;
- expectedCount := 0;
- END ResetCounter;
- PROCEDURE Show(CONST string : ARRAY OF CHAR);
- BEGIN
- KernelLog.String("ATADisks: "); KernelLog.String(string);
- END Show;
- (* Clean up unloaded module. *)
- PROCEDURE Cleanup;
- VAR i: LONGINT; d: Device;
- BEGIN
- FOR i := 0 TO MaxDevices-1 DO
- d := device[i];
- IF d # NIL THEN
- d.Finalize;
- END
- END;
- FOR i := 0 TO MaxControllers-1 DO
- IF (controller[i] # NIL) THEN
- controller[i].Finalize();
- controller[i] := NIL
- END
- END
- END Cleanup;
- BEGIN
- Modules.InstallTermHandler(Cleanup);
- Install;
- END ATADisks.
- Error codes
- 2801 device select failed before issueing
- 2802 device select failed after issueing
- 2807 dma transfer timeout
- 2808 dma transfer failed
- 2809 dma transfer error
- 2812 identify atapi failed
- 2813 size 0 device
- 2814 identify failed
- 2815 bad controller port
- 2816 atapi reset failed
- 2817 ata set parameters failed
- 2819 pio read timeout
- 2820 pio read error
- 2821 pio read error
- 2822 pio write error
- 2823 pio write timeout
- 2824 pio write error
- 2825 identify ata geometry bad
- 2826 transfer out of range
- 2827 ATA: removable with no RMSN support
- 2828 ATAPI: removable with no RMSN support
- 2829 ATAPI: packet command failed
- 2830 ATAPI: transfer packet error (did not complete)
- 2831 ATAPI: transfer failed (no sense data)
- 2832 ATAPI: transfer failed (sense data available)
- 2833 ATAPI: unsupported packet size
- 2834 ATAPI: could not enable RMSN
- 2835 ATAPI: could not disable RMSN
- 2836 RMSN: get media status failed
- 2837 Eject failed
- 2838 Lock failed
- 2839 Unlock failed
- AosATADisk.Install ~ SystemTools.Free ATADisks ~
- ATAErrors.Text
|