[comp.os.minix] Suggestion for PC wini te

peter_van_epp@cc.sfu.ca@canremote.uucp (Peter_Van_Epp@cc.sfu.ca) (12/21/89)

Subj: Suggestion for PC wini test program under DOS (long)

Given the amount of troubles I and other people are having with
xt_/at_wini.c it seems to me that we should write a test program that
runs under DOS (sorry Andy!) that does the following: 
Asks DOS what the drive under consideration looks like (int 13) by
reading the   controller bios rom. Now the wini.c code would be
executed (again under DOS although we may have to reset the
controller before trying to talk to it again  from DOS) except
arrange to dump out the values that the MINIX code gets.  Assuming
that matches then try reading either some or all of the sectors of
the DOS partition (note being sure to only read!) with both the DOS
and the  minix code and insure that they are the same. Assuming that
doesn't work it would be nice (and shouldn't be too hard!) to allow a
command line switch to enable the various compile time switches so
that the various options (xt/at WD or ADAPTEC controllers etc) can be
tried without recompiling the DOS program. This should allow us to
create an option file that could be used to control the recompilation
of the wini driver (and give us better confidence that the driver is
actually working correctly!) before having Minix up. I will put this
project on the end of my (long!) list of things to do, unless someone
else is interested in making one (hint! hint!).
Peter_Van_Epp@cc.sfu.ca
---
 * Via MaSNet/HST96/HST144/V32 - UN Minix
 * Via Usenet Newsgroup comp.os.minix

hall@cod.NOSC.MIL (Robert R. Hall) (01/03/90)

In article <89122504055886@masnet.uucp>, peter_van_epp@cc.sfu.ca@canremote.uucp (Peter_Van_Epp@cc.sfu.ca) writes:
> Subj: Suggestion for PC wini test program under DOS (long)
> 
> Given the amount of troubles I and other people are having with
> xt_/at_wini.c it seems to me that we should write a test program that
> runs under DOS (sorry Andy!) that does the following: 
> Asks DOS what the drive under consideration looks like (int 13) by
> reading the   controller bios rom. Now the wini.c code would be
   
   . . .

> project on the end of my (long!) list of things to do, unless someone
> else is interested in making one (hint! hint!).
> Peter_Van_Epp@cc.sfu.ca


Here is a couple of MS-DOS programs I used to  get Minix working with
my hard drive.  It doesn't have most of the feature Peter_Van_Epp
suggested but is may be a starting place for someone.

Robert R. Hall
hall@nosc.mil

echo x - rd_parms.c
sed '/^X/s///' > rd_parms.c << '/'
X/* rd_params.c
X   read hard dirve parameters */
X
Xstruct param {
X   int nr_cyl;		/* Number of cylinders */
X   int nr_heads;	/* Number of heads */
X   int nr_sectors;	/* Number of sectors per track */
X   int nr_drives;	/* Number of drives */
X   int dr_type;		/* drive type */
X} param0, param1;
X
Xint Ax, Bx, Cx, Dx;
X
X#include <dos.h>
X#define BIOS_ASK	0x08
X#define DRIVE		0x80
X
Xbios13()
X{
X  union REGS in_regs, out_regs;
X
X  in_regs.x.ax = Ax;
X  in_regs.x.bx = Bx;
X  in_regs.x.cx = Cx;
X  in_regs.x.dx = Dx;
X  int86(0x13, &in_regs, &out_regs);
X  Ax = out_regs.x.ax;
X  Bx = out_regs.x.bx;
X  Cx = out_regs.x.cx;
X  Dx = out_regs.x.dx;
X  return;
X}
X
Xget_params(dr, params)
Xint dr;
Xstruct param *params;
X{
X   Dx = dr + DRIVE;
X   Ax = (BIOS_ASK << 8);
X   bios13();
X   params->nr_heads = ((Dx >> 8) & 0xff) + 1;
X   params->nr_sectors = (Cx & 0x3F);
X   params->nr_cyl = ((Cx & 0xC0) << 2) + ((Cx >> 8) & 0xFF);
X   params->nr_drives = (Dx & 0xFF);
X   params->dr_type = (Bx & 0x07);
X}
X
Xmain()
X{
X  get_params(1, &param0);
X  printf("nr_heads   is: %d\n", param0.nr_heads);
X  printf("nr_sectors is: %d\n", param0.nr_sectors);
X  printf("nr_cyl     is: %d\n", param0.nr_cyl);
X  printf("nr_drives  is: %d\n", param0.nr_drives);
X  printf("dr_type    is: %d\n", param0.dr_type);
X
X  printf("Ax is: %.4x  Bx is: %.4x  Cx is: %.4x  Dx is: %.4x\n",
X    Ax, Bx, Cx, Dx);
X}
/
echo x - rd_part.c
sed '/^X/s///' > rd_part.c << '/'
X/* This file contains a hard disk driver that uses the ROM BIOS.  It makes
X * a call and just waits for the transfer to happen.  It is not interrupt
X * driven and thus will have poor performance.  The advantage is that it should
X * work on virtually any PC, XT, 386, PS/2 or clone.  The generic boot
X * diskette uses this driver.  It is suggested that all MINIX users try the
X * other drivers, and use this one only as a last resort, if all else fails.
X *
X * The driver supports two operations: read a block and
X * write a block.  It accepts two messages, one for reading and one for
X * writing, both using message format m2 and with the same parameters:
X *
X *	m_type	  DEVICE   PROC_NR	COUNT	 POSITION  ADRRESS
X * ----------------------------------------------------------------
X * |  DISK_READ | device  | proc nr |  bytes  |	 offset | buf ptr |
X * |------------+---------+---------+---------+---------+---------|
X * | DISK_WRITE | device  | proc nr |  bytes  |	 offset | buf ptr |
X * ----------------------------------------------------------------
X *
X * The file contains one entry point:
X *
X *	 winchester_task:	main entry when system is brought up
X *
X */
X
X#include <dos.h>
X
X#include "minix/const.h"
X#include "minix/type.h"
X#include "minix/callnr.h"
X#include "minix/com.h"
X#include "minix/error.h"
X#include "const.h"
X#include "type.h"
X#include "glo.h"
X#include "proc.h"
X
X/* Error codes */
X#define ERR		  -1	/* general error */
X
X/* Parameters for the disk drive. */
X#define MAX_DRIVES         2	/* this driver supports 2 drives (hd0 - hd9)*/
X#define DEV_PER_DRIVE	   5	/* hd0 + hd1 + hd2 + hd3 + hd4 = 5 */
X#define NR_DEVICES      (MAX_DRIVES * DEV_PER_DRIVE)
X#define SECTOR_SIZE	 512	/* physical sector size in bytes */
X#define BASE            1536	/* base address of kernel */
X
X/* BIOS parameters */
X#define BIOS_ASK        0x08	/* opcode for asking BIOS for parameters */
X#define BIOS_RESET      0x00	/* opcode for resetting disk BIOS */
X#define BIOS_READ       0x02	/* opcode for BIOS read */
X#define BIOS_WRITE      0x03	/* opcode for BIOS write */
X#define DRIVE           0x80	/* BIOS code for drive 0 */
X#define PART_TABLE     0x1C6	/* IBM partition table starts here in sect 0 */
X
XPRIVATE unsigned char buf[BLOCK_SIZE]; /* Buffer used by the startup routine */
XPRIVATE message w_mess;		/* message buffer for in and out */
X
XPRIVATE struct wini {		/* main drive struct, one entry per drive */
X  int wn_opcode;		/* DISK_READ or DISK_WRITE */
X  int wn_procnr;		/* which proc wanted this operation? */
X  int wn_cylinder;		/* cylinder number addressed */
X  int wn_sector;		/* sector addressed */
X  int wn_head;			/* head number addressed */
X  int wn_heads;			/* maximum number of heads */
X  int wn_maxsec;		/* maximum number of sectors per track */
X  long wn_low;			/* lowest cylinder of partition */
X  long wn_size;			/* size of partition in sectors */
X  int wn_count;			/* byte count */
X  int wn_drive;			/* 0x80 or 0x81 */
X  vir_bytes wn_address;		/* user virtual address */
X} wini[NR_DEVICES];
X
XPRIVATE struct param {
X	int nr_cyl;		/* Number of cylinders */
X	int nr_heads;		/* Number of heads */
X	int nr_drives;		/* Number of drives on this controler */
X	int nr_sectors;		/* Number of sectors per track */
X} param0, param1;
X
Xint nr_drives;
X
Xint Ax, Bx, Cx, Dx, Es;
X
X
Xbios13()
X{
X  union REGS in_regs, out_regs;
X  struct SREGS seg_regs;
X
X  in_regs.x.ax = Ax;
X  in_regs.x.bx = Bx;
X  in_regs.x.cx = Cx;
X  in_regs.x.dx = Dx;
X  seg_regs.es = Es;
X  int86x(0x13, &in_regs, &out_regs, &seg_regs);
X  Ax = out_regs.x.ax;
X  Bx = out_regs.x.bx;
X  Cx = out_regs.x.cx;
X  Dx = out_regs.x.dx;
X  return;
X}
X
X/*==========================================================================*
X *				w_do_rdwt				    * 
X *==========================================================================*/
XPRIVATE int w_do_rdwt(m_ptr)
Xmessage *m_ptr;			/* pointer to read or write w_message */
X{
X/* Carry out a read or write request from the disk. */
X  register struct wini *wn;
X  vir_bytes vir, ct;
X  unsigned locyl, hicyl, c1, c2, c3;
X  int r, device, errors = 0;
X  long sector;
X  phys_bytes user_phys;
X  extern phys_bytes umap();
X  char far *pointer;
X  unsigned int segment;
X
X  /* Decode the w_message parameters. */
X  printf("Entered W_do_rdwt\n");
X  device = m_ptr->DEVICE;	/* minor device #.  1-4 are partitions */
X  if (device < 0 || device >= NR_DEVICES) return(EIO);
X  if (m_ptr->COUNT != BLOCK_SIZE) return(EINVAL);
X  printf("Passed BLOCK_SIZE test\n");
X  wn = &wini[device];		/* 'wn' points to entry for this drive */
X
X  /* Set opcode to BIOS_READ or BIOS_WRITE. Check for bad starting addr. */
X  wn->wn_opcode = (m_ptr->m_type == DISK_WRITE ? BIOS_WRITE : BIOS_READ);
X  if (m_ptr->POSITION % BLOCK_SIZE != 0) return(EINVAL);
X
X  /* Calculate the physical parameters */
X  sector = m_ptr->POSITION/SECTOR_SIZE;	/* relative sector within partition */
X  printf("sector is %ld  wn_size is: %ld\n", sector, wn->wn_size);
X  if ((sector+BLOCK_SIZE/SECTOR_SIZE) > wn->wn_size) return(EOF);
X  printf("Passed sector test\n");
X  sector += wn->wn_low;		/* absolute sector number */
X  wn->wn_cylinder = sector / (wn->wn_heads * wn->wn_maxsec);
X  wn->wn_sector =  (sector % wn->wn_maxsec);
X  wn->wn_head = (sector % (wn->wn_heads * wn->wn_maxsec) )/wn->wn_maxsec;
X  wn->wn_count = m_ptr->COUNT;
X  wn->wn_address = (vir_bytes) m_ptr->ADDRESS;
X  wn->wn_procnr = m_ptr->PROC_NR;
X
X  /* Do the transfer */
X  vir = (vir_bytes) wn->wn_address;
X  ct = (vir_bytes) wn->wn_count;
X  pointer = buf;
X  segment = FP_SEG(pointer);
X  user_phys = ((unsigned long)segment << 4) + vir;
X  printf("pointer is 0x%.8lx\n", pointer);
X  printf("segment is 0x%.4x\n", segment);
X  printf("offset  is 0x%.4x\n", vir);
X  Ax = (wn->wn_opcode << 8) | 2;		/* read or write 2 sectors */
X  Bx = (unsigned) (user_phys & 0xF);	/* bx = low order 4 bits */
X  Es = (unsigned) ((user_phys >> 4) & 0xFFFF);
X  hicyl = (wn->wn_cylinder >> 8) & 03;	/* two high-order bits */
X  locyl = (wn->wn_cylinder & 0xFF);	/* 8 low-order bits */
X  c1 = (locyl<<8);
X  c2 = (hicyl<<6);
X  c3 = ((unsigned) wn->wn_sector) + 1;
X  Cx = c1 | c2 | c3;
X  Dx = (wn->wn_head<<8) | wn->wn_drive;
X  printf("Starting call to BIOS\n");
X  printf("Ax is: 0x%.4x\n", Ax);
X  printf("Bx is: 0x%.4x\n", Bx);
X  printf("Cx is: 0x%.4x\n", Cx);
X  printf("Dx is: 0x%.4x\n", Dx);
X  printf("Es is: 0x%.4x\n", Es);
X  bios13();
X  r = (Ax >> 8) & 0xFF;
X  printf("bios13 status is: 0x%.2x\n", r);
X  return(r == 0 ? BLOCK_SIZE : EIO);
X}
X
X
X/*============================================================================*
X *				get_params				      *
X *============================================================================*/
Xget_params(dr, params)
Xint dr;
Xstruct param *params;
X{
X   Dx = dr + DRIVE;
X   Ax = (BIOS_ASK << 8);
X   bios13();
X   params->nr_heads = ((Dx >> 8) & 0xFF) + 1;
X   params->nr_sectors = (Cx & 0x3F);
X   params->nr_cyl = ((Cx & 0xC0) << 2) + ((Cx >> 8) & 0xFF);
X   params->nr_drives = (Dx & 0xFF);
X}
X
X/*============================================================================*
X *				init_params				      *
X *============================================================================*/
Xmain()
X{
X  unsigned int i, j;
X
X  get_params(0, &param0);
X  get_params(1, &param0);
X
X  /* Get the number of drives */
X  nr_drives = param0.nr_drives;
X
X  /* Set the parameters in the drive structure */
X  for (i = 0; i < DEV_PER_DRIVE; i++)
X  {
X	wini[i].wn_heads = param0.nr_heads;
X	wini[i].wn_maxsec = param0.nr_sectors;
X	wini[i].wn_drive = DRIVE;
X  }
X  wini[0].wn_low = wini[DEV_PER_DRIVE].wn_low = 0L;
X  wini[0].wn_size = (long)((long)param0.nr_cyl
X      * (long)param0.nr_heads * (long)param0.nr_sectors);
X  for (i = DEV_PER_DRIVE; i < (2*DEV_PER_DRIVE); i++)
X  {
X	wini[i].wn_heads = param1.nr_heads;
X	wini[i].wn_maxsec = param1.nr_sectors;
X	wini[i].wn_drive = DRIVE + 1;
X  }
X  wini[DEV_PER_DRIVE].wn_size = (long)((long)param1.nr_cyl
X       * (long)param1.nr_heads * (long)param1.nr_sectors);
X
X  printf("Starting read of partition table\n");
X  /* Read the partition table for each drive and save them */
X  for (i = 0; i < 1; i++) {
X	w_mess.DEVICE = i * 5;
X	w_mess.POSITION = 0L;
X	w_mess.COUNT = BLOCK_SIZE;
X	w_mess.ADDRESS = (char *) buf;
X	w_mess.PROC_NR = WINCHESTER;
X	w_mess.m_type = DISK_READ;
X	if (w_do_rdwt(&w_mess) != BLOCK_SIZE)
X		printf("Can't read partition table of winchester %d\n", i);
X	printf("Read partition table %d completed\n", i);
X
X
X   for(i = 0; i < 5 * 8; i += 8)
X      {
X      for(j = 0; j < 8; j++)
X	printf("  %.2x", buf[i + j] & 0xFF);
X      printf("\n");
X      }
X  i = XT_WINI_VECTOR;
X  printf("XT_WINI_VECTOR is: %d  0x%.2x\n", i, i);
X  i = PRINTER_VECTOR;
X  printf("PRINTER_VECTOR is: %d  0x%.2x\n", i, i);
X  }
X}
X
/