May 24, 2022

MFM disk - Using "mfm_dump" to dump a track

I decided that there was no better way to get familiar with David Gesswein's software than to rewrite it. I am joking really, but that is what I did in a way. I began going crazy using grep and ctags to study his code and decided to start copying it piecewise to a project of my own. I learn better when I am hands on, both compiling and running code. This is all about learning for me, and is in no way a commentary on the excellent work he has done. I have taken a variety of ugly short cuts to get something up and running quickly. In particular I took only the WD1006 controller code and left all of the others behind (where that was appropriate). I am running this on a fast linux machine. I captured a transitions file using David's emulator running on the BBB, then copied that file (using scp) to my linux machine for analysis. After a long day of brutal hacking, I learned enough to write some fairly clean and decent code to do some simple things for my case.

This program reads a single track from a transitions file and dumps it in various ways. One thing that was useful was to simply dump all of the 0xa1 marks that indicate the start of a header or data on the disk, and I got this:

Initial bit sep time: 20.000
Mark (A1) 1 at index 198 of 80987
Mark (A1) 2 at index 388 of 80987
Mark (A1) 3 at index 4852 of 80987
Mark (A1) 4 at index 5044 of 80987
Mark (A1) 5 at index 9507 of 80987
Mark (A1) 6 at index 9700 of 80987
Mark (A1) 7 at index 14163 of 80987
Mark (A1) 8 at index 14357 of 80987
Mark (A1) 9 at index 18818 of 80987
Mark (A1) 10 at index 19011 of 80987
Mark (A1) 11 at index 23472 of 80987
Mark (A1) 12 at index 23659 of 80987
Mark (A1) 13 at index 28124 of 80987
Mark (A1) 14 at index 28311 of 80987
Mark (A1) 15 at index 32775 of 80987
Mark (A1) 16 at index 32964 of 80987
Mark (A1) 17 at index 37427 of 80987
Mark (A1) 18 at index 37618 of 80987
Mark (A1) 19 at index 42081 of 80987
Mark (A1) 20 at index 42272 of 80987
Mark (A1) 21 at index 46734 of 80987
Mark (A1) 22 at index 46923 of 80987
Mark (A1) 23 at index 51388 of 80987
Mark (A1) 24 at index 51583 of 80987
Mark (A1) 25 at index 56043 of 80987
Mark (A1) 26 at index 56234 of 80987
Mark (A1) 27 at index 60698 of 80987
Mark (A1) 28 at index 60886 of 80987
Mark (A1) 29 at index 65352 of 80987
Mark (A1) 30 at index 65547 of 80987
Mark (A1) 31 at index 70009 of 80987
Mark (A1) 32 at index 70199 of 80987
Mark (A1) 33 at index 74664 of 80987
Mark (A1) 34 at index 74854 of 80987
final filtered bit sep time: 19.982
Getting 34 of these marks (where we expect 2 per sector) is a very strong indication that this disk is formatted with 17 sectors per track!

Some more fiddling gave us this. Here we are dumping 24 bytes for both the header and the data. Dumping more for the header meant that we never saw the mark for the data.

Dump (header) a1 fe 64 03 00 be d6 00 00 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 09 2f ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 01 ae f7 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 0a 1f 9c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 02 9e 94 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 0b 0f bd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 03 8e b5 00 00 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 0c 7f 5a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 04 fe 52 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 0d 6f 7b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 05 ee 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 0e 5f 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 06 de 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 0f 4f 39 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 07 ce 31 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 10 ac e7 00 00 00 00 3f ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (header) a1 fe 64 03 08 3f de 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I switched from track 100, head 3 (where the sectors seem full of zeros) to track 180, head 3 (where the sectors seem to have textual data). I also fiddle with the software so it prints 24 bytes of header data and 128 bytes of sector data (which includes the data header). I added some display on the right side that shows text, fixed byte swapping and am fairly satisfied with the following:
Dump (header) a1 fe b4 03 00 db 42 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 70 2e 20 6e 33 32 2e 0a 72 74 7e 20 2e 0a 6c 6c 39 20 35 2e 0a 69 70 2e 20 6c 34 31 0a 69  ...pn 23..tr ~..ll 9.5i..pl 14i.
Dump (data  ) 6c 2e 20 74 2e 39 69 37 2e 0a 6f 70 30 20 0a 69 64 2e 20 73 54 45 22 5c 2e 0a 65 64 48 20 0a 44  .lt 9.7i..po 0i..ds ET\"..de HD.
Dump (data  ) 70 2e 20 6f 0a 30 6c 2e 20 74 2e 39 69 34 27 0a 70 73 31 20 70 38 2e 0a 66 69 65 20 2e 20 6c 74  .po 0..lt 9.4i.'sp 18p..if e .tl
Dump (data  ) 27 20 5c 5c 28 2a 54 45 27 27 0a 27 69 2e 20 66 20 6f 74 2e 20 6c 27 27 5c 27 2a 5c 45 28 27 54   '\\*(ET'''..if o .tl '''\\*(ET'
Dump (header) a1 fe b4 03 09 4a 6b 00 00 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 66 0a 72 6f 61 20 20 6e 76 6f 72 65 69 76 77 65 73 20 65 65 60 20 68 54 0a 65 55 2e 0a 58  ...for an overview see `The..UX.
Dump (data  ) 69 54 65 6d 53 2d 61 68 69 72 67 6e 53 20 73 79 65 74 27 6d 62 0a 20 79 69 52 63 74 69 68 20 65  Time-Sharing System'.by Ritchie
Dump (data  ) 6e 61 20 64 68 54 6d 6f 73 70 6e 6f 20 3b 6f 66 20 72 20 61 75 74 6f 74 69 72 6c 61 73 20 65 65  and Thompson; for a tutorial see
Dump (data  ) 60 0a 73 5c 55 38 49 4e 5c 58 31 73 20 30 6f 66 20 72 65 42 69 67 6e 6e 72 65 27 73 62 20 20 79  .`\s8UNIX\s10 for Beginners' by
Dump (header) a1 fe b4 03 01 cb 63 00 00 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 74 75 70 6d 35 28 0a 29 78 2e 20 78 22 22 22 20 20 22 77 22 6d 74 3a 70 75 20 65 73 20 72  ..utmp(5)..xx "" "" "wtmp: user
Dump (data  ) 6f 6c 69 67 20 6e 69 68 74 73 72 6f 2e 79 20 22 22 22 77 20 6d 74 28 70 29 35 2e 0a 78 78 22 20  login history." "" wtmp(5)..xx "
Dump (data  ) 20 22 22 22 22 20 75 77 70 6d 20 3a 68 74 20 65 61 67 65 6d 6f 20 20 66 75 68 74 6e 74 2d 65 68  " "" "wump: the game of hunt-the
Dump (data  ) 77 2d 6d 75 75 70 2e 73 20 22 22 22 77 20 6d 75 28 70 29 36 2e 0a 78 78 22 20 68 73 72 61 64 65  -wumpus." "" wump(6)..xx "shared
Dump (header) a1 fe b4 03 0a 7a 08 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 63 65 74 75 20 65 6f 63 6d 6d 6e 61 20 64 65 72 65 70 74 61 64 65 79 6c 0a 2e 73 63 28 68  ..ecute command repeatedly..csh(
Dump (data  ) 29 31 73 20 74 65 20 3a 68 63 6e 61 65 67 76 20 6c 61 65 75 6f 20 20 66 68 73 6c 65 20 6c 61 76  1) set: change value of shell va
Dump (data  ) 69 72 62 61 65 6c 0a 2e 73 63 28 68 29 31 73 20 74 65 6e 65 3a 76 73 20 74 65 76 20 72 61 61 69  riable..csh(1) setenv: set varia
Dump (data  ) 6c 62 20 65 6e 69 65 20 76 6e 72 69 6e 6f 65 6d 74 6e 0a 2e 73 63 28 68 29 31 73 20 69 68 74 66  ble in environment..csh(1) shift
Dump (header) a1 fe b4 03 02 fb 00 00 00 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 64 6e 6c 20 6e 61 75 67 67 61 2e 65 20 22 22 22 73 20 28 68 29 31 2e 0a 78 78 22 20 20 22  ..nd language." "" sh(1)..xx ""
Dump (data  ) 6c 22 67 6f 6e 69 22 3a 22 20 69 73 6e 67 6f 20 2e 6e 20 22 22 22 6c 20 67 6f 6e 69 31 28 0a 29  "login:" "sign on." "" login(1).
Dump (data  ) 78 2e 20 78 22 22 22 20 61 70 73 75 3a 65 73 20 6f 74 20 70 6e 75 69 74 22 6c 22 20 69 73 6e 67  .xx "" "pause: stop until" "sign
Dump (data  ) 6c 61 22 2e 22 20 20 22 61 70 73 75 28 65 29 32 2e 0a 78 78 22 20 20 22 61 22 61 6c 6d 72 20 3a  al." "" pause(2)..xx "" "alarm:
Dump (header) a1 fe b4 03 0b 6a 29 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 65 22 65 78 3a 63 6f 20 65 76 6c 72 79 61 73 20 65 68 6c 6c 77 20 74 69 22 68 22 20 70 73  .."exec: overlay shell with" "sp
Dump (data  ) 63 65 66 69 65 69 20 64 6f 63 6d 6d 6e 61 2e 64 20 22 22 22 63 20 68 73 31 28 0a 29 78 2e 20 78  ecified command." "" csh(1)..xx
Dump (data  ) 22 22 22 20 78 65 65 74 72 72 2d 20 74 20 72 75 20 6e 6e 6f 6f 2f 66 66 74 20 65 68 65 20 74 78  "" "exterr - turn on/off the ext
Dump (data  ) 6e 65 65 64 20 64 72 65 6f 72 73 72 69 20 20 6e 68 74 22 65 22 20 70 73 63 65 66 69 65 69 20 64  ended errors in the" "specified
Dump (header) a1 fe b4 03 03 eb 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 66 69 5c 20 02 77 5c 5c 34 24 20 02 64 2e 20 73 33 73 7e 20 5c 7e 0a 22 64 2e 20 73 34 73  ..if \w.\\$4. .ds s3 ~~\"..ds s4
Dump (data  ) 7e 20 5c 7e 0a 22 64 2e 20 73 35 73 7e 20 5c 7e 0a 22 64 2e 20 73 20 79 5c 5c 28 2a 34 73 66 5c   ~~\"..ds s5 ~~\"..ds y \\*(s4\f
Dump (data  ) 01 33 66 5c 5c 50 2a 5c 73 28 0a 35 74 2e 20 61 2e 39 69 30 5c 2d 02 77 5c 5c 28 2a 35 73 75 02  3.\fP\\*(s5..ta 9.0i-\w.\\*(s5.u
Dump (data  ) 5c 0a 22 68 2e 34 69 35 5c 2d 02 77 5c 5c 31 24 5c 5c 28 2a 31 73 5c 5c 32 24 5c 5c 28 2a 32 73  .\h"4.5i-\w.\\$1\\*(s1\\$2\\*(s2
Dump (header) a1 fe b4 03 0c 1a ce 00 00 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 64 20 73 65 72 63 62 69 64 65 61 0a 20 73 74 69 69 20 2c 73 6e 20 74 6f 61 20 20 73 74 69  .. described.as it is, not as it
Dump (data  ) 73 20 6f 68 6c 75 20 64 65 62 0a 2e 6e 49 76 65 74 69 62 61 79 6c 20 2c 68 74 73 69 6d 20 61 65   should be..Inevitably, this mea
Dump (data  ) 73 6e 74 20 61 68 0a 74 61 76 69 72 75 6f 20 73 65 73 74 63 6f 69 73 6e 77 20 6c 69 20 6c 6f 73  ns that.various sections will so
Dump (data  ) 6e 6f 62 20 20 65 75 6f 20 74 66 6f 64 20 74 61 2e 65 2e 0a 50 4c 54 0a 65 68 76 20 6c 6f 6d 75  on be out of date...LP.The volum
Dump (header) a1 fe b4 03 04 9b c6 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 73 63 28 68 29 31 61 20 69 6c 73 61 20 3a 68 73 6c 65 20 6c 61 6d 72 63 73 6f 0a 2e 73 63  ..csh(1) alias: shell macros..cs
Dump (data  ) 28 68 29 31 62 20 65 72 6b 61 20 3a 78 65 74 69 77 20 69 68 65 6c 66 2f 72 6f 61 65 68 63 6c 20  h(1) break: exit while/foreach l
Dump (data  ) 6f 6f 2e 70 63 0a 68 73 31 28 20 29 72 62 61 65 73 6b 3a 77 65 20 69 78 20 74 72 66 6d 6f 73 20  oop..csh(1) breaksw: exit from s
Dump (data  ) 69 77 63 74 2e 68 63 0a 68 73 31 28 20 29 61 63 65 73 20 3a 65 73 65 6c 74 63 72 6f 69 20 20 6e  witch..csh(1) case: selector in
Dump (header) a1 fe b4 03 0d 0a ef 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 20 73 6f 63 64 6e 74 69 6f 69 61 6e 6c 6c 2e 79 63 0a 68 73 31 28 20 29 3a 40 61 20 69 72  ..s conditionally..csh(1) @: ari
Dump (data  ) 68 74 65 6d 69 74 20 63 6e 6f 73 20 65 68 6c 6c 76 20 72 61 61 69 6c 62 73 65 0a 2e 00 00 00 00  thmetic on shell variables......
Dump (data  ) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
Dump (data  ) 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................................
Dump (header) a1 fe b4 03 05 8b e7 00 00 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 6e 61 3a 68 68 20 70 79 72 65 6f 62 69 6c 20 63 75 66 63 6e 69 74 6e 6f 2e 73 20 22 22 22  ..anh: hyperbolic functions." ""
Dump (data  ) 73 20 6e 69 28 68 4d 33 0a 29 78 2e 20 78 22 22 22 20 75 6e 6c 6c 20 3a 61 64 61 74 20 22 73 22   sinh(3M)..xx "" "null: data" "s
Dump (data  ) 6e 69 2e 6b 20 22 22 22 6e 20 6c 75 28 6c 29 34 2e 0a 78 78 22 20 20 22 73 22 7a 69 3a 65 20 22  ink." "" null(4)..xx "" "size:"
Dump (data  ) 73 22 7a 69 20 65 66 6f 61 20 20 6e 62 6f 65 6a 74 63 66 20 6c 69 2e 65 20 22 22 22 73 20 7a 69  "size of an object file." "" siz
Dump (header) a1 fe b4 03 0e 3a 8c 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 74 69 22 3a 22 20 70 73 69 6c 20 74 20 61 69 66 65 6c 69 20 74 6e 20 6f 69 70 63 65 73 65  ..it:" "split a file into pieces
Dump (data  ) 22 2e 22 20 20 22 70 73 69 6c 28 74 29 31 2e 0a 78 78 22 20 20 22 66 22 65 72 70 78 20 2c 64 6c  ." "" split(1)..xx "" "frexp, ld
Dump (data  ) 78 65 2c 70 6d 20 64 6f 3a 66 20 22 73 22 6c 70 74 69 69 20 74 6e 20 6f 61 6d 74 6e 73 69 61 73  exp, modf:" "split into mantissa
Dump (data  ) 61 20 64 6e 65 20 70 78 6e 6f 6e 65 2e 74 20 22 22 22 66 20 65 72 70 78 33 28 0a 29 78 2e 20 78   and exponent." "" frexp(3)..xx
Dump (header) a1 fe b4 03 06 bb 84 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 61 2e 20 66 4e 50 69 20 2e 0a 6e 70 35 20 2e 0a 65 64 49 20 0a 52 66 5c 5c 49 24 5c 5c 31  ...af PN i..pn 5..de IR.\fI\\$1\
Dump (data  ) 5c 5e 52 66 5c 5c 32 24 2e 0a 0a 2e 64 2e 20 65 49 52 5c 0a 52 66 5c 5c 31 24 66 5c 5c 49 24 5c  ^\fR\\$2.....de RI.\fR\\$1\fI\\$
Dump (data  ) 5c 32 5c 5e 52 66 5c 5c 33 24 2e 0a 0a 2e 54 2e 0a 4c 4e 49 52 54 44 4f 43 55 49 54 4e 4f 54 20  2\^\fR\\$3.....TL.INTRODUCTION T
Dump (data  ) 20 4f 4f 56 55 4c 45 4d 31 20 2e 0a 50 4c 54 0a 69 68 20 73 6f 76 75 6c 65 6d 67 20 76 69 73 65  O VOLUME 1..LP.This volume gives
Dump (header) a1 fe b4 03 0f 2a ad 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 6d 6f 61 6d 64 6e 20 73 65 67 65 6e 61 72 6c 6c 20 79 65 72 69 73 65 64 69 20 20 6e 69 64  ..ommands generally reside in di
Dump (data  ) 65 72 74 63 72 6f 0a 79 49 2e 2f 20 69 62 0a 6e 66 28 72 6f 2e 0a 52 49 62 20 6e 69 5c 20 61 7c  rectory..I /bin.(for..IR bin \|a
Dump (data  ) 79 72 70 0a 6f 72 72 67 6d 61 29 73 0a 2e 6f 53 65 6d 70 20 6f 72 72 67 6d 61 20 73 6c 61 6f 73  ry.programs)..Some programs also
Dump (data  ) 72 20 73 65 64 69 20 65 6e 69 2e 0a 0a 49 5c 2f 75 7c 72 73 5c 2f 62 7c 6e 69 0a 2c 52 2e 6f 0a   reside in..I./\|usr/\|bin,..R.o
Dump (header) a1 fe b4 03 07 ab a5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 6d 6d 6e 61 2e 64 63 0a 68 73 31 28 20 29 78 65 74 69 20 3a 65 6c 76 61 20 65 68 73 6c 65  ..mmand..csh(1) exit: leave shel
Dump (data  ) 2e 6c 63 0a 68 73 31 28 20 29 6f 66 65 72 63 61 3a 68 6c 20 6f 6f 20 70 76 6f 72 65 6c 20 73 69  l..csh(1) foreach: loop over lis
Dump (data  ) 20 74 66 6f 6e 20 6d 61 73 65 0a 2e 73 63 28 68 29 31 67 20 6f 6c 3a 62 66 20 6c 69 6e 65 6d 61  t of names..csh(1) glob: filenam
Dump (data  ) 20 65 78 65 61 70 64 6e 61 20 67 72 6d 75 6e 65 20 74 69 6c 74 73 0a 2e 73 63 28 68 29 31 67 20  e expand argument list..csh(1) g
Dump (header) a1 fe b4 03 10 c9 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 78 2e 20 78 69 22 74 6e 6f 72 20 22 69 22 74 6e 6f 72 75 64 74 63 6f 69 20 6e 6f 74 63 20  ...xx "intro" "introduction to c
Dump (data  ) 6d 6f 61 6d 64 6e 22 73 2e 0a 78 78 22 20 64 61 22 62 22 20 65 64 75 62 67 67 72 65 0a 22 78 2e  ommands"..xx "adb" "debugger"..x
Dump (data  ) 20 78 61 22 6d 64 6e 69 20 22 63 22 65 72 74 61 20 65 6e 61 20 64 64 61 69 6d 69 6e 74 73 72 65  x "admin" "create and administer
Dump (data  ) 53 20 43 43 20 53 69 66 65 6c 22 73 2e 0a 78 78 22 20 72 61 20 22 61 22 63 72 69 68 65 76 61 20   SCCS files"..xx "ar" "archive a
Dump (header) a1 fe b4 03 08 5a 4a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 65 74 20 64 69 66 65 6c 2e 73 20 22 22 22 63 20 6d 6f 28 6d 29 31 2e 0a 78 78 22 20 20 22  ..ted files." "" comm(1)..xx ""
Dump (data  ) 6c 22 6f 6f 3a 6b 66 20 6e 69 20 64 69 6c 65 6e 20 73 6e 69 61 20 20 22 73 22 72 6f 65 74 20 64  "look: find lines in a" "sorted
Dump (data  ) 69 6c 74 73 22 2e 22 20 20 22 6f 6c 6b 6f 31 28 0a 29 78 2e 20 78 22 22 22 20 6b 6d 74 73 3a 72  list." "" look(1)..xx "" "mkstr:
Dump (data  ) 63 20 65 72 74 61 20 65 6e 61 65 20 72 72 72 6f 6d 20 73 65 61 73 65 67 66 20 6c 69 20 65 79 62   create an error message file by
Here is what I have been able to figure out about the format. First of all, the information in the hardware manual for the Callan winchester controller is wrong and generally confused. Few people probably ever knew or cared what the format on the disk looked like. Here is what I see:
Dump (header) a1 fe 2c 13 0f f8 46 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 bd 2f 00 00
The data part is easy. We get the 2 bytes "a1 f8" and then 512 bytes of data follows. Probably 4 bytes of CRC/ECC follows that.

The header is as follows:

a1, fe - synch bytes
2c - low 8 bits of cylinder
13 - cyl_high<<4 | head
0f - sector number
f8, 46 - CRC
Here the cylinder number is 0x12c, which is 300 and that is correct.

So I extended the program to simply count how many sectors there were on each track and had it loop over the entire disk. I pulled the cylinder and head from the sector header information I just figured out. It all is fine up through cylinder 305, then things get weird.

CH =  316 5 -- 17 sectors
CH =  316 6 -- 17 sectors
CH =  316 7 -- 17 sectors
CH =  317 0 -- 10 sectors
CH = 4095 15 -- 9 sectors
CH = 3903 15 -- 14 sectors
CH =  316 3 -- 12 sectors
CH =    0 0 -- 11 sectors
CH =    0 0 -- 9 sectors
CH =  317 6 -- 9 sectors
CH =  317 7 -- 7 sectors
CH =  318 0 -- 17 sectors

I can use my track dumper to look at a specific track in detail (such as track 317:1) Here is that track:

[tom@trona mfm]$ ./mfm_dump callan_raw1 -l 32 -c 317 -h 1 -d
Track for 317:1 -- 73079 bytes
Initial bit sep time: 20.000
Dump (header) a1 f8 00 00 4a 38 00 00 4a 38 00 00 49 38 00 00 4a 38 00 00 09 38 00 00
Dump (data  ) a1 87 ff ff 21 83 ff ff 21 87 ff ff 21 87 ff ff 21 87 ff ff 21 87 ff ff 21 87 ff ff 21 87 ff f3  .....!...!...!...!...!...!...!..
Dump (header) a1 54 38 00 29 99 00 00 28 f9 00 00 28 19 00 00 0c 52 3c 00 08 92 3c 00
Dump (data  ) a1 f8 00 00 a3 38 00 00 a3 38 00 00 a3 38 00 00 a3 38 00 00 a3 38 00 00 a3 38 00 00 a3 38 00 00  ....8...8...8...8...8...8...8...
Dump (header) a1 fe 3d 11 0f ea 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 fe 3d 19 07 6b 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 87 e0 00 02 94 e0  ...=k...........................
Dump (header) a1 08 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a1 08 00 00 a5 38 00 00
Dump (data  ) a1 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 84 38 00 01  8...8...8...8...8...8...8...8...
Dump (header) a1 00 00 00 84 38 00 00 a5 38 00 00 a5 38 00 00 a1 38 00 00 a5 3c 00 00
Dump (data  ) a1 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a1 00 00 00 a5 38 00 00  8...8...8...8...8...8.......8...
Dump (header) a1 38 00 00 a5 38 00 01 a1 00 00 00 a5 38 00 00 a1 30 00 00 a5 38 00 00
Dump (data  ) a1 00 00 00 a5 3c 00 00 a5 38 00 00 a5 38 00 00 a1 00 00 00 84 38 00 01 a1 00 00 00 84 38 00 00  ....<...8...8.......8.......8...
Dump (header) a1 38 00 00 a5 38 00 00 a1 00 00 00 84 38 00 01 21 00 00 00 84 38 00 00
Dump (data  ) a1 08 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 b5 38 00 00 a5 38 00 00 a5 38 00 00 a4 38 00 00  ....8...8...8...8...8...8...8...
Dump (header) a1 08 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 01 21 00 00 00 a5 38 00 00
Dump (data  ) a1 00 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00  ....8...8...8...8...8...8...8...
Dump (header) a1 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00 a5 38 00 00
Dump (data  ) a1 fe 3d 11 10 09 a9 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff e0 40 7f ff e0 78 7f  ...=.......................@...x
Dump (header) a1 e1 ff ff 81 e1 ff ff a5 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 f1 ff ff
Dump (data  ) a1 e1 ff ff 81 f1 ff ff 81 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 f1 ff ff a1 e1 ff ff 81 e1 ff ff  ................................
Dump (header) a1 e1 ff ff 81 e1 ff ff 85 e1 ff ff 81 f1 ff ff 85 e1 ff ff 81 e1 ff ff
Dump (data  ) a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff 81 e1 ff ff 81 e1 ff ff  ................................
Dump (header) a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff 85 e1 ff ff 81 e1 ff ff
Dump (data  ) a1 e1 ff ff 81 f1 ff ff a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff  ................................
Dump (header) a1 e1 ff ff 81 f1 ff ff 81 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff
Dump (data  ) a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff  ................................
Dump (header) a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff 85 e1 ff ff 81 e1 ff ff
Dump (data  ) a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff 81 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff  ................................
Dump (header) a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff
Dump (data  ) a1 e1 ff ff 81 e1 ff ff 85 e1 ff ff 81 e1 ff ff 85 e1 ff ff 81 e1 ff ff a1 e1 ff ff 81 e1 ff ff  ................................
Dump (header) a1 e1 ff ff 81 e1 84 01 81 80 30 01 39 39 39 39 39 39 39 39 39 39 39 39
Dump (data  ) a1 fe 3d 11 08 9a 90 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff
This looks badly garbled. the first mark we see should be a header (with a1 fe), but it looks like we found a sector mark. And other marks don't look like marks at all. I guess I should check the second byte when I think I have a sector header and see if it is 0xfe like it should be.

I add logic to check the second byte and discover these kinds of things are scattered around the entire disk. Here is a bad spot on CH = 8:6 for example.

Dump (header) a1 fe 08 06 0a 0e 63 00 00 00 00 3f ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 00 00 5f 18 4b 9d 00 00 01 00 a4 81 00 00 f5 00 00 00 07 01 00 00 34 00 00 00 00 00 00 00  ....._.K.................4......
Dump (header) a1 ff 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21
Dump (data  ) a1 fe 08 06 02 8f 6b 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff fe 14 07 ff ff 81 83 89  .......k........................
Dump (header) a1 fe 08 06 0b 1e 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 00 00 00 00 00 00 00 40 00 00  ....................A.......@...
Dump (header) a1 fe 08 06 03 9f 4a 00 00 00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff
Dump (data  ) a1 f8 31 30 02 00 00 04 00 00 2e 32 32 4c 30 30 33 30 02 00 00 04 00 00 2e 54 32 4c 30 30 35 30  ..01......2.L20003......T.L20005
Dump (header) a1 fe 08 06 0c 6e a5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Dump (data  ) a1 f8 00 04 00 00 2e 00 31 53 20 00 00 04 00 00 61 00 6d 66 6c 75 20 00 00 04 00 00 5f 00 63 73  ........S1. .....afmul. ....._sc
My logic for recognizing marks may be too naive. David has fancy logic that might handle this, so what I ought to do is put my energy into working up a custom format and then take advantage of his knowledge and experience by using his software.

So, add a custom format

Here is how you do it: I study these instructions, then dive in. The Callan is just a minor tweak on the WANG_2275_B with the head and upper cylinder bits in the same word (3) in the header, but the boundary is shifted by one bit. I add "CALLAN" to the collection, rebuild mfm_util and run it to get:
mfm_util --format CALLAN --sectors 17,0 --heads 8 --cylinders 320 --header_crc 0xffff,0x1021,16,0 --data_crc  0xffffffff,0x140a0445,32,6 --sector_length 512  --extr
acted_data_file callan2_unswap.img --transitions_file callan_raw1
Original decode arguments: --heads 8 --cylinders 320 --sector_length 512 --retries 50,4 --drive 1
At cyl 0
At cyl 10
At cyl 50
At cyl 250
ECC Corrections on cylinder 305 head 0: 13(1)
Bad sectors on cylinder 307 head 0: 2 3 4H 5H 6 7H 10 11 12 14
ECC Corrections on cylinder 307 head 0: 13(1)
Bad sectors on cylinder 307 head 1: 2 3 5 10 11 13 14 15
ECC Corrections on cylinder 307 head 1: 12(1)
Bad sectors on cylinder 307 head 2: 3 5 11 12
Bad sectors on cylinder 307 head 3: 3 5 11 12 13H 15
ECC Corrections on cylinder 307 head 3: 1(1) 10(1)
Bad sectors on cylinder 307 head 4: 11 12
Bad sectors on cylinder 307 head 5: 4 12
Bad sectors on cylinder 307 head 6: 2H 10H 11H 12
ECC Corrections on cylinder 307 head 6: 4(1)
Bad sectors on cylinder 307 head 7: 5 12
ECC Corrections on cylinder 307 head 7: 11(1)
Bad sectors on cylinder 309 head 0: 0H 1 2H 3H 4H 5H 6H 7 9H 10H 11 12H 13H 14H 15H 16
Bad sectors on cylinder 309 head 1: 0 1 2H 3H 4H 5H 6H 7H 9 10 11 12 13H 14 15
Bad sectors on cylinder 309 head 2: 1H 2H 3H 4H 5H 6H 7H 10 11 12 13 16
ECC Corrections on cylinder 309 head 2: 15(1)
Bad sectors on cylinder 309 head 3: 1H 2H 3H 4H 5H 6H 7 9H 10 11H 12H 13H 14H 15H 16
ECC Corrections on cylinder 309 head 3: 8(1)
Bad sectors on cylinder 309 head 4: 1 2H 3H 4 6H 7H 9 10 11H 12H 13 14H 16
Bad sectors on cylinder 309 head 5: 2 3 4 6 9 12H 13H 15
ECC Corrections on cylinder 309 head 5: 11(1) 14(1)
Bad sectors on cylinder 309 head 6: 2H 3H 4H 5H 6H 7H 9 10 11 12
ECC Corrections on cylinder 309 head 6: 0(1) 14(1) 15(1)
At cyl 310
ECC Corrections on cylinder 309 head 7: 0(1) 1(1) 8(1)
Bad sectors on cylinder 311 head 0: 0 2H 3H 4H 5H 6H 7 9 10H 11 12H 13H 14H 15H 16
ECC Corrections on cylinder 311 head 0: 1(1)
Bad sectors on cylinder 311 head 1: 0 1 2H 3H 4H 5H 6H 8 10H 11H 12H 13H 14H 15 16
Bad sectors on cylinder 311 head 2: 0 1 2 3 4H 6 10 12H 13
ECC Corrections on cylinder 311 head 2: 11(1)
Bad sectors on cylinder 311 head 3: 2 3H 4 5 10 11H 12 13H 14 15
Bad sectors on cylinder 311 head 4: 1 2 4 10 11 12 13
ECC Corrections on cylinder 311 head 4: 14(1)
Bad sectors on cylinder 311 head 5: 2 3 4 6 12
ECC Corrections on cylinder 311 head 5: 10(1) 11(1) 13(1) 14(1)
Bad sectors on cylinder 311 head 6: 1 2 3 4 6 7 11 12 13
Bad sectors on cylinder 311 head 7: 2 3 4 6 7 11 12 13
ECC Corrections on cylinder 311 head 7: 8(1) 10(1)
Bad sectors on cylinder 313 head 0: 1 2 3 4 5 6 7 8 9 10 11H 12H 13 14H 16H
Bad sectors on cylinder 313 head 1: 0H 1 2H 3H 4H 5H 6H 7 8 9H 10H 11H 12H 13H 14H 15
Bad sectors on cylinder 313 head 2: 2H 3 5 6 11 12H 13H 14H
Bad sectors on cylinder 313 head 3: 2 3 4 5 11H 12H 13
ECC Corrections on cylinder 313 head 3: 1(1)
Bad sectors on cylinder 313 head 4: 2 3 4 10 11H 12H 13 14
ECC Corrections on cylinder 313 head 4: 1(1)
Bad sectors on cylinder 313 head 5: 0 1 3 4 11 12 13 15
Bad sectors on cylinder 313 head 6: 1 2 3 4H 5 10 11 12H 13
Bad sectors on cylinder 313 head 7: 2 3 4H 10 11
ECC Corrections on cylinder 313 head 7: 1(1)
Bad sectors on cylinder 315 head 0: 0 1H 2H 3H 4H 5H 6H 7H 8H 9H 10 11H 12H 13H 14H 15H 16
Bad sectors on cylinder 315 head 1: 0 1 2H 3H 4H 5 6H 7 8 9 10 11 12H 13H 14H 15 16
Bad sectors on cylinder 315 head 2: 1 2 3H 4H 5 6 8 9 10 11 12H 13H 14H 15 16
Bad sectors on cylinder 315 head 3: 0 1 2 3H 4H 5H 6 7 8 9 10 11 12H 13H 14 15
Bad sectors on cylinder 315 head 4: 0 1 2 3 4 5 6H 7 8 9 10 11H 12H 13H 14
ECC Corrections on cylinder 315 head 4: 16(1)
Bad sectors on cylinder 315 head 5: 1H 2H 3 4H 5H 6 7 8H 10 11H 12H 13H 14H
Bad sectors on cylinder 315 head 6: 0H 1H 2H 3H 4H 5H 6H 7 8 9 10H 11H 12H 13H 14 15 16
Bad sectors on cylinder 315 head 7: 1 2 3 4 5 7 8 9H 10H 11H 12H 13H 14H 15H 16
Bad sectors on cylinder 317 head 0: 0H 1H 2H 3H 4H 5H 6H 7H 8H 9H 10H 11H 12H 13H 14H 15H 16
Bad sectors on cylinder 317 head 1: 0H 1H 2H 3H 4H 5H 6H 7H 8 9H 10H 11H 12H 13H 14H 15H 16
Bad sectors on cylinder 317 head 2: 0H 1H 2H 3H 4H 5H 6 7 8H 9H 10H 11H 12H 13H 14H 15H
Bad sectors on cylinder 317 head 3: 0 1 2H 3H 4H 5H 6 8H 9 10H 11H 12H 13H 14H 15H 16
Bad sectors on cylinder 317 head 4: 0 1 2H 3H 4 5H 6 7 8H 9 10H 11H 12H 13H 14 15 16
Bad sectors on cylinder 317 head 5: 0 1H 2H 3H 4H 5H 6 7H 8H 9H 10H 11H 12H 13H 14H 15H 16H
Bad sectors on cylinder 317 head 6: 0 1 2H 3H 4H 5H 6H 7 8 9H 10H 11H 12H 13H 14H 15 16
Bad sectors on cylinder 317 head 7: 0H 1H 2H 3H 4H 5 6H 7H 8 9H 10H 11H 12H 13H 14 15 16
Bad sectors on cylinder 319 head 0: 0H 1H 2H 3H 4H 5H 6H 7 8H 9H 10H 11H 12H 13H 14H 15 16
Bad sectors on cylinder 319 head 1: 0H 1 2H 3H 4H 5H 6H 7 8 9 10H 11H 12H 13H 14H 15H 16H
Bad sectors on cylinder 319 head 2: 0 1 2 3H 4 5 6 7 8H 9 10H 11H 12H 13H 14H 15H 16
Bad sectors on cylinder 319 head 3: 0 1 2H 3H 4 5H 6 7 8H 10 11 12H 13H 14H 15 16
Bad sectors on cylinder 319 head 4: 0 2 3 4 5 6 7 9 10 11 12 13H 15
ECC Corrections on cylinder 319 head 4: 1(1) 14(1) 16(1)
Bad sectors on cylinder 319 head 5: 0 1H 2H 3H 4H 5H 6H 7H 9 10 11 12 13 14 15 16
Bad sectors on cylinder 319 head 6: 0 1 2H 3H 4H 5 6 7 8 9H 10H 11H 12H 13 14 16
Bad sectors on cylinder 319 head 7: 0H 1 2H 3 4 5 6H 7 8H 9 10 11 12H 13H 14H 15H 16
Found cyl 0 to 319, head 0 to 7, sector 0 to 16
Expected 43520 sectors got 42839 good sectors, 342 bad header, 339 bad data
0 sectors marked bad or spare
34 sectors corrected with ECC. Max bits in burst corrected 2
[tom@trona MFM]$
dd if=callan2_unswap.img of=callan2.img conv=swab
43520+0 records in
43520+0 records out
22282240 bytes (22 MB, 21 MiB) copied, 0.107339 s, 208 MB/s
[tom@trona MFM]$
ls -l callan2.img
-rw-rw-r-- 1 tom tom  22282240 May 26 18:00 callan2.img
This may well be as good as I am going to get. The disk seems to have serious trouble past cylinder 305, but that means I am only loosing 15 of the 320 cylinders.

The thing to do now is analyze the disk image, see if I can find an old style unix filesystem on it, and either find some way to mount it on linux, or else write my own file extractor for it.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org