Subject: Re: Large Drives and old BIOS's
To: Mike Pelley <mike@pelley.com>
From: Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
List: tech-kern
Date: 04/12/2001 16:29:23
> I have a 60 gig maxtor drive that I would like to move to an older P2 
> machine.  Unfortunately, that machine will not boot with the drive 
> plugged in unless I set the cylinder limitation jumper (or disable the 
> IDE controller in the BIOS).
> 
> Normally, users would then install maxblast which does a 
> READ_NATIVE_MAX_ADDRESS (or something similar) to get the size of the 
> drive, and then a SET_MAX_ADDRESS to correct the size visable to the os.
> Since this occurs after the BIOS has probed the drive, everybody is happy.

I wandered down this road recently for a very different reason
(backing up a tivo's disk).  I only needed to do this once, which is
why I haven't cleaned up my solution..

> Specifically, if someone could give me some hints about where
> functions available in linux's linux/hdreg.h might be in netbsd that
> would save me some effort.

You can (almost) do the READ_NATIVE_MAX_ADDRESS and SET_MAX_ADDRESS
from userland using the ATAIOCCOMMAND ioctl on the raw disk.  (The
main problem is that you can't currently set the "LBA" bit in the
request, so you wind up getting the CHS geometry, which is pretty much
meaningless).  
So, I hacked the kernel to let the user set the 0x40 bit of the "head"
register (which is where the "LBA" bit resides):

Index: wd.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ata/wd.c,v
retrieving revision 1.212
diff -u -u -r1.212 wd.c
--- wd.c        2001/01/08 02:03:45     1.212
+++ wd.c        2001/04/12 20:25:41
@@ -1525,7 +1525,7 @@
 
        wdc_c.timeout = wi->wi_atareq.timeout;
        wdc_c.r_command = wi->wi_atareq.command;
-       wdc_c.r_head = wi->wi_atareq.head & 0x0f;
+       wdc_c.r_head = wi->wi_atareq.head & 0x04f;
        wdc_c.r_cyl = wi->wi_atareq.cylinder;
        wdc_c.r_sector = wi->wi_atareq.sec_num;
        wdc_c.r_count = wi->wi_atareq.sec_count;

.. and then ran the following:

#include <stdio.h>
#include <fcntl.h>
#include <sys/ataio.h>

main(int argc, char **argv)
{
  int fd, r;
  atareq_t atr, natr;

  atr.flags = ATACMD_READREG;
  atr.command = 0xf8;
  atr.features = 0;
  atr.sec_count = 0;
  atr.sec_num = 0;
  atr.head = 0x40;
  atr.cylinder = 0;
  atr.databuf = 0;
  atr.datalen = 0;
  atr.timeout = 1000;
  atr.retsts = 0;
  atr.error = 0;

  fd = open(argv[1], O_RDWR, 0);
  if (fd < 0) {
    perror(argv[1]);
    exit(1);
  }
  sleep(5);
  r = ioctl(fd, ATAIOCCOMMAND, &atr);
  if (r < 0) {
    perror("ATAIOCCOMMAND");
    exit(1);
  }
  printf("%x %x %x %x %x %x\n",
         atr.error,
         atr.sec_count,
         atr.sec_num,
         atr.cylinder,
         atr.head,
         atr.retsts);
  natr.flags = ATACMD_READREG;
  natr.command = 0xf9;
  natr.features = 0;
  natr.sec_count = 0;
  natr.sec_num = atr.sec_num;
  natr.head = 0x40 | (atr.head & 0xf);
  natr.cylinder = atr.cylinder;
  natr.databuf = 0;
  natr.datalen = 0;
  natr.timeout = 1000;
  natr.retsts = 0;
  natr.error = 0;

  r = ioctl(fd, ATAIOCCOMMAND, &natr);
  if (r < 0) {
    perror("ATAIOCCOMMAND");
    exit(1);
  }
  printf("%x %x %x %x %x %x\n",
         natr.error,
         natr.sec_count,
         natr.sec_num,
         natr.cylinder,
         natr.head,
         natr.retsts);

}

---

Of course, you then have to force the kernel to re-probe the disk; in
my case, I just rebooted the machine w/o a power cycle and it found
the new size on reboot (which solved my problem but won't really solve
yours).

					- Bill