This text contains some background technical info. It is not a manual, but it fills in some data regarding the problems with disk control and how things are implemented. (And I love to talk about it after all this work) INTRODUCTION The rotational speed of an Amiga disk is 300 rpm. The time of one revolution is .2 seconds. Data is sampled at .5 MHz. So a track on an Amiga floppy disk contains 100000 bits. This can vary a little due to motor speed variations. Alas we cannot put any desired pattern in these bits. Therefore data is converted to patterns which are allowed. This conversion, called MFM-encoding, has an efficiency of 50 percent. For every bit of data two bits of the magnetic track are used. We can picture an encoded sector as follows: 4 bytes inter sector gap 4 bytes sync pattern 8 bytes sector ID 32 bytes label 8 bytes checksum over sector ID and label 8 bytes checksum over data block 1024 bytes data block Therefore the size of a sector is 1088*8=8704 bits. 100000/8704=11, remainder 4256. Thus we can store 11 sectors. We have 4256 bits left we do not use for storage. Instead these bits allow us to accept a motor speed increase of 4.25 %. If we allow the same speed decrease, we must be able to supply a non used space of roughly 8500 bits or 1100 bytes. In fact, Trackdisk is prepared for an unused space of 1660 bytes. (Why that much?) Trackdisk does not write separate sectors as found on other systems. Instead it writes out a complete track, actually reformatting the track. That is why blocks can be so tight together. (On the other systems you need gaps between the sectors and between sector ID and data block to allow soft and hardware to synchronize) If Trackdisk writes out a track, it begins with the 1660 bytes gap, followed by the sectors. Although the sectors are written out in order, the first sector can be any of the eleven. The last sector is written over the begin of the gap, thus effectively removing old data and patterns. Although Trackdisk allows for synchronization with the disk index, this is normally not used; Trackdisk just starts writing when it is ready to do so. Reading is something else. If Trackdisk should wait for the gap to pass, average halve a tracktime is done nothing. Therefore reading is started, ignoring where the head is in the track. To ensure that all sectors are read, the readsize must be one sector larger than the number of available sectors. And the gap must be read too. This results in a readsize of 12*1088+1660=14716 bytes or 117728 bits, 18% more than a physical track. Usually the read is started somewhere within a sector, continues until the gap, the gap itself and enough sectors after the gap to cover the whole track. Reading and writing is done by DMA (Direct Memory Access) and word wide (16 bits). Therefore data read from disk can be in memory shifted up to 15 bits. The part behind the gap has no exact relation in position and shift to the first read part. To recover the track, a search is started for a sync pattern. If found, this informs us about the shift. Knowing the shift, the following sector id can be decoded. This sector id has the following form and are all bytes: $ff (formatbyte) tracknumber sectornumber number of sectors until gap The last item "number of sectors until gap" tells us how large the part is with the current shift. This part is shifted and moved to the begin of the data part of the trackbuffer. Then a second search for a syncword is done, starting behind the first part. The remaining sectors are found and moved and shifted tight behind the first part. Now there is in the buffer a block of 11 sectors and after updating the last items of the sector id's, "number of sectors until gap", the track is ready to be written again. But before that a lot can go wrong. If some syncword or intersector gap is distorted, or one of the 22 checksums is wrong, Trackdisk stops and returns an error. If the error concerns a syncword or a gap, or if a faulting checksum belongs to a sector ID, it is likely that all data can be recovered (except for the label, but that is not used by Dos). And if the checksum belongs to a data block, but this data block is not requested, then the other blocks could be read without a problem. Of course a track with an error must not be written back to disk. SALVE FUNCTION The salve function of TrackSalve reads data from disk in such a large buffer, that there will be an uninterrupted array of sectors in this buffer. If one sector can be found with a good checksum over its header, all data to calculate the position of the other sectors is available. The data and label blocks are copied to the original buffer, this time with sector 0 in the first position. If the checksum of the current block is correct, a corresponding bit is cleared in a word that is initiated with 11 ones. Such a word exists as well for the data as the label blocks. There is a byte that contains normally the number of the first sector, but it will contain an error number if the track is bad. The Trackdisk errors start at 20, so if the byte is larger than 10, the track is bad. Somewhere within trackdisk this is tested and as result the tracknumber is set to -1, meaning "trackbuffer not valid". Therefore any subsequent read request will result in a seek and several read retries of the track. If the salve function is active, this invalidation of the tracknumber is prevented. Instead the first sector byte is tested at a read request and if this indicates an error, the bitpattern with bad blocks are tested. As soon as the request concerns a bad block, the error value and the number of transferred bytes is set and fixed, but transfers continues until the number of requested bytes are copied. There is no difference between the original behavior of trackdisk and the salve function other than the bonus of the extra transferred data (IO_ERROR contains the error and IO_ACTUAL contains the number of bytes without error). If label transfers is switched on, IO_ACTUAL presents the number of sectorbytes transferred until an error is encountered in a label OR sector. Some specialized recovery program can use this info to recover more data at the cost of accuracy, which may be acceptable in some cases. A write to the same track still will set this tracknumber to -1, and the normal retry scheme will be used. The salve function is rather introvert and will at a priority of +5 disturb the feeling of the Amiga. So the priority is lowered to -2 during track salvage. MFM FLAW How heavy the tests are on the track read from disk, there is a serious gap (to my opinion) in these integrity checks. As stated earlier, not every pattern is allowed in the magnetic track. A MFM encoded data block exist of true data bits and timing bits. The databits are always valid: these are not coded, but the timing bits, these are to be found between the data bits, are meaningless as data. They are just there to prevent too much and to less subsequent magnetic transitions. Too much is beyond the bandwidth of the medium and too less may lead to loss of synchronization and gives noise a chance. The used recording technique is a transition on a one and no transition on a zero. MFM coding defines patterns where a one always is followed by a zero, and there are never more than three subsequent zeros. What happens if there are two subsequent ones? Or more than three zeros? The system is not that sensitive that this immediately will lead to bad reads of the data containing bits. And Trackdisk maintains checksums over encoded data, or..? But ONLY over the data bits, NOT over the timing bits! If a timing bit is read wrong from disk, this will not be detected. The sector is copied to a new position in the trackbuffer, and if an other sector is changed, it will be written back to disk with the faulting timing bit! If the sector is not updated (eg belonging to a program) this faulting bit will stay forever. Slowly all timing bits can disappear due to the retry scheme of trackdisk. At a moment the track will be unreadable. Especially the roottrack is sensitive for this phenomena. TrackSalve has modified Trackdisk in such way that just before a track is written to disk, all timing bits are set according to the MFM standard. This takes very little time because it is all done by the blitter. Now that it is ensured that the track is MFM updated before it goes to disk, the encoding routines can ignore these bits, and that saves cpu time. Because the encoding routines were rewritten, it was easy to allow non chip memory for IO buffers. Non-chip buffers are copied by the cpu at the most efficient way (cribbed from exec's CopyMem()), although CopyMem() is used if it is replaced. BUGS IN TRACKDISK I knew of two bugs and found a third. These all are repaired in TrackSalve. Raw read and write had problems because IO_LENGTH was compared with $8000 instead of #$8000. The difference is that IO_LENGTH should be compared with the value 8000 hex. Instead it was compared with some value that was at memory location 8000 hex. In a multitasking environment the hardware must be shared between the concurrent tasks. There can be up to four drives connected to the Amiga. For each drive a Trackdisk task is started (all executing the same code but with separate data area's). These four drives are controlled by one piece of hardware (some custom chip I forgot the name but I know its address). The TD-tasks use it to control their particular drives. The tasks ask permission to the disk.resource to access this chip directly by a call named GetUnit(). If the task is ready with it, this is told to the disk.resource by a call named GiveUnit(). Another TD-task that perhaps was waiting for it, gets access permission. There is a nasty bug in Trackdisk which could disturb the permission scheme. Because a branch was too far, a call to GetUnit() was missed if that drive was empty. The task assumed permission, did some access and called GiveUnit(). This is not as bad as it looks, because the time of violated hardware access is very short, and was very short after a permitted access. But if another TD-task had got permission (and the more drives the more likely this will happen), the turnips are cooked. The other tasks commands to the hardware are possibly destroyed and to make matters worse, it looses its permission to access by the first tasks call to GiveUnit(). So now this ignorant task is violating the rules. The patch done by the setpatch program modifies disk.resource in such way that only GiveUnits() are valid from tasks that did the GetUnit(). The access violation was not repaired. During the tests with special Trackdisk IO programs, some strange behavior of Trackdisk came up. Dos is very precise in its IO with Trackdisk, but a Trackdisk tester is not. That must explain why this was not disturbing more general. If a write to a protected disk was done, this disk became unreadable for all other tracks than that was just written to. Reads via Dos resulted in a Read/Write error requester although retry selection solved the problem (CMD_CLEAR). A new bug in Trackdisk? Yes! If you write a sector to a protected disk, first the track is read into the trackbuffer, followed by a copy of the sector into this buffer, replacing the original, and a flag is set, meaning "trackbuffer changed". If you want to read a sector from another track, trackdisk tries to flush (write to disk) its trackbuffer. The disk is protected and the attempt will fail. So you cannot read another track! But it is even worse if you want to read from the track currently in the buffer. You think the data is coming from disk, but it might be the never updated sector! What is the problem? Trackdisk does not check the protect status before letting a CMD_WRITE modify the trackbuffer. AUTO UPDATE FUNCTION There were times when I used Sectorama (I still use this nice program from the hand of David Joiner), I did not understand why sometimes a modified and written sector would not stick on disk. Now I know this is because Trackdisk needs some help. It must be told to flush its buffers, although this is automatic done if some data is requested from another track. Trackdisk also does not switch off its drive motor. If not be told to switch it off, the motor runs forever. Dos knows about Td's lack of updating and does some special commands: CMD_UPDATE and TD_MOTOR. Dos does this well within five seconds. But programs that directly access Td, may not be aware and leave the motor running and the buffers unflushed. There are a lot of timers in Trackdisk, so why does not Td do it by it self? I do not know, but if you have the function switched on, Td flushes a modified trackbuffer and switch the motor off after five seconds idling. NOCLICK FUNCTION The presence of a disk in a drive is reflected by a line called CHNG. This line is asserted if there is no disk in the drive. It stays that way until a disk in the drive and the head is stepped (and the drive is selected of course). I assume this is done this way to give the opportunity to acknowledge an disk extraction. If the line directly reflects the disk presence state, an extraction can be missed. Well, it is a way, I know some other, and I know too that the sound of an empty drive generally is experienced to be annoying. The step direction is each time reversed, so the head will stay about the same position. This reverse is done by a CPU instruction "bchg", bitchange. Therefore is was very simple to implement the noclick function, just change the instruction into "bset", bit set. Then the head steps to the outside of the disk and once arrived, it stops because it is blocked there. This can be by a pillow or by an electrical switch, the latter effectively preventing stepping. When Kickstart got in rom, this was not that easy anymore. TrackSalve executes Trackdisk in ram, and the patch is simple again. But should you have noclick on every drive? Some drives still make noise, this time not as regular as well in time as in sound. Even more disturbing! Apart from the fact that I believe that these drives are not suitable for this method. For disk absence detection it is not needed to step the head. Therefore disk absence check is done every .5 seconds and presence check every 2.5 seconds. Now that the heads do not actually step, the interval of the presence check can be reduced to .5 seconds. VERIFY FUNCTION A drawback of this whole track read/write system is that a simple verify is not possible. It is not enough to verify the just written sector, because ten more sectors are written to disk. These sectors have probably no connection with the writing program, and a more general warning must be made. It is the particular Trackdisk task that does a request and the user must reply on it. The AutoRequest() has been proven unreliable in low memory situations. It returns "Cancel" if the function could not be carried out, where it should return "Retry". The same is true for an Alert(). Therefore TrackSalve build its own requester. My mouse is often hard to find, and if found, I have to search for a surface for it (the screen would be nice but it's too steep). So I like keyboard shortcuts. This is well implemented in the system requester. If you build your own requester, suddenly all input is blocked, and I found no way (other than an special inputhandler, which is beyond I am willing to implement in a patch) to receive shortcuts. What is a requester other than a window with some gadgets? Then I can receive everything I like. But this time Dmouse does not recognize the requester as a requester. Sigh. It doesn't get any easier with Intuition. Do the verify, the track is read back into another buffer and then compared with the original. This is broken in two parts, because the data in the verify buffer probably begins with another sector. The comparison is done by the blitter, xor-ing both buffers. The motor is switched off before the requester is displayed. The writing program however is not notified and may not switch off a motor of a source. The standard diskcopy is a good example. If you use diskcopy without its verify function, but with TrackSalve verifying (which is faster), and a verify error happens, the destination drive will stop turning. Diskcopy does not know and does not switch off its source drive. This is a good reason to enable the auto update function in TrackSalve, which will stop the source's motor. BUGS? The preceding release of TrackSalve (1.0) had a bug in it, although it was extremely unlikely that the buggy code would be executed. This unlikeliness was the reason that the bug slipped through the debugging phase. It brought me to an improved debugging administration and every single branch is executed under debug control, how trivial a branch might look. Pieces of code that could behave unexpectable because of special combinations of parameters, have been run under simulators producing all possible combinations. This time I would like to qualify the debugging as "extreme". Again: This program is extremely debugged! CONCLUSION With this patch Trackdisk becomes more efficient in its CPU use, although slightly slower (well under 2%) in its writing, because of the MFM update. A lot features are added, which are fully transparent. Trackdisk has come closer to what I think a floppy disk device driver should be. Better requires a complete rewrite. (Sorry Commodore, but disk drivers are my favorite pastime, yours too?).