[Kos-dev] ATA & LBA, more informations

Hervé Poussineau kos-dev@enix.org
Wed, 13 Feb 2002 22:17:44 +0100


C'est un message de format MIME en plusieurs parties.

------=_NextPart_000_0045_01C1B4DC.429684D0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 8bit

Salut !

J'ai bien essayé ton code, et c'est vrai, il marche pas avec mon disque.
Mais pour avoir fait ça, j'ai intégré ton code dans le mien, et tu as le
résultat dans le fichier joint : lecture de la table des partitions avec
deux méthodes. J'ai pas le courage de comparer les procédures hd_read et
hd_read_thomas, mais tu devrais trouver ton bonheur là-dedans...

@+, pour les résultats de ton enquète...

Hervé




------=_NextPart_000_0045_01C1B4DC.429684D0
Content-Type: application/octet-stream;
	name="LISTPART.C"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="LISTPART.C"

#include <conio.h>
#include <dos.h>		/* juste pour delay */
#include <stdio.h>

#define REG_BASE0       0x1F0   /* base register of controller 0 */
#define REG_BASE1       0x170   /* base register of controller 1 */
#define REG_DATA            0   /* data register (offset from the base =
reg.) */
#define REG_PRECOMP         1   /* start of write precompensation */
#define REG_COUNT           2   /* sectors to transfer */
#define REG_SECTOR          3   /* sector number */
#define REG_CYL_LO          4   /* low byte of cylinder number */
#define REG_CYL_HI          5   /* high byte of cylinder number */
#define REG_LDH             6   /* lba, drive and head */
#define   LDH_DEFAULT           0xA0    /* ECC enable, 512 bytes per =
sector */
#define   LDH_LBA               0x40    /* Use LBA addressing */
#define   ldh_init(drive)       (LDH_DEFAULT | ((drive) << 4))

/* Read only registers */
#define REG_STATUS          7   /* status */
#define   STATUS_BSY            0x80    /* controller busy */
#define   STATUS_RDY            0x40    /* drive ready */
#define   STATUS_WF             0x20    /* write fault */
#define   STATUS_SC             0x10    /* seek complete (obsolete) */
#define   STATUS_DRQ            0x08    /* data transfer request */
#define   STATUS_CRD            0x04    /* corrected data */
#define   STATUS_IDX            0x02    /* index pulse */
#define   STATUS_ERR            0x01    /* error */
#define REG_ERROR           1   /* error code */
#define   ERROR_BB              0x80    /* bad block */
#define   ERROR_ECC             0x40    /* bad ecc bytes */
#define   ERROR_ID              0x10    /* id not found */
#define   ERROR_AC              0x04    /* aborted command */
#define   ERROR_TK              0x02    /* track zero error */
#define   ERROR_DM              0x01    /* no data address mark */

/* Write only registers */
#define REG_COMMAND         7   /* command */
#define   CMD_IDLE              0x00    /* for w_command: drive idle */
#define   CMD_RECALIBRATE       0x10    /* recalibrate drive */
#define   CMD_READ              0x20    /* read data */
#define   CMD_WRITE             0x30    /* write data */
#define   CMD_READVERIFY        0x40    /* read verify */
#define   CMD_FORMAT            0x50    /* format track */
#define   CMD_SEEK              0x70    /* seek cylinder */
#define   CMD_DIAG              0x90    /* execute device diagnostics */
#define   CMD_SPECIFY           0x91    /* specify parameters */
#define   ATA_IDENTIFY          0xEC    /* identify drive */
#define REG_CTL         0x206   /* control register */
#define   CTL_NORETRY           0x80    /* disable access retry */
#define   CTL_NOECC             0x40    /* disable ecc retry */
#define   CTL_EIGHTHEADS        0x08    /* more than eight heads */
#define   CTL_RESET             0x04    /* reset controller */
#define   CTL_INTDISABLE        0x02    /* disable interrupts */

#define SECTOR_SIZE  512

typedef unsigned char  byte;
typedef unsigned short word;
typedef unsigned long  dword;

void hd_sethd(word reg_base, byte hd);
void partition(dword offset, int methode);
void fat_info(dword sector, int methode);

word hd_reg_base =3D 0;
byte hd_hd =3D 0;
void hd_sethd(word reg_base, byte hd)
{
	hd_reg_base =3D reg_base;
	hd_hd =3D hd;
}

int hd_wait(dword block)
{
	long ticks =3D 5000L;
	byte status;
	while (ticks-- > 0) {
		status =3D inp(hd_reg_base + REG_STATUS);
		if ((status & STATUS_BSY) =3D=3D 0) break;
		delay(1);
	}
	if (ticks =3D=3D -1) {
		printf("%s line %d : timeout in reading at LBA =3D %lu\n", __FILE__, =
__LINE__, block);
		return 1;
	}
	return 0;
}

int hd_input_thomas(void *buffer2, word len, dword sector_num, byte cmd)
{
	int sect   =3D (sector_num & 0xff);
	int cyl_lo =3D (sector_num >> 8) & 0xff;
	int cyl_hi =3D (sector_num >> 16) & 0xff;
	int head   =3D ((sector_num >> 24) & 0xf) | 0x40 /* LBA */;
	int device =3D hd_hd;
	int timeout;
	int i;
	byte status;
	word *buffer =3D (word *)buffer2;
	int ioaddr =3D hd_reg_base;
#define ATA_STATUS  REG_STATUS
#define ATA_S_BSY   STATUS_BSY
#define ATA_A_nIEN  CTL_INTDISABLE
#define ATA_A_4BIT  LDH_DEFAULT
#define ATA_DRIVE   REG_LDH
#define ATA_ALTPORT REG_CTL
#define ATA_SECTOR_COUNT REG_COUNT
#define ATA_ERROR   REG_ERROR
#define ATA_CYL_MSB REG_CYL_HI
#define ATA_CYL_LSB REG_CYL_LO
#define ATA_SECTOR_NUMBER REG_SECTOR
#define ATA_CMD     REG_COMMAND
#define ATA_C_READ  CMD_READ
#define ATA_S_DRQ   STATUS_DRQ
#define MASTER      0
#define ATA_MASTER  (0 << 4)
#define ATA_SLAVE   (1 << 4)
#define inb(a)      inp(a)
#define inw(a)      inpw(a)
#define outb(a,b)   outp(b,a)
#define usleep(a)   delay(a)
#define printk      printf
#define ATA_D_IBM   LDH_LBA | LDH_DEFAULT


  for(timeout =3D 0; timeout < 30000; timeout++)
	 {
		status =3D inb(ioaddr + ATA_STATUS);
		if(!(status & ATA_S_BSY))
		  break;
     =20
      usleep(1);
    }
  if(timeout =3D=3D 30000)
	 printk("TIMEOUT");

  outb(ATA_A_nIEN | ATA_A_4BIT, ioaddr + ATA_ALTPORT);
  /* select drive */
  outb(ATA_D_IBM
		 | (device =3D=3D MASTER) ? ATA_MASTER : ATA_SLAVE
       | head,=20
       ioaddr + ATA_DRIVE);

  //  outb(0, ctrl->ioaddr + ATA_PRECOMP);
  outb(1, ioaddr + ATA_SECTOR_COUNT);
  outb(sect, ioaddr + ATA_SECTOR_NUMBER);
  outb(cyl_lo, ioaddr + ATA_CYL_LSB);
  outb(cyl_hi, ioaddr + ATA_CYL_MSB);

  /* FOR THE MOMENT WE DON'T CARE ABOUT THE OPERATION TYPE ... ALWAYS
     READ ... */
  outb(ATA_C_READ, ioaddr + ATA_CMD);

  for(timeout =3D 0; timeout < 30000; timeout++)
	 {
      status =3D inb(ioaddr + ATA_STATUS);
      if(!(status & ATA_S_BSY))
        break;

      usleep(1);
    }
  if(timeout =3D=3D 30000)
    printk("TIMEOUT");

  if(!(status & ATA_S_DRQ))
	 {
		printk("Error (0x%x)\n", inb(ioaddr + ATA_ERROR));
		return -1;
	 }

  for(i =3D 0; i < 256; i++)
	 buffer[i] =3D inw(ioaddr);
  return 0;
}

int hd_input(void *buffer, word len, dword block, byte cmd)
{
	word n;
	word *buf =3D buffer;

	if (hd_wait(block)) return 1;
	outp(hd_reg_base + REG_PRECOMP, 0);
	outp(hd_reg_base + REG_COUNT, len);
	outp(hd_reg_base + REG_SECTOR, (block >>  0) & 0xFF);
	outp(hd_reg_base + REG_CYL_LO, (block >>  8) & 0xFF);
	outp(hd_reg_base + REG_CYL_HI, (block >> 16) & 0xFF);
	outp(hd_reg_base + REG_LDH, LDH_LBA | ldh_init(hd_hd) | ((block >> 24) =
& 0x7));
	outp(hd_reg_base + REG_CTL, CTL_EIGHTHEADS | CTL_INTDISABLE); /* > a 8 =
tetes */
	if (hd_wait(block)) return 1;

	outp(hd_reg_base + REG_COMMAND, cmd);
	if (hd_wait(block)) return 1;

	for (n =3D 0; n < SECTOR_SIZE*len/2; ) {
		word x =3D inpw(hd_reg_base + REG_DATA);
		buf[n++] =3D x;
	}

	if (inp(hd_reg_base + REG_STATUS) & STATUS_ERR) {
		printf("%s line %d : cmd 0x%02x at LBA =3D %lu (status =3D %02x, error =
=3D %02x)\n", __FILE__, __LINE__, cmd, block, inp(hd_reg_base + =
REG_STATUS), inp(hd_reg_base + REG_ERROR));
		return 1;
	}

	return 0;
}

int hd_read(void *buffer, word len, dword sector, int methode)
{
	if (methode =3D=3D 0)
		return hd_input(buffer, len, sector, CMD_READ);
	else
		return hd_input_thomas(buffer, len, sector, CMD_READ);
}

int main(void)
{
	clrscr();

	hd_sethd(0x170, 1);

	puts("------- READ METHODE HERVE ------");
	partition(0, 0);
	puts("------- READ METHODE THOMAS ------");
	partition(0, 1);
	return 0;
}


/* =
************************************************************************ =
*/

typedef struct {
	byte  status_;
	byte  startHead_;
	byte  startSecCyl_[2];
	byte  type_;
	byte  endHead_;
	byte  endSecCyl_[2];
	dword bootSec_;
	dword numSec_;
} PartitionEntryStruct;

typedef struct {
	byte  bootCode_[0x1BE];
	PartitionEntryStruct entries_[4];
	word  iDCode_;
} PartitionSectorStruct;

char *nom_type(byte type)
{
	static struct {
		byte value;
		char *name;
	} types[] =3D {
   	{ 0x00, "None" },
		{ 0x01, "FAT12" },
		{ 0x02, "XENIX" },
		{ 0x03, "XENIX" },
		{ 0x04, "FAT16" },
		{ 0x05, "Ext. part." },
		{ 0x06, "FAT16 >32M" },
		{ 0x07, "NTFS or HPFS" },
		{ 0x0A, "Boot Mgr" },
		{ 0x0b, "FAT32" },
		{ 0x0c, "FAT32" },
		{ 0x0e, "FAT16" },
		{ 0x0f, "Ext. part." },
		{ 0x51, "Ext. part. Ontrack" },
		{ 0x64, "Novell" },
		{ 0x75, "PCIX" },
		{ 0xdb, "CPM/Concurrent" },
		{ 0xff, "BBT" },
	};
	static char unknown[] =3D "UNKNOWN";
	int i;
	for (i =3D 0; i < sizeof(types) / sizeof(types[0]); i++)
		if (types[i].value =3D=3D type)
			return types[i].name;
	return unknown;
}

void partition(dword offset, int methode)
{
	int i;
	dword extended =3D 0;
	PartitionSectorStruct pt;

	hd_read(&pt, 1, offset, methode);

	/* is partition table valid ? */
	for (i =3D 0; i < 4; i++) {
		if (pt.entries_[i].type_ =3D=3D 0x05 || pt.entries_[i].type_ =3D=3D =
0x0f)
			extended =3D pt.entries_[i].bootSec_ + offset;
		if (pt.entries_[i].status_ & ~0x80)
			return;
	}

	printf("Partition at offset %lu\n", offset);

	puts("Boot Type Cyl  Head Sect Cyl  Head Sect Boot Sct Num Sect");
	puts("=3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D =
=3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D =
=3D=3D=3D=3D=3D=3D=3D=3D");
	for (i =3D 0; i < 4; i++) {
		printf("0x%02x 0x%02x %4d %4d %4d %4d %4d %4d %8lu %8lu  %s\n",
					pt.entries_[i].status_,
					pt.entries_[i].type_,
					pt.entries_[i].startSecCyl_[1] + ((pt.entries_[i].startSecCyl_[0] =
>> 6) << 8),
					pt.entries_[i].startHead_,
					pt.entries_[i].startSecCyl_[0] & 0x3f,
					pt.entries_[i].endSecCyl_[1] + ((pt.entries_[i].endSecCyl_[0] >> 6) =
<< 8),
					pt.entries_[i].endHead_,
					pt.entries_[i].endSecCyl_[0] & 0x3f,
					pt.entries_[i].bootSec_,
					pt.entries_[i].numSec_,
					nom_type(pt.entries_[i].type_)
					);
		if (pt.entries_[i].type_ =3D=3D 0x01
			|| pt.entries_[i].type_ =3D=3D 0x04
			|| pt.entries_[i].type_ =3D=3D 0x06
			|| pt.entries_[i].type_ =3D=3D 0x0e)
			fat_info(pt.entries_[i].bootSec_, methode);
	} putchar('\n');
	if (extended)
		partition(extended, methode);
}

/* =
************************************************************************ =
*/

typedef struct fat_bootsector {
	byte Jump[3];
	byte OEM_ID[8];
	word bytes_per_sector;
	byte sectors_per_cluster;
	word reserved_sectors;
	byte number_of_FATs;
	word root_dir_entries; // Reserved1 for FAT32
	word number_of_sectors; // Reserved1 for FAT32
	byte MediaDescriptor;
	word sectors_per_FAT;
	word TrackSize;
	word HeadCount;
	dword StartSector;
	dword big_number_of_sectors;
	word Drive;
	byte signature;
	dword serial_number;
	byte label[11];
	byte FSID[8];
	byte Loader[448];
	word magic_number;  // 0xaa55
};

void fat_info(dword sector, int methode)
{
	struct fat_bootsector bs;
	hd_read(&bs, 1, sector, methode);
	printf("  fat_info : FS=3D%8.8s   magic_number=3D%04x", bs.FSID, =
bs.magic_number);
   putchar('\n');
}
------=_NextPart_000_0045_01C1B4DC.429684D0--