12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582 |
- 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): WORD;
- 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(): WORD;
- 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): WORD;
- 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): WORD;
- 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): WORD;
- 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): WORD;
- 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): WORD;
- 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: LONGINT; res: WORD; 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: LONGINT; ignore: WORD; 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: LONGINT; VAR res: WORD);
- 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): WORD;
- 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(): WORD;
- 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(): WORD;
- 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(): WORD;
- 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): WORD;
- BEGIN {EXCLUSIVE}
- IF ~(RemovableBit IN id.type) THEN RETURN Disks.Unsupported; END;
- RETURN SendATACommand(0EDH, IOTimeout); (* media eject *)
- END MediaEject;
- PROCEDURE MediaLock(lock: BOOLEAN): WORD;
- 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(): WORD;
- BEGIN
- RETURN SendATACommand(0E0H, IOTimeout); (* standby immediate *)
- END Powersave;
- PROCEDURE SendATACommand(cmd, ms: LONGINT): WORD;
- 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): WORD;
- 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: LONGINT; res: WORD;
- 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: LONGINT; VAR res: WORD);
- 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): WORD;
- VAR
- command: CommandPacket;
- i: LONGINT; res: WORD;
- 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): WORD;
- VAR
- command: Command;
- res: WORD; 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(): WORD;
- 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(): WORD;
- VAR
- i: LONGINT; res: WORD;
- 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, res); (* ignore res *)
- (*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*(): WORD;
- 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*(): WORD;
- 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(): WORD;
- BEGIN
- RETURN Flush^();
- END Flush;
- PROCEDURE MediaEject*(immediate, load: BOOLEAN): WORD;
- VAR
- command: CommandPacket;
- res: WORD; 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): WORD;
- 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(): WORD;
- 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): WORD;
- VAR
- buf: ARRAY 2 OF LONGINT; res: WORD; 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): WORD;
- 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
- #IF I386 THEN
- #IF COOP THEN
- MOV ESI, ECX
- #END
- MOV EDX, [EBP + port]
- MOV EDI, [EBP + bufAdr]
- MOV ECX, [EBP + len]
- CLD
- REP INSW
- #IF COOP THEN
- MOV ECX, ESI
- #END
- #ELSIF AMD64 THEN
- MOV RDX, [RBP + port]
- MOV RDI, [RBP + bufAdr]
- MOV RCX, [RBP + len]
- CLD
- REP INSW
- #ELSE
- unimplemented
- #END
- END RepInWord;
- (* Block port out instruction. *)
- PROCEDURE RepOutWord(port, bufAdr: ADDRESS; len: SIZE);
- CODE
- #IF I386 THEN
- #IF COOP THEN
- MOV EDI, ECX
- #END
- MOV EDX, [EBP + port]
- MOV ESI, [EBP + bufAdr]
- MOV ECX, [EBP + len]
- CLD
- REP OUTSW
- #IF COOP THEN
- MOV ECX, EDI
- #END
- #ELSIF AMD64 THEN
- MOV RDX, [RBP + port]
- MOV RSI, [RBP + bufAdr]
- MOV RCX, [RBP + len]
- CLD
- REP OUTSW
- #ELSE
- unimplemented
- #END
- END RepOutWord;
- PROCEDURE ResetCommand(cmd: Command; size: SIZE);
- BEGIN
- ASSERT(cmd # NIL);
- ASSERT(size MOD 4 = 0);
- Machine.Fill32(ADDRESS OF cmd.dev, 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: WORD; 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; Dot();
- 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; Dot();
- 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 ScanIterate;
- VAR pci: PCI.Pci; res: WORD; r0,r8,class: LONGINT;
- BEGIN
- PCI.StartIterate(pci);
- WHILE PCI.Iterate(pci) DO
- res := PCI.ReadConfigDword(pci.bus, pci.device, pci.function, 0, r0);
- IF r0 # LONGINT(0FFFFFFFFH) THEN
- res := PCI.ReadConfigDword(pci.bus, pci.device, pci.function, 8, r8);
- class := r8 DIV 100H MOD 1000000H;
- IF (class DIV 10000H = 01H) (* mass storage *)
- (*(class >= 010100H) & (class <= 0101FFH) OR (class >= 010600H) & (class <= 0106FFH)
- OR (class >= 010400H) & (class <= 0104FFH) OR (class >= 018000H) & (class <= 0180FFH) *) THEN
- IdentifyController(pci.bus, pci.device, pci.function);
- END
- END;
- END;
- END ScanIterate;
- PROCEDURE IdentifyControllers;
- VAR
- class: LONGINT;
- str: ARRAY 128 OF CHAR;
- c: Controller;
- i, num1, num2: LONGINT;
- 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 *)
- ScanPCI(8086H, 27C0H); (* found on TL device *)
- 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);
- ELSIF ~ParseConfigString(str) THEN
- ScanIterate; (* much faster *)
- (*
- 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;
- VAR dots: LONGINT;
- PROCEDURE Dot;
- BEGIN
- KernelLog.String(".");
- INC(dots); IF dots >= 128 THEN KernelLog.Ln; dots := 0 END;
- END Dot;
- PROCEDURE Show(CONST string : ARRAY OF CHAR);
- BEGIN
- IF dots > 0 THEN KernelLog.Ln END;
- dots := 0;
- KernelLog.String("ATADisks: "); KernelLog.String(string);
- END Show;
- PROCEDURE ParseConfigString(CONST s: ARRAY OF CHAR): BOOLEAN;
- VAR pos: LONGINT; ch: CHAR; cmdbase, cnlbase, bmbase, irq: LONGINT; c: Controller;
- PROCEDURE Char(VAR ch: CHAR);
- BEGIN ch := s[pos]; IF ch # 0X THEN INC(pos) END;
- END Char;
- PROCEDURE Hex(VAR n: LONGINT): BOOLEAN;
- VAR ch: CHAR;
- BEGIN
- ch := s[pos];
- IF (ch >= "0") & (ch <= "9") THEN n := ORD(ch)-ORD("0"); INC(pos); RETURN TRUE
- ELSIF (ch >= "A") & (ch <= "F") THEN n := ORD(ch)-ORD("A")+10; INC(pos); RETURN TRUE
- ELSE RETURN FALSE
- END;
- END Hex;
- PROCEDURE Number(VAR num: LONGINT);
- VAR n: LONGINT;
- BEGIN
- num := 0;
- WHILE Hex(n) DO num := num* 10H + n END;
- END Number;
- BEGIN
- IF s[0] = "X" THEN
- pos := 1; (* skip "X" "*)
- Show("Using predefined configuration string "); KernelLog.String(s); KernelLog.Ln;
- REPEAT
- Number(cmdbase); Char(ch);
- Number(cnlbase); Char(ch);
- Number(bmbase); Char(ch);
- Number(irq); Char(ch);
- NEW(c,cmdbase, cnlbase, bmbase, irq);
- AddController(c);
- UNTIL ch # ",";
- RETURN TRUE
- ELSE
- RETURN FALSE
- END;
- END ParseConfigString;
- PROCEDURE GetConfigString*(VAR s: ARRAY OF CHAR);
- VAR i: LONGINT; c: Controller; first: BOOLEAN; pos: LONGINT
- PROCEDURE Char(c: CHAR);
- BEGIN
- s[pos] := c;
- IF pos < LEN(s)-1 THEN INC(pos) END;
- END Char;
- PROCEDURE Hex(x: LONGINT): CHAR;
- BEGIN
- IF x < 10 THEN RETURN CHR(ORD("0")+x)
- ELSE RETURN CHR(ORD("A")+x-10);
- END;
- END Hex;
- PROCEDURE Number(n: LONGINT);
- VAR h: ARRAY 8 OF CHAR; i: LONGINT;
- BEGIN
- ASSERT(n>=0);
- i := 0;
- REPEAT
- h[i] := Hex(n MOD 10H); n := n DIV 10H; INC(i);
- UNTIL n = 0;
- WHILE(i>0) DO
- DEC(i); Char(h[i]);
- END;
- END Number;
- BEGIN
- pos := 0;
- first := TRUE;
- Char("X");
- FOR i := 0 TO MaxControllers-1 DO
- c := controller[i];
- IF c # NIL THEN
- IF ~first THEN Char(",") ELSE first := FALSE END;
- Number(c.cmdbase);Char(":");
- Number(c.cnlbase);Char(":");
- Number(c.bmbase); Char(":");
- Number(c.irq);
- END;
- END;
- Char(0X);
- END GetConfigString;
- PROCEDURE ShowConfigString*;
- VAR s: ARRAY 128 OF CHAR;
- BEGIN
- GetConfigString(s);
- KernelLog.String("config = "); KernelLog.String(s); KernelLog.Ln;
- END ShowConfigString;
- (* 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 ~ System.Free ATADisks ~
- ATAErrors.Text
|