Projekter/CDC 9762 CR80 disk packs
Arkivering af CR80 disk packs til CDC 9762
I 2023 lykkedes det os at bit-arkivere flere CDC 9762 disk packs skrevet af en Christian Rovsing CR80 computer. CDC 9762 er en harddisk i Storage Module Device (SMD) familien, lavet af Control Data Corporation, og en dertilhørende disk pack (en slags "removable media") kunne lagre 80MB data. CDC 9762 blev lanceret i 1974, men vores CR80 disk packs er formentlig blevet skrevet i midt-80'erne. CR80 kontrollerede drevet via en CR8044 disk controller.
Status
- Drevet er i en stand, hvor det kan foretage fejlfrie eller nær-fejlfrie læsninger.
- Drevet kan fortsat ikke seeke mere end ±1 cylinder af gangen. Dette er ikke til hinder for dataarkivering, men en CR8044 vil næppe kunne bruge drevet før dette problem bliver løst.
- Vi har egetudviklet controller hardware+software, der kan kontrollere drevet.
- AutoArkæologen forstår CR8044'ens sektorformat.
- Vi kan ikke foretage fejlfrie læsninger af ukendte/andre sektorformater. Dette skyldes, at der opstår fejl i data hvis ikke læsninger startes og stoppes på præcise tidspunkter i forhold til sektorformatet. Men selv uperfekte læsninger er gode nok til, at vi burde kunne udlede ukendte sektorformater, og så bootstrappe derfra.
- Hvis en disk pack bruger "address marks", skal vi sandsynligvis lidt længere tilbage til tegnebrædtet.
Medvirkende
- Holger Straadt (hardware, diagrammer, tidligere Rovsing-medarbejder)
- Anders Straadt (controller, software)
- Poul-Henning Kamp (dataanalyse, software)
- Erlo (hardware, har arbejdet med CR80)
("hovedområde" i parentes)
Om CDC 9762
En disk pack består af 5 diske. De to yderste diske (øverst/nederst) er "dummies" uden data, men er nødvendige pga. aerodynamik (hovederne svæver). De 3 diske i midten har 2 sider (top/bund); 5 ud af de 6 sider har data, mens den sidste side er en "servo-overflade". Denne indeholder et særligt mønster der bruges til at generere clock-signaler, og til at seeke.
Drevet forbindes via 2 kabler; et 60 pin A-cable, og et 26 pin B-cable. Alle de vigtigste signaler er balancerede, dvs. der bruges 2 pins til 1 signal. De relevante (for os) signaler er:
Retning | Navn | Funktion |
---|---|---|
ctrl→drev | UNIT SELECT TAG | Bruges sammen med UNIT SELECT BIT 0-3 til at vælge det drev du vil snakke med. I vores setup er disee bits hardwired til 0 ("unit 0") da vi kun snakker med ét drev. |
ctrl→drev | TAG1 | Starter en cylinder seek, BIT0-BIT9 angiver cylindren, 0-822. |
ctrl→drev | TAG2 | Starter et head select, BIT0-BIT2 angiver hovedet, 0-4. |
ctrl→drev | TAG3 | "Kontrol": bruges sammen med BIT0-BIT9 til at starte læsninger, skrivninger, udføre "fault clear", osv. |
ctrl→drev | BIT0-BIT9 | 10-bit adresse/argument til TAG1-TAG3. |
drev→ctrl | INDEX | Sender 1 impuls per omdrejning (60 gange i sekundet). |
drev→ctrl | SECTOR | 32 impulser per omdrejning i vores tilfælde, men kan ændres med DIP-switches på drevet. Sector 0 starter efter INDEX, mens sector 1+ starter efter SECTOR. |
drev→ctrl | ON CYLINDER | Drevet er låst fast på en cylinder (er lav mens drevet seeker). |
drev→ctrl | UNIT READY | "Drevet er klar" (i praksis er det en afledt status, og derfor unødvendig). |
drev→ctrl | FAULT | Generelt fejl-signal. |
drev→ctrl | SEEK ERROR | Opstår hvis en seek ikke lykkes inden for 500ms. |
drev→ctrl | SEEK END | Er lav når drevet seeker; går høj samtidigt med enten ON CYLINDER eller SEEK ERROR. |
drev→ctrl | UNIT SELECTED | Svaret på UNIT SELECT TAG. |
drev→ctrl | SERVO CLOCK | Clock signal fra servo disken. |
drev→ctrl | READ CLOCK | Clock afledt fra SERVO CLOCK, men også påvirket af datastrømmen selv. |
drev→ctrl | READ DATA | Data-bit læses herfra når READ CLOCK skifter fra 0 til 1. |
Restaurering af CDC 9762 (foråret, 2023)
Den første opgave var at finde en CDC 9762. Eller rettere 2, fordi vi ikke regnede med, at så fintfølende mekanik som et diskdrev bare ville virke efter 35 år. Så en reserve var ønskelig.
Finn og Holger tog på lager og fandt to, der så nogenlunde tilforladelige ud. De er temmelig tunge, 65 kg.
Den ene så temmelig korroderet ud. Hovedlejet, hvor disken sidder ovenpå, drejede kun rundt med besvær. Så den anden blev valgt som "master". Dens hovedleje drejede nogenlunde ubesværet.
Nu skulle coveret åbnes. Her benyttes en umbraco, som ikke findes i et standard sæt, men Holger fandt en derhjemme der passede. Herfter kunne den åbnes til "maintenance position".
Her kunne han se, at pakningerne til de rør, der styrer luften fra blæseren gennem et filter, ind til disken var næsten korroderet væk.
I maintenance manualen er det beskrevet, hvor vigtigt, det er, at luften strømmer rigtigt ind mellem pladerne på disken. Der er oven i købet en procedure for, hvordan man måler lufttrykket i systemet på en lille studs på luftfilteret.
Så det kunne ikke bare ignoreres. Holger skar nogle pakninger ud af et flamingo-lignende materiale og limede dem på.
Herefter kunne han prøve at sætte strøm på. Kontakten knækkede men var heldigvis nem at skifte.
Der kom strøm på, og blæseren begyndte at køre (larme). Imidlertid lyste fejllampen på frontpanelet, og en lysdiode på et elektronik-kort lyste. Fejlen betød "Multiple Head Select", hvilket ikke gav meget mening, da vi ikke havde selected et hoved endnu. Efter nogen granskning af diagrammer kom Holger frem til, at fejlen bliver sat, hvis man selecterer to hoveder samtidigt. Det gav endnu mindre mening. Så et eller andet var "ravende" galt. Holger skiftede det kort, som håndterer Head Select. Derefter initialiserede den og meldte Ready (klar til at spinne disken op).
Nu var tiden inde til at putte en disk i (uden interessante data), og spinne den op. Den begyndte langsomt at spinne og larmen tiltog, indtil den lød som en mejetærsker. Holger trykkede på stopknappen, nærmest i panik, men nåede dog at se, at den faktisk loadede hovederne, dvs. den kørte dem frem til spor 0. Så bortset fra larmen, så det ud til at virke.
Den mest sandsynlige kandidat til larmen var hovedlejet, som disken ligger på. På reservedrevet kørte hovedlejet meget dårligt. Holger pillede det ud og gav det noget Caramba.
Derefter drejede den pænt og nydeligt rund, så godt som man nu kan mærke med hænderne. Der var ikke meget andet at gøre end at sætte den i hoveddrevet, med fare for at hovederne kom helt ud af alignment.
En del af proceduren for at skifte hovedleje er, at man skal skal justere lejet med et specialværktøj.
Det ser ud til, at den horizontale x position (x-retningen: vinkelret på hovederne) skal justeres med 0,1 mm nøjagtighed. Vi forstår ikke rigtig, hvorfor denne justering er nødvendig, hvordan en horizontal forskydning i x-retningen på 0,1 mm skulle ændre noget på hovedernes funktion. Holger monterede lejet og forsøgte at få det til at sidde centreret i skruehullerne.
Holger spinnede den op igen, hovederne loadede, og drevet meldte "Ready". Den larmede dog mere, end Holger husker det fra gamle dage ("en fuldstændig subjektiv og upræcis bemærkning").
Tilkoblet en CR80
Nu var tiden inde til at få CR80'eren op at køre og koble den til drevet. Her var Erlo den mest aktive med sit kendskab til CR80 hardware og CR80 bootloader.
Når man sætter strøm på racket, kommer bootloader menuen fint op på en VT100 emulator. Her kan man så liste addresser mm. på I/O modulerne, herunder disk controlleren. Desværre kunne Erlo ikke få kontakt til disk controlleren eller læse dens I/O addresse. Et skift af disk controlleren (CR8044) hjalp ikke.
Projektets formål var i starten, at få en CR80 til at boote fra en CDC 9762, men nu begyndte det at trække i retning af, at vi burde udvikle vores egen controller.
Homebrew controller, juli-december 2023
Holger fik lokket Anders med på projektet, som gik i gang med at designe en controller. Der var nogen, der mente det skulle laves på en FPGA, men Anders havde snuset lidt til Raspberry Pi Pico, der huser RP2040 processoren. Det særlige ved denne er, at den har "Programmable I/O" (PIO), 2 små co-processorer, der kan køre bittesmå programmer, skrevet i et lille I/O-centrisk instruktionssæt. Folk har implementeret VGA, USB, I2C, mm. ved hjælp af PIO, og således sætter RP2040 sig lidt på det samme marked som "programmable logic". Desuden har Anders engang leget lidt med en CPLD (Altera MAX II EPM240), hvilket var en blandet oplevelse (Verilog er fint, men Java SDK'et og lange build-times var noget bras).
Designet blev, at en Raspberry Pi Pico snakker med drevet på den ene side, og en PC på den anden side. Pico'en har lige akkurat nok GPIO pins til vi kan håndtere alle de relavante inputs og outputs fra drevet. Holger byggede hardwaren, der består af logic level converters og differential line drivers/receivers, der kan kobles op imod de balancerede signaler.
Anders troede først at alle "TAG"'s fungerede ens, dvs. man sætter en adresse/argument, og derefter sender man en kort TAG-impuls for at latche værdien, men kun TAG1 og TAG2 fungerer sådan, mens TAG3 og UNIT SELECT TAG skal holdes høje imens funktionen ønskes. Eksempler:
- En seek til cylinder 256 foretages ved at sætte BIT8=1 og BIT0-BIT9 til 0, og derefter sende en kort TAG1 impuls
- En læsning foretages ved at holde TAG3 og BIT1 høje så længe man ønsker at læse (læsning stopper hvis en eller begge signaler går lav).
Søgeproblemer
Når man sender en søgekommando (TAG1) til drevet sker der det, at "vognen" (med skrive-/læsehoveder) sætter i gang, men ikke stopper før den når "end of travel" (EOT), som er "grøften" på hver sin side af cylinder 0 til 822. Det lader også til, at hastigheden er proportionel med cylinder-afstanden, således at en søgning fra cylinder 0 til 500 får vognen til at bevæge sig hurtigere end en søgning fra cylinder 0 til 50.
Drevet har 4 faser under en seek: acceleration, coasting, deceleration, og finsøgning. Noget kunne tyde på, at accelerationen fungerer fint, men at noget går galt i de resterende trin.
Vi har haft udskiftet nærmest samtlige logic boards (fra vores anden CDC 9762, som vi låner reservedele fra), samt en velocity transducer, der måler hastigheden på vognen. Ingen af disse udskiftninger gjorde en forskel.
Holger fik så den idé, at drevet måske kunne søge 1 cylinder af gangen, bl.a. fordi manual og diagrammer hentyder til, at den springer søgefaser over hvis de ikke er nødvendige. Det viste sig at passe, og herefter kunne vi søge således:
- Søg ±1 cylinder
- Vent på ON CYLINDER
- Gentag indtil den ønskede cylinder
Et sundt drev kan i følge manualen søge på 50ms, men med denne metode kan vi alligevel søge 800 cylindre på 2-3 sekunder.
Det var ikke noget vi ville have opdaget, med mindre vi ledte efter det, fordi det ikke er muligt at se med det blotte øje om vognen faktisk har flyttet sig 1 cylinder (der er 823 cylindre på ~6cm).
Data
Med et drev der nu kunne søge, kunne vi således også begynde at læse data. Det gjorde vi således:
- Vent på INDEX
- Begynd læsning (TAG3 + BIT1)
- Læs samme spor ~5 gange (dvs. 5 omdrejninger)
Allerede her begyndte vi at se rigtig data vha. Poul-Hennings software, men vi så samtidigt også mange læsefejl.
Når man begynder læsning (TAG3+BIT1) kan man samtidigt kombinere det med "justeringer":
- Data strobe delay: late/early (PLL timing?)
- Servo offset: plus/minus (skuber vognen en smule imod/væk fra aksen)
De har også begge en "neutral", som er det man normalt bruger. Så der er 9 kombinationsmuligheder. Vi forsøgte at se, om vi kunne forbedre læsningerne med disse justeringer. Det blev bedre, men ikke markant.
Head alignment mv.
Der er umiddelbart kun 2 mekaniske ting man kan "skrue på", hvis drevet læser dårligt:
- Aksen som disken spinner omkring kan flyttes en halv millimeter til hver side
- Hvert læse-/skrivehoved kan flyttes frem og tilbage langs søgeaksen ("head alignment")
I drevets storhedstid foregik head alignment vha. specialudstyr:
- Et specialværktøj bruges til at skubbe hovederne frem og tilbage.
- En særlig head alignment disk pack placeres i drevet, istedet for en normal disk pack.
- En CDC FTU (Field Test Unit) kobles til drevet vha. et specielt logic board, og bruges bl.a. til feedback mens man aligner hoveder.
Vi har ingen af disse ting, og de kan umiddelbart heller ikke findes på ebay mv.
Så vi måtte improvisere:
- Vi fandt noget metalskrot i en kasse, som vi kunne slibe til, og lave et head alignment værktøj.
- Vi brugte en almindelig CR80 disk pack.
- Som feedback fik vi vores software til at læse det samme spor igen og igen, og fortælle hvor mange gode sektorer den kunne finde.
Det fungerede, men i praksis kunne vi aldrig få den justeret til at læse bedre end 10-15 sektorer (ud af 32) per spor i gennemsnit.
Eftersom man nemt kan komme til at skubbe et hovede ±10 spor til hver side fik vi også hurtigt softwaren til at fortælle hvilket spor den havde fundet :-) ("Address field" indeholder cylinder, hoved og sektor, hvilket er praktisk!)
Datafejl og Eureka
Med gentagende læsninger af samme data kunne vi forbedre resultatet, men det var ikke gående mod 100% succes.
Ved inspektion af den data vi læste, så man at datasignalet "inverterede" et par gange i løbet af en omdrejning. Dvs. man kom til et punkt, hvor "00001010" blev til "11110101". Det fungerede dog ikke at invertere det tilbage, tildels fordi vi også så bits, der blev "tværet ud", fx "00001000" der blev til "00001100". Der var også ca. 8 clock cycles (READ CLOCK) for meget per omdrejning, hvilket sikkert passede meget godt med antallet af inverteringer per omdrejning.
Poul-Henning fandt dog et mønster i hvor bit-inverteringerne startede.
CR8044 sektorformatet (efter INDEX/SECTOR puls) er:
Felt | Indhold | Længde |
---|---|---|
Gap-A | nuller | 31 bytes |
Address Field | cylindernr., hovednr., sektornr., bad sector flag, mv., checksum | 9 bytes |
Gap-B | nuller | 19 bytes |
Data Field + EOS | sektordata, checksum, end-of-sector | 552 bytes |
Gap-C | nuller | 17,5 bytes |
Mønsteret var, at mange bit-inverteringer startede ~30 bits inde i "Gap-B". Det er et godt gæt at CR8044 begyndte skrivninger samme sted, også fordi der som regel ikke er nogen grund til at skrive address field når disken først er formatteret.
Derudover står der, hvis man nærlæser SMD-dokumentationen, at man skal starte læsningen (TAG3+BIT1) på et tidspunkt hvor drevet kan læse data-nuller i 7.75µs (~75 bits).
Så noget kunne tyde på, at man efterlader noget "snavs", når man begynder en skrivning, og at det er kraftigt nok til at en læsning ikke bare kan passere dette punkt, uden at blive skubbet ud af fase (gæt). Men det pegede også i retning af, at vi kunne løse vores bit-inverteringsproblemer hvis blot vi startede og stoppede læsninger på det rette tidspunkt.
For at afprøve det, forsøgte vi først at læse sektorer enkeltvis: istedet for at læse 5 omdrejninger efter INDEX, læste vi hver sektor efter INDEX/SECTOR. Dette førte til det første "lille store" gennembrud, hvor vi læste 70.000+ address fields uden en eneste fejl. Bit-inverteringerne forekom dog stadigt i Gap-B, og derfor var data field stadigt ofte korrupt.
Efter en ikke helt triviel omskrivning endte vi med:
For hver sektor:
- Vent på INDEX hvis sector 0, ellers SECTOR hvis sector 1+
- (I Gap-A) Brug SERVO CLOCK til at vente et magisk antal cycles
- Start læsning (TAG3+BIT1)
- Læs address field
- Stop læsning
- (I Gap-B) Brug SERVO CLOCK til at vente et magisk antal cycles
- Start læsning
- Læs data field
- Stop læsning
Bemærk at vi også endte med at indsætte et delay i Gap-A, hvilket var nødvendigt for at læse fx disk pack'en FNJ1 perfekt.
Med denne tilgang lykkedes det os endeligt at læse samtlige 131.680 sektorer fejlfrit på en disk pack, og selv den mest vanskelige disk pack ("systemdisk") havde kun omkring 150 dårlige sektorer.
Flere billeder
Se også
CDC's SMD manual (bitsavers.org)
Dokumentation af CR8044-sektorformatet (TODO: flyt til bitarkiv? Vi har hele dokumentet, men det er ikke indscannet endnu)