• Please review our updated Terms and Rules here

INT 13h get drive params problem!!!

Mike Chambers

Veteran Member
Joined
Sep 2, 2006
Messages
2,621
alright, so i'm trying to write a hard drive imager that works over FTP. i tried this before but i was having problems, and lost interest.

right now i'm having problems using the 08h call to interrupt 13h. fdisk clearly shows that the drive in my XT clone has 781 cylinders, but for some reason the code i wrote to get the params returns 557 cyls, 4 heads, and 48 SPT. (totalling 54,755,328 bytes which is way off, the drive's true capacity is half of that.)

here is my code for that part: (cal is the call registers, and of course ret is the return registers.

Code:
drv = &H80
PRINT "Resetting drive on primary master..."
cal.ax = 0
cal.dx = dev
CALL interruptx(&H13, cal, ret)

PRINT "Reading drive parameters of primary master..."
'get drive parameters
cal.ax = &H800
cal.dx = drv
CALL interruptx(&H13, cal, ret)
split$ = RIGHT$("0000" + HEX$(ret.dx), 4)
numhdd = VAL("&H" + RIGHT$(split$, 2))
heads = VAL("&H" + LEFT$(split$, 2))
decby = 16384
DO
  IF ret.cx - decby >= 0 THEN
    tb$ = "1" + tb$
    ret.cx = ret.cx - decby
  ELSE
    tb$ = "0" + tb$
  END IF
  decby = decby / 2
LOOP UNTIL decby < 1
cyls = 0
addby = 512
FOR n = 1 TO 10
  IF MID$(tb$, n, 1) = "1" THEN cyls = cyls + addby
  addby = addby / 2
NEXT n
spt = 0
addby = 32
FOR n = 11 TO 16
  IF MID$(tb$, n, 1) = "1" THEN spt = spt + addby
  addby = addby / 2
NEXT n
PRINT "Cylinders:" + STR$(cyls + 1)
PRINT "Heads:" + STR$(heads + 1)
PRINT "Sectors per track:" + STR$(spt)
t& = cyls + 1
t& = t& * (heads + 1)
t& = t& * (spt * 512)
PRINT "Disk capacity:" + STR$(t&) + " bytes          "
'end get parameters

i know i huge improvements could be made to my math-related code there, but as far as i can see this should still get the numbers properly based on what i've read about the call.

any ideas?

thanks!
 
it's been too long since I've looked at basic to be able to follow that.
can you duplicate this in debug and make sure the values in cx and dx are what you're getting back from basic?

c:>debug
-a
mov ah, 08
mov dl, 80
int 13

-p
-p
-p

then look at CX and DX

and that you're taking into account how goofy the cylinder stuff is done?
(upper 2 bits of cylinder are in CL 7:6 and the lower 8 bits are in CH) wtf?

and don't try it under a windows shell. you'll get really weird results in CX/DX
 
thanks for the response hargle. it seems like it's actually working now. i examined the length of the binary string that it generated from the 16-bit number, and noticed there were only 15 bits in it.

looking back at the code, decby = 16384 should have been debcy = 32768... and yes your'e right i had to move the two highest bits from CL to be the highest bits in the 10-bit cyl count value.

now it's reading properly i believe. the numbers matched what you told me to get from debug.

prog's output:

Cylinders: 781
Heads: 4
Sectors per track: 17
Disk capacity: 27,191,296 bytes



all that's left to do to get the data to read for imaging over the network. i was going to try making a full raw of the drive in my XT clone, boot it up in QEMU and run chkdsk and scandisk to see if it can find errors in the file system.

my goal here is make a complete "swiss army knife" that's easy to use for stone-age computers for backup/restore of hard drive and floppy disks. being able to image to an FTP server is an awesome and easy way to back your old machines up and restore them imo.

another idea i had in mind for it is allowing you to save to a custom image format that can save space by not actually writing sectors that are filled with zeros, but instead just use 1 byte as a marker before each sector telling the restore code whether to write the next 512 bytes in the file, or write 512 ASCII zeros thus saving 511 bytes for each. :p

thanks again hargle.
 
Last edited:
That code starting at the DO looks kind of screwy.

Try this:
Code:
   spt = ret.cx mod 64   ' Sectors/track
   cyls = int ( ret.cx/256)  ' Get  lower 8 bits of cylinder
   crem = int ((ret.cx mod 256)/64)  ' isolate bits 6 and 7
   cyls = cyls + (256 * crem);  ' add into cylinder count

Forgive my BASIC; I don't know which dialect you're using. I hope you'll get the idea.

Be aware however, that 13H/08H may not tell you the whole truth. You'll also want to try the extended BIOS calls 4100H/4800H before you do the 08H call just to see if there's more there than 08's reporting. If you want a little more certainty, also check the BIOS Disk parameter blocks at the addresses that interrupts 41H and 46H point to.
 
Last edited:
I wouldn't bother trying to compress the data in any way. An FTP client that can read the entire partition and send it unaltered to another machine is better. If that other machine is a Linux machine you can actually 'mount' the disk image file to the filesystem and then be able to poke around in it from within Linux. It also doesn't lock somebody into a specific restore program and it doesn't take that much more time overall. (Your chances on finding a sector of zeros on a well used hard drive is almost NIL.)

What is really important for performance is to minimize the disk I/O and to maximize the outgoing packet sizes. To minimize disk I/O you just need to do big block reads - something like 8KB or 16KB at a time. Then you have enough data to send out a few full sized packets. (Be sure the MTU size is as large as possible ... if you are on a local network MTU=1500 will give you a 1460 byte payload.)

This is an example where asynchronous I/O would be really nice. I'd love to be prefetching data from the drive while I'm sending packets out. DOS by itself can't do this.

Lastly, you have to provide some sort of verification that the data was copied bit for bit. A backup program is useless without that. I would keep a running checksum (or better yet, CRC) and send that after the transfer is done in a separate transfer. The machine on the other side needs to be able to read the partition image and verify that it comes up with the same CRC or checksum. It's the same concept as using MD5 to verify a large download.
 
I wouldn't bother trying to compress the data in any way. An FTP client that can read the entire partition and send it unaltered to another machine is better. If that other machine is a Linux machine you can actually 'mount' the disk image file to the filesystem and then be able to poke around in it from within Linux. It also doesn't lock somebody into a specific restore program and it doesn't take that much more time overall. (Your chances on finding a sector of zeros on a well used hard drive is almost NIL.)

What is really important for performance is to minimize the disk I/O and to maximize the outgoing packet sizes. To minimize disk I/O you just need to do big block reads - something like 8KB or 16KB at a time. Then you have enough data to send out a few full sized packets. (Be sure the MTU size is as large as possible ... if you are on a local network MTU=1500 will give you a 1460 byte payload.)

This is an example where asynchronous I/O would be really nice. I'd love to be prefetching data from the drive while I'm sending packets out. DOS by itself can't do this.

Lastly, you have to provide some sort of verification that the data was copied bit for bit. A backup program is useless without that. I would keep a running checksum (or better yet, CRC) and send that after the transfer is done in a separate transfer. The machine on the other side needs to be able to read the partition image and verify that it comes up with the same CRC or checksum. It's the same concept as using MD5 to verify a large download.

yep, i was thinking about the all-zero sectors situation too. that's a good point, probably wouldn't find more than 10 zero sectors on 99% of drives. there's always the possibility of writing true compression routines like ZIP-style or LHA or something, but on machines as old as my target platforms here the HD's are so small it doesn't really matter. that would take decades on an 8088 anyway. (even checking for 512 zeros would slow it down to a painful crawl)

what do you think a good method of CRC generation would be? since this is aimed at XT/AT machines, it needs to be something that is going to be reasonably thorough without giving the CPU too much work because then you run into the same speed situation as with compression. well okay not AS bad, but it still wouldn't be very fun. i'd like my 25 MB to back up before i develop alzheimers. (too late??)

i don't know if i really need a CRC though, because since transfers are going to be done via TCP only it has it's own CRC system in place.

as far as disk I/O my plan was to grab 8 sectors at a time or so. what do you think i should in the situation of unreadable sectors? in addition to warning the user, do you think the best "filler" for the space would just be 512 zeros?
 
Agreed - compression would be too slow on these machines. Even simple run length encoding would slow it down quite a bit.

I like the idea of a CRC better than a checksum because a checksum is not robust enough. Especially when we are talking about megabytes of data. Keep in mind that the idea of the CRC or checksum isn't to ensure that the TCP/IP code is doing it's job - it is to keep you, the programmer honest. If you have a utility that can compute a CRC on the partition and that CRC matches another utility that runs a CRC on the saved image, then you know that you got everything without error. This can protect you against your bugs and bugs in the TCP stack. And it also gives the end user some assurance that their data is safe, which is the important part.

Eight sectors is probably not enough - better than 1, but still fairly small. I would read 16 or 32K worth of sectors at a time.

Extra credit - If you can determine that you are on an old system where CHS values are valid (no LBA) then you can optimize things by reading a track at at time. That will minimize head movement.
 
good ideas mike, thanks for the input. a QB string is limited to 32 KB, but i think i'll just read 16 KB of sectors at a time just to be careful with memory. just wondering, would you use this software yourself? can't be too safe with old hardware like this. you may just turn on your XT that worked perfectly last night again in the morning and find your drive that you saved your latest code on and forgot to copy to a floppy is shot. :p

i think it would be a nice tool.
 
as far as disk I/O my plan was to grab 8 sectors at a time or so. what do you think i should in the situation of unreadable sectors? in addition to warning the user, do you think the best "filler" for the space would just be 512 zeros?

FIrst, go back and re-read the segment (8 sectors, if that's what you're doing), one sector at a time--a lot of BIOSes differ as to how and where they indicate errors. When you find the sector, take a look at the error code coming back.

If it's "sector not found", there's not much you can do other than note it. Just fill the buffer with some value, preferably non-zero (makes it easier to find the sector in a dump file). F4 (x86 Halt instruction) would be a good choice.

If it's an ECC/CRC error, do a "read long" and use that data, noting the error. Quite often, the problem bits will be toward the end of a sector. Half a loaf is better than none.

That's what worked for us.
 
I would expand on that and try to reread the failing sector a few times. Also, make sure you put a message out so the user knows that their drive has some new blemishes.


Mike
 
I would expand on that and try to reread the failing sector a few times. Also, make sure you put a message out so the user knows that their drive has some new blemishes.


Mike

yep, i've already added a 10-count retry loop on a bad sec. i actually abandoned the previous code i'd written and have started from scratch again now that i've got the functions all down in my head. (printed the old code for reference too) i'm working on a minimal, but good looking text UI as well. menu driven.
 
FIrst, go back and re-read the segment (8 sectors, if that's what you're doing), one sector at a time--a lot of BIOSes differ as to how and where they indicate errors. When you find the sector, take a look at the error code coming back.

If it's "sector not found", there's not much you can do other than note it. Just fill the buffer with some value, preferably non-zero (makes it easier to find the sector in a dump file). F4 (x86 Halt instruction) would be a good choice.

If it's an ECC/CRC error, do a "read long" and use that data, noting the error. Quite often, the problem bits will be toward the end of a sector. Half a loaf is better than none.

That's what worked for us.

thanks chuck.. this is why post here, i can learn from the pros. :)

i'm more or less new to dealing directly with 13h.
 
I would expand on that and try to reread the failing sector a few times. Also, make sure you put a message out so the user knows that their drive has some new blemishes.

You could, but most controllers do auto retries, so additional retries are of marginal use. One might allow the user to specify a retry count. Keeping a log as well as putting messages out is probably a good thing.

Disk managers are another thing to be aware of (e.g. SpeedStor, Disk Manager, etc.) The user might well take a drive and temporarily install it as a second drive in a system and the drive overlay won't be loaded.
 
good ideas mike, thanks for the input. a QB string is limited to 32 KB, but i think i'll just read 16 KB of sectors at a time just to be careful with memory. just wondering, would you use this software yourself? can't be too safe with old hardware like this. you may just turn on your XT that worked perfectly last night again in the morning and find your drive that you saved your latest code on and forgot to copy to a floppy is shot. :p

i think it would be a nice tool.

16K is fine then. As large as you can get it is the key. I did a lot of experimentation with my netcat and FTP clients, and the minimum should be 8. 16K is slightly better. After that you start running up against the law of diminishing returns.

I might use a tool like this. I normally don't have anything on an XT class hard drive that I already don't have somewhere else. If I do a backup, I usually use pkzip to a network drive. Pkzip gives me nearly everything that I need - it can pick up hidden and system files. The only thing it doesn't do is preserve the layout of the disk - for that you need an image.

I'm really concerned about verifying the copied contents of the drive - a backup that you have doubts about it worthless. Hence the comments about doing some sort of CRC or checksum on both sides of the transfer.

Time is not as big of an issue as we think. I just ran the numbers and at 25KB/sec, I can read the entire contents of my XT 10MB hard drive in 7 minutes. Slow machines with bigger drives are where the speed of the code will make a difference.

And you know me ... if I do use a tool like this, I'm probably writing my own. ;-) I've got a disk imager already (dskimage) and a stable FTP client already. I've done all of the code to read tracks, retry in case of errors, etc. I don't think I'd add this to the general purpose FTP client because I want to keep the size of that executable small, but a specialized FTP client used for disk imaging makes a lot of sense.

Try mounting the image on a Linux box sometime - that's a good test to ensure you got it all. It's also non-destructive - much safer than saving, restoring, and hoping that you did everything right. :)
 
Disk managers are another thing to be aware of (e.g. SpeedStor, Disk Manager, etc.) The user might well take a drive and temporarily install it as a second drive in a system and the drive overlay won't be loaded.

What's the issue here? For saving the image drive overlays shouldn't be a problem. I figure that somebody would use the later DOS (5.0+) calls where you read a sector by number, and the layout of the drive isn't your problem. You'll get the entire partition regardless of geometry.

Restoring is a different problem - you'd have to have the drive overlay software to reinstall it before attempting to restore the partition image.
 
16K is fine then. As large as you can get it is the key. I did a lot of experimentation with my netcat and FTP clients, and the minimum should be 8. 16K is slightly better. After that you start running up against the law of diminishing returns.

I might use a tool like this. I normally don't have anything on an XT class hard drive that I already don't have somewhere else. If I do a backup, I usually use pkzip to a network drive. Pkzip gives me nearly everything that I need - it can pick up hidden and system files. The only thing it doesn't do is preserve the layout of the disk - for that you need an image.

I'm really concerned about verifying the copied contents of the drive - a backup that you have doubts about it worthless. Hence the comments about doing some sort of CRC or checksum on both sides of the transfer.

Time is not as big of an issue as we think. I just ran the numbers and at 25KB/sec, I can read the entire contents of my XT 10MB hard drive in 7 minutes. Slow machines with bigger drives are where the speed of the code will make a difference.

And you know me ... if I do use a tool like this, I'm probably writing my own. ;-) I've got a disk imager already (dskimage) and a stable FTP client already. I've done all of the code to read tracks, retry in case of errors, etc. I don't think I'd add this to the general purpose FTP client because I want to keep the size of that executable small, but a specialized FTP client used for disk imaging makes a lot of sense.

Try mounting the image on a Linux box sometime - that's a good test to ensure you got it all. It's also non-destructive - much safer than saving, restoring, and hoping that you did everything right. :)

yeah, i was planning to test a few backups when i'm ready by mounting them as drives in QEMU and run chkdsk/scandisk from a DOS floppy image.
 
What's the issue here? For saving the image drive overlays shouldn't be a problem. I figure that somebody would use the later DOS (5.0+) calls where you read a sector by number, and the layout of the drive isn't your problem. You'll get the entire partition regardless of geometry.

Restoring is a different problem - you'd have to have the drive overlay software to reinstall it before attempting to restore the partition image.

Consider the situation where you've removed a drive with a drive overlay and installed it in a different system as a second drive. This second system isn't aware that you've got a drive overlay, so Int 13H calls just sucks the thing up, overlay and all. If you do restore the data to a different drive, you may likely find that the overlay is drive manufacturer-specific.

It's worth checking and noting that a DO is present, that's all.
 
And that's probably why somebody should use DOS INT 25 instead, and just read by sector number. A drive image read using INT 25 should be readable anywhere because it leaves it to DOS to do the CHS gorp, not the programmer.

I just didn't spell out INT 25 in my last post. As it turns out, the API has been available since DOS 3.31.


Mike
 
And that's probably why somebody should use DOS INT 25 instead, and just read by sector number. A drive image read using INT 25 should be readable anywhere because it leaves it to DOS to do the CHS gorp, not the programmer.

I just didn't spell out INT 25 in my last post. As it turns out, the API has been available since DOS 3.31.


Mike

hmm... do you think it might be a good idea for me to use that interface instead? if any DOS 3.31+ i'm sure just about anybody's old machine can handle that. if an older DOS is installed, a newer DOS boot disk could be used.

what do you think?
 
And that's probably why somebody should use DOS INT 25 instead, and just read by sector number. A drive image read using INT 25 should be readable anywhere because it leaves it to DOS to do the CHS gorp, not the programmer.

I just didn't spell out INT 25 in my last post. As it turns out, the API has been available since DOS 3.31.

It's older than that--try DOS 1.0. The only real gotcha is that it works on DOS filesystems only.
 
Back
Top