[Kos-dev] ATA, probleme

kos-dev@enix.org kos-dev@enix.org
11 Feb 2002 18:23:20 +0100


--=-=-=

salut a tous,

j'ai une question, plutot pour Hlide, mais si d'autres savent, c'est
tout aussi bien.

lorsque j'utilise le mode d'adressage des secteurs CHS
(cylinder/head/sector) ca marche nickel, je peux lire n'importe quel
secteur du disque, decoder la table des partitions, et les tables des
partitions etendues.

par contre, quand j'utilise le mode d'adressage LBA, quelque soit le
secteur que je veux lire, ca me renvoie toujours le contenu du secteur
0. Ca me permet de lire la table des partitions, mais pas de lire
d'autres secteurs. Ce qui est un peu ennuyeux. Je suis sur que
l'ordinateur sur lequel je teste supporte le LBA car Linux utilise le
LBA (j'ai modifie le noyau pour qu'il me dise si oui ou non il utilise
le LBA).

Je joins le code, la partie interessante pour cette question etant
dans add_ide_op_polled_mode.

Merci bcp

Thomas
--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=_ide.c

/* ATA driver for KOS
   by Thomas Petazzoni, <thomas.petazzoni@enix.org>
   with the help of Soren Schmidt, <sos@freebsd.dk>
*/

#include <kos/asm.h>
#include <lib/stdio.h>
#include <scheduler/scheduler.h>
#include <idt/irq.h>
#include <ide/_ide.h>
#include <liblist/liblist.h>
#include <kos/spinlock.h>
#include <lib/string.h>
#include <kmem/kmem.h>


#define ATA_MASTER                      0x00
#define ATA_SLAVE                       0x10

/* Registers */
#define ATA_DATA                        0x00    /* Data register */

#define ATA_ERROR                       0x01    /* (R) error register */

#define ATA_PRECOMP                     0x01    /* (W) precompensation */

#define ATA_SECTOR_COUNT                0x02    /* sector count register */

#define ATA_SECTOR_NUMBER               0x03    /* sector number register */

#define ATA_CYL_LSB                     0x04    /* cylinder# LSB */

#define ATA_CYL_MSB                     0x05    /* cylinder# MSB */

#define ATA_DRIVE                       0x06
#define         ATA_D_IBM               0xa0

#define ATA_STATUS                      0x07    /* status register */
#define         ATA_S_ERROR             0x01    /* error */
#define         ATA_S_INDEX             0x02    /* index */
#define         ATA_S_CORR              0x04    /* data corrected */
#define         ATA_S_DRQ               0x08    /* data request */
#define         ATA_S_DSC               0x10    /* drive Seek Completed */
#define         ATA_S_DWF               0x20    /* drive write fault */
#define         ATA_S_DRDY              0x40    /* drive ready */
#define         ATA_S_BSY               0x80    /* busy */

#define ATA_CMD                         0x07    /* command register */
#define         ATA_C_ATA_IDENTIFY      0xec    /* get ATA params */
#define         ATA_C_ATAPI_IDENTIFY    0xa1    /* get ATAPI params*/
#define         ATA_C_READ              0x20    /* read command */
#define         ATA_C_WRITE             0x30    /* write command */
#define         ATA_C_READ_MULTI        0xc4    /* read multi command */
#define         ATA_C_WRITE_MULTI       0xc5    /* write multi command */
#define         ATA_C_SET_MULTI         0xc6    /* set multi size command */
#define         ATA_C_PACKET_CMD        0xa0    /* set multi size command */

#define ATA_ALTPORT                     0x206   /* alternate Status register */

#define ATA_DEVICE_CONTROL               0x206
#define         ATA_A_nIEN              0x02    /* disable interrupts */
#define         ATA_A_RESET             0x04    /* RESET controller */
#define         ATA_A_4BIT              0x08    /* 4 head bits */


/* Devices types */
#define ATA_ATA_MASTER                  0x01
#define ATA_ATA_SLAVE                   0x02
#define ATA_ATAPI_MASTER                0x04
#define ATA_ATAPI_SLAVE                 0x08

#define ATAPI_MAGIC_LSB                 0x14
#define ATAPI_MAGIC_MSB                 0xeb

typedef struct identify_device_info
{
  k_ui16_t general_config_info;      /* 0 */
  k_ui16_t nb_logical_cylinders;     /* 1 */
  k_ui16_t reserved1;                /* 2 */
  k_ui16_t nb_logical_heads;         /* 3 */
  k_ui16_t unformatted_bytes_track;  /* 4 */
  k_ui16_t unformatted_bytes_sector; /* 5 */
  k_ui16_t nb_logical_sectors;       /* 6 */
  k_ui16_t vendor1[3];               /* 7-9 */
  k_ui8_t  serial_number[20];        /* 10-19 */
  k_ui16_t buffer_type;              /* 20 */
  k_ui16_t buffer_size;              /* 21 */
  k_ui16_t ecc_bytes;                /* 22 */
  k_ui8_t  firmware_revision[8];     /* 23-26 */
  k_ui8_t  model_number[40];         /* 27-46 */
  k_ui8_t  max_multisect;            /* 47 */
  k_ui8_t  vendor2;
  k_ui16_t dword_io;                 /* 48 */
  k_ui8_t  vendor3;                  /* 49 */
  k_ui8_t  capabilities;
  k_ui16_t reserved2;                /* 50 */
  k_ui8_t  vendor4;                  /* 51 */
  k_ui8_t  pio_trans_mode;
  k_ui8_t  vendor5;                  /* 52 */
  k_ui8_t  dma_trans_mode;
  k_ui16_t fields_valid;             /* 53 */
  k_ui16_t cur_logical_cylinders;    /* 54 */
  k_ui16_t cur_logical_heads;        /* 55 */
  k_ui16_t cur_logical_sectors;      /* 56 */
  k_ui16_t capacity1;                /* 57 */
  k_ui16_t capacity0;                /* 58 */
  k_ui8_t  multsect;                 /* 59 */
  k_ui8_t  multsect_valid;
  k_ui32_t lba_capacity;             /* 60-61 */
  k_ui16_t dma_1word;                /* 62 */
  k_ui16_t dma_multiword;            /* 63 */
  k_ui16_t pio_modes;                /* 64 */
  k_ui16_t min_mword_dma;            /* 65 */
  k_ui16_t recommended_mword_dma;    /* 66 */
  k_ui16_t min_pio_cycle_time;       /* 67 */
  k_ui16_t min_pio_cycle_time_iordy; /* 68 */
  k_ui16_t reserved3[11];            /* 69-79 */
  k_ui16_t major_version;            /* 80 */
  k_ui16_t minor_version;            /* 81 */
  k_ui16_t command_sets1;            /* 82 */
  k_ui16_t command_sets2;            /* 83 dixit lk : b14 (smart enabled) */
  k_ui16_t reserved4[4];             /* 84-87 */
  k_ui16_t dma_ultra;                /* 88 dixit lk */
  k_ui16_t reserved5[37];            /* 89-125 */
  k_ui16_t last_lun;                 /* 126 */
  k_ui16_t reserved6;                /* 127 */
  k_ui16_t security;                 /* 128 */
  k_ui16_t reserved7[127];
} identify_device_info_t __attribute__((packed));


typedef struct partition_entry 
{
  k_ui8_t active;
  k_ui8_t start_dl;
  k_ui16_t start_cylinder;
  k_ui8_t type;
  k_ui8_t end_dl;
  k_ui16_t end_cylinder;
  k_ui32_t lba;
  k_ui32_t size;
} partition_entry_t;

#define PRIMARY_CONTROLLER 0
#define SECONDARY_CONTROLLER 1
#define MASTER 0
#define SLAVE 1
#define NB_CONTROLLERS 2

typedef struct partition
{
  enum { ACTIVE, NOT_ACTIVE } is_active;
  k_ui8_t  fs_type;
  k_ui32_t start;
  k_ui32_t size;
  int      number;

  struct partition *next;
  struct partition *prev;
} partition_t;


typedef struct controller
{
  k_ui16_t ioaddr;
  k_ui16_t irq;
  enum { ATA_NOT_PRESENT, ATA_IDLE, ATA_WAIT_INTR } state;
  int ctrl;
  int devices;
  void *device[2];
} controller_t;

typedef struct harddisk
{
  k_ui16_t logical_cylinder_nb;
  k_ui16_t logical_head_nb;
  k_ui16_t logical_sector_per_track;
  k_ui32_t lba_capacity;
  char serial_number[21];
  char firmware_revision[9];
  char model_number[41];
  controller_t *ctrl;
  int flags;
#define HARDDISK_LBA_CAPABLE 0x1

  int size;
  int device;
  partition_t *partition_list;
} harddisk_t;

typedef struct cdrom
{
  controller_t *ctrl;
} cdrom_t;

typedef struct ide_op
{
  enum { READ, WRITE } type;
  enum { IDE_OP_WAITING, IDE_OP_IN_PROGRESS } status;
  harddisk_t *harddisk;
  int cyl;
  int sector;
  int head;
  char *buffer;
  struct ide_op *next, *prev;
} ide_op_t;

ide_op_t *ide_op_list;




controller_t controllers[NB_CONTROLLERS] =
{
  { 0x1F0, 14, ATA_NOT_PRESENT, PRIMARY_CONTROLLER, 0, { NULL, NULL }},
  { 0x170, 15, ATA_NOT_PRESENT, SECONDARY_CONTROLLER, 0, { NULL, NULL }}
};


static int init_ide(controller_t *ctrl)
{
  int status0, status1;
  int mask = 0;
  int timeout;

  outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
  usleep(1);
  status0 = inb(ctrl->ioaddr + ATA_STATUS);

  outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
  usleep(1);
  status1 = inb(ctrl->ioaddr + ATA_STATUS);
  
  if((status0 & 0xf8) != 0xf8)
    mask |= 0x01;
  if((status1 & 0xf8) != 0xf8)
    mask |= 0x02;

  /* If both BSY bit are set => leave */
  if((status0 & ATA_S_BSY) && (status1 & ATA_S_BSY))
    return 0;

  /* no device present */
  if(!mask)
    return 0;
  
  /* select the master */
  outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
  usleep(1);
  /* send reset */
  outb(ATA_A_nIEN | ATA_A_RESET, ctrl->ioaddr + ATA_ALTPORT);
  usleep(1000);
  outb(ATA_A_nIEN, ctrl->ioaddr + ATA_ALTPORT);
  usleep(1000);
  inb(ctrl->ioaddr + ATA_ERROR);
  outb(ATA_A_4BIT, ctrl->ioaddr + ATA_ALTPORT);
  usleep(1);

  /* wait busy */
  for(timeout = 0; timeout < 300000; timeout++)
    {
      /* select master and get status register */
      outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
      usleep(1);
      status0 = inb(ctrl->ioaddr + ATA_STATUS);
      
      /* select slave and get status register */
      outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
      usleep(1);
      status1 = inb(ctrl->ioaddr + ATA_STATUS);

      if(mask == 0x01)
	if(!(status0 & ATA_S_BSY))
	  break;
      if(mask == 0x02)
	if(!(status1 & ATA_S_BSY))
	  break;
      if(mask == 0x03)
	if(!(status0 & ATA_S_BSY) && !(status1 & ATA_S_BSY))
	  break;
      usleep(100);
    }

  if(status0 & ATA_S_BSY)
    mask &= ~0x01;
  if(status1 & ATA_S_BSY)
    mask &= ~0x02;
  
  /* no device */
  if(!mask)
    return 0;

  /* there's at least one device, initialize state */
  ctrl->state = ATA_IDLE;

  /* check what is the type of the device */
  outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
  usleep(10);
  
  if(inb(ctrl->ioaddr + ATA_CYL_LSB) == ATAPI_MAGIC_LSB &&
     inb(ctrl->ioaddr + ATA_CYL_MSB) == ATAPI_MAGIC_MSB)
    {
      ctrl->devices |= ATA_ATAPI_MASTER;
    }
  
  outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
  usleep(10);
  
  if(inb(ctrl->ioaddr + ATA_CYL_LSB) == ATAPI_MAGIC_LSB &&
     inb(ctrl->ioaddr + ATA_CYL_MSB) == ATAPI_MAGIC_MSB)
    {
      ctrl->devices |= ATA_ATAPI_SLAVE;
    }

  if(status0 != 0x00 && !(ctrl->devices & ATA_ATAPI_MASTER))
    {
      outb(ATA_D_IBM | ATA_MASTER, ctrl->ioaddr + ATA_DRIVE);
      usleep(1);
      outb(0x58, ctrl->ioaddr + ATA_ERROR);
      outb(0xa5, ctrl->ioaddr + ATA_CYL_LSB);
      if(inb(ctrl->ioaddr + ATA_ERROR) != 0x58 &&
	 inb(ctrl->ioaddr + ATA_CYL_LSB) == 0xa5)
	{
	  ctrl->devices |= ATA_ATA_MASTER;
	}
    }
  
  if(status1 != 0x00 && !(ctrl->devices & ATA_ATAPI_SLAVE))
    {
      outb(ATA_D_IBM | ATA_SLAVE, ctrl->ioaddr + ATA_DRIVE);
      usleep(1);
      outb(0x58, ctrl->ioaddr + ATA_ERROR);
      outb(0xa5, ctrl->ioaddr + ATA_CYL_LSB);
      if(inb(ctrl->ioaddr + ATA_ERROR) != 0x58 &&
	 inb(ctrl->ioaddr + ATA_CYL_LSB) == 0xa5)
	{
	  ctrl->devices |= ATA_ATA_SLAVE;
	}
    }

  return 0;
}

static int convert_to_ascii(char *src, char *dst, int len)
{
  int i;
  
  for(i = 0; i < len; i=i+2)
    {
      dst[i] = (src[i+1] & 0xff);
      dst[i+1] = (src[i] & 0xff);
    }

  dst[len] = '\0';
  for(i = len; i > 0; i--)
    {
      if(dst[i] == 0)
	continue;
      else if(dst[i] == ' ')
	dst[i] = '\0';
      else
	break;
    }
  
  return 0;
}




/* Will be used for IRQ mode */
static int do_op_first_step(ide_op_t *op)
{
  controller_t *ctrl;

  ctrl = op->harddisk->ctrl;
  ctrl->state = ATA_WAIT_INTR;

  outb(ATA_A_4BIT, ctrl->ioaddr + ATA_ALTPORT);

  /* select drive */
  outb(ATA_D_IBM 
       | (op->harddisk->device == MASTER) ? ATA_MASTER : ATA_SLAVE
       | op->head, 
       ctrl->ioaddr + ATA_DRIVE);
  usleep(1);
  
  outb(1, ctrl->ioaddr + ATA_SECTOR_COUNT);
  outb(op->sector, ctrl->ioaddr + ATA_SECTOR_NUMBER);
  outb((op->cyl & 0xff), ctrl->ioaddr + ATA_CYL_LSB);
  outb(((op->cyl & 0xff00) >> 8), ctrl->ioaddr + ATA_CYL_MSB);

  /* FOR THE MOMENT WE DON'T CARE ABOUT THE OPERATION TYPE ... ALWAYS
     READ ... */
  op->status = IDE_OP_IN_PROGRESS;
  outb(ATA_C_READ, ctrl->ioaddr + ATA_CMD);

  return 0;
}

static int add_ide_op_with_irq(harddisk_t *harddisk, int type, int cyl, int head, int sector, char *buffer)
{
  ide_op_t *new;

  new = kmalloc(sizeof(ide_op_t));
  if(new == NULL)
    {
      printk("Memory allocation error\n");
      return -1;
    }

  if(type != READ && type != WRITE)
    return -1;

  new->status = IDE_OP_WAITING;
  new->harddisk = harddisk;
  new->cyl = cyl;
  new->sector = sector;
  new->head = head;
  new->buffer = buffer;
  new->type = type;
  
  list_add_tail(ide_op_list, new);
  
  if(harddisk->ctrl->state == ATA_IDLE)
    do_op_first_step(new);

  return 0;
}

static int add_ide_op_polled_mode(harddisk_t *harddisk, int type, 
				  k_ui32_t sector_num,
				  char *buffer)
{
  int timeout, status = 0;
  int i, tmp;
  k_ui8_t cyl_lo, cyl_hi, sect, head;
  controller_t *ctrl;

  __dbg_printk("[add_ide_op_polled_mode] bonjour\n");

  ctrl = harddisk->ctrl;

  if(type != READ && type != WRITE)
    {
      printk("Unknown type of operation\n");
      return -1;
    }

  ctrl->state = ATA_IDLE;

  __dbg_printk("Converting to correct sector addressing\n");

  if(harddisk->flags & HARDDISK_LBA_CAPABLE)
    {
      sect   = (sector_num & 0xff);
      cyl_lo = (sector_num >> 8) & 0xff;
      cyl_hi = (sector_num >> 16) & 0xff;
      head   = ((sector_num >> 24) & 0xf) | 0x40 /* LBA */;
      printk("Using LBA mode %d : sect=%d,cyl_lo=%d,cyl_hi=%d,head=%d\n",
	     sector_num,sect,cyl_lo,cyl_hi,head);
    }
  else
    {
      int cylinder = sector_num / 
	(harddisk->logical_head_nb * harddisk->logical_sector_per_track);
      int temp = sector_num %
	(harddisk->logical_head_nb * harddisk->logical_sector_per_track);
      cyl_lo = cylinder & 0xff;
      cyl_hi = (cylinder >> 8) & 0xff;
      head   = temp / harddisk->logical_sector_per_track;
      sect   = (temp % harddisk->logical_sector_per_track) + 1;
    }

  __dbg_printk("conversion done\n");

  /*
  printk("Going to read cyl_hi=0x%x, cyl_lo=0x%x, head=0x%x, sect=0x%x\n",
	 cyl_hi, cyl_lo, head, sect);
  */

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

  outb(ATA_A_nIEN | ATA_A_4BIT, ctrl->ioaddr + ATA_ALTPORT);
  /* select drive */
  outb(ATA_D_IBM 
       | (harddisk->device == MASTER) ? ATA_MASTER : ATA_SLAVE
       | head, 
       ctrl->ioaddr + ATA_DRIVE);

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

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

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

  __dbg_printk("Checking for error\n");

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

  __dbg_printk("Avec bochs c'est la fete, on lit des secteurs\n");
  
  for(i = 0; i < 512; i++)
    {
      tmp = inw(ctrl->ioaddr);
      buffer[i] = (tmp & 0xff);      
      buffer[++i] = (tmp & 0xff00) >> 8;
    }

  __dbg_printk("[add_ide_op_polled_mode] bonjour\n");

  return 0;
}

static int get_partition_table (harddisk_t *harddisk)
{
  int i;
  partition_entry_t *p;
  partition_t *new;
  int extstart = 0;  
  int extsup = 0;
  int partnum = 1;
  k_ui8_t buffer[512];
  
  if(add_ide_op_polled_mode(harddisk, READ, 0, buffer) < 0)
    {
      __dbg_printk("Bonjour coucou\n");
      return -1;
    }

  __dbg_printk("Going to dereference harddisk 0x%x.. might explose\n", (unsigned) harddisk);
  p = (partition_entry_t *) (buffer+446);
  harddisk->partition_list = NULL;

  /*  GROS TEST POUR DEBUGGAGE LBA
  {
    char buffer2[512];
    if(add_ide_op_polled_mode(harddisk, READ, 1, buffer2) < 0)
      printk("*********** EROOOR \n");
    printk("buffer1 : ");
    for(i = 0; i < 16; i++)
      printk("%x ", buffer[446+i]);
    printk("\n");
    printk("buffer2 : ");
    for(i = 0; i < 16; i++)
      printk("%x ", buffer2[446+i]);
  }
  */

  /* Manage primary partitions */
  for (i = 0; i < 4; i++)
    {
      if (p[i].size == 0)
	continue;

      new = kmalloc(sizeof(partition_t));
      if(new == NULL)
	{
	  printk("Couldn't allocate memory\n");
	  return -1;
	}

      if(p[i].type != 0x5)
	{
	  new->is_active = (p[i].active == 0) ? 0 : 1;
	  new->fs_type   = p[i].type;
	  new->start     = p[i].lba;
	  new->size      = p[i].size;
	  new->number    = partnum++;
	  list_add_tail(harddisk->partition_list, new);
	}
      else
	extstart = p[i].lba;
    }

  /* Manage extended partitions */
  while(extstart != 0)
    {
      if(partnum > 6)
	break;
      /*
      printk("Reading MBR for extended partition : %d\n",
	     extstart+extsup);
      */

      memset(buffer, 0, 512);
      if(add_ide_op_polled_mode(harddisk, READ, extstart+extsup, buffer) < 0)
	{
	  printk("Error while reading sector %d\n", extstart+extsup);
	  return -1;
	}
      
      p = (partition_entry_t *) (buffer + 446);

      new = kmalloc(sizeof(partition_t));
      if(new == NULL)
	{
	  printk("Couldn't allocate memory\n");
	  return -1;
	}

      new->is_active = (p[0].active == 0) ? 0 : 1;
      new->fs_type   = p[0].type;
      new->start     = extstart + extsup + p[0].lba;
      new->size      = p[0].size;
      new->number    = partnum++;
      /*
      printk("First entry : ");
      for (i = 0; i < 16; i++)
	printk("%x ", (unsigned) buffer[446+i]);
      printk("Second entry : ");
      for (i = 0; i < 16; i++)
	printk("%x ", (unsigned) buffer[446+16+i]);
      printk("Extended adding %d (%d %d 0x%x) %x%x\n", 
	     partnum-1, new->start, new->size, new->fs_type,
	     (unsigned)buffer[510], (unsigned)buffer[511]);
      */
      list_add_tail(harddisk->partition_list, new);

      extsup = p[1].lba;
      if(extsup == 0)
	break;
    }

  return 0;
}


/* this function set the command "Identify Drive". For this command,
   we don't wait for an IRQ, we just wait for BSY bit to be
   cleared. (polled mode) */

static int get_drv_infos(controller_t *ctrl, int device)
{ 
  int timeout, status=0;
  harddisk_t *harddisk;
  identify_device_info_t *dinfo;
  k_ui16_t buffer[256];
  int i;

  /* On met nIEN a 1 dans device control */
  outb(ATA_A_nIEN | ATA_A_4BIT, ctrl->ioaddr + ATA_DEVICE_CONTROL);
  usleep(1);

  /* on selectionne le device */
  outb(ATA_D_IBM | (device == 0) ? ATA_MASTER : ATA_SLAVE, 
       ctrl->ioaddr + ATA_DRIVE);

  /* sencind command */
  outb(ATA_C_ATA_IDENTIFY, ctrl->ioaddr + ATA_CMD);

  for(timeout = 0; timeout < 30000; timeout++)
    {
      status = inb(ctrl->ioaddr + ATA_STATUS);
      if(!(status & ATA_S_BSY))
	break;
      
      usleep(1);
    }

  if(!(status & ATA_S_DRQ))
    {
      printk("Error\n");
      return -1;
    }

  for(i = 0; i < 256; i++)
    buffer[i] = inw(ctrl->ioaddr);

  dinfo = (identify_device_info_t *) buffer;

  harddisk = (harddisk_t *) ctrl->device[device];
  harddisk->ctrl = ctrl;
  harddisk->device = device;

  harddisk->logical_cylinder_nb      = dinfo->nb_logical_cylinders;
  harddisk->logical_head_nb          = dinfo->nb_logical_heads;
  harddisk->logical_sector_per_track = dinfo->nb_logical_sectors;

  if(harddisk->logical_sector_per_track == 0 ||
     harddisk->logical_head_nb == 0 ||
     harddisk->logical_cylinder_nb)
    return -1;
  
  harddisk->lba_capacity             = dinfo->lba_capacity;
  
  harddisk->flags = 0;

  if(dinfo->capabilities & (1<<1)     /* LBA bit must be set */
     && dinfo->major_version          /* major version must be non 0 */
     && (dinfo->fields_valid & 1)     /* lba fields must be valid */
     && (dinfo->lba_capacity))        /* lba capacity must be non 0 */
    harddisk->flags |= HARDDISK_LBA_CAPABLE;

  if(harddisk->logical_head_nb == 16 &&
     harddisk->logical_sector_per_track == 63 &&
     harddisk->logical_cylinder_nb == 16383)
    {
      if(harddisk->flags & HARDDISK_LBA_CAPABLE)
	harddisk->size = harddisk->lba_capacity;
      else
	FAILED_VERBOSE("Large harddisk without LBA ...\n");
    }
  else
    harddisk->size = 
      harddisk->logical_cylinder_nb * 
      harddisk->logical_sector_per_track *
      harddisk->logical_head_nb;

  convert_to_ascii(dinfo->model_number, harddisk->model_number,40);
  convert_to_ascii(dinfo->serial_number, harddisk->serial_number,20);  
  convert_to_ascii(dinfo->firmware_revision, harddisk->firmware_revision,8);

  __dbg_printk("Calling get_partition_table for %d-%d\n",
	       ctrl->ctrl, device);
  if(get_partition_table(harddisk) < 0)
    {
      printk("Error while getting partition table\n");
      return -1;
    }

  return 0;
}

static void ide_handler(int nb, cpu_state_t *state)
{
  UNUSED(state);
  if(controllers[PRIMARY_CONTROLLER].state == ATA_WAIT_INTR)
    {
      printk("Got an IRQ %d !\n", nb);
      printk("The job was of type : %d\n", ide_op_list->type);
      controllers[PRIMARY_CONTROLLER].state = ATA_IDLE;
    }
}

static char *partition_type(int type)
{
  switch(type)
    {
    case 0xe:
    case 0x6:
      return "FAT16";
    case 0xb:
    case 0xc:
      return "FAT32";
    case 0x82:
      return "Linux Swap";
    case 0x83:
      return "Linux";
    default:
      return "Unknow";
    }
}

      

static int initialize_devices(int controller)
{
  char c;
  controller_t *ctrl;

  if(controller == PRIMARY_CONTROLLER)
    {
      c = 'a';
      ctrl = &controllers[PRIMARY_CONTROLLER];
    }
  else if(controller == SECONDARY_CONTROLLER)
    {
      c = 'c';
      ctrl = &controllers[SECONDARY_CONTROLLER];
    }
  else
    {
      printk("Unknow controller !\n");
      return -1;
    }

  if(ctrl->state != ATA_NOT_PRESENT)
    {
      if(ctrl->devices & ATA_ATA_MASTER)
	{
	  harddisk_t *harddisk;
	  partition_t *p;
	  int nb_elts;
	  
	  ctrl->device[MASTER] = kmalloc(sizeof(harddisk_t));
	  if(ctrl->device[MASTER] == NULL)
	    {
	      printk("[test_ide] memory allocation error\n");
	      return -1;
	    }
	  harddisk = (harddisk_t *) ctrl->device[MASTER];
	  if(get_drv_infos(ctrl, MASTER) < 0)
	    {
	      printk("Failure while getting info for master\n");
	      kfree(ctrl->device[MASTER]);
	      ctrl->device[MASTER] = NULL;
	      return -1;
	    }
	  
	  printk("hd%c: (%s = %d Mb : C/H/S : %d/%d/%d\n", 
		 c, harddisk->model_number, harddisk->size>>11,
		 harddisk->logical_cylinder_nb,
		 harddisk->logical_head_nb,
		 harddisk->logical_sector_per_track);
	  list_foreach(harddisk->partition_list, p, nb_elts)
	    {
	      printk(" - hd%c%d start=%d size=%d Mb type=%s\n", 
		     c, nb_elts+1, p->start, p->size>>11, partition_type(p->fs_type));
	    }
	}
      if(ctrl->devices & ATA_ATA_SLAVE)
	{
	  harddisk_t *harddisk;
	  partition_t *p;
	  int nb_elts;
	  
	  ctrl->device[SLAVE] = kmalloc(sizeof(harddisk_t));
	  if(ctrl->device[SLAVE] == NULL)
	    {
	      printk("[test_ide] memory allocation error\n");
	      return -1;
	    }
	  harddisk = (harddisk_t *) ctrl->device[SLAVE];
	  if(get_drv_infos(ctrl, SLAVE) < 0)
	    {
	      printk("Failure while getting info for slave\n");
	      kfree(ctrl->device[SLAVE]);
	      ctrl->device[SLAVE] = NULL;
	      return -1;
	    }

	  printk("hd%c: (%s = %d Mb : C/H/S : %d/%d/%d\n", 
		 c+1, harddisk->model_number, harddisk->size>>11,
		 harddisk->logical_cylinder_nb,
		 harddisk->logical_head_nb,
		 harddisk->logical_sector_per_track);
	  
	  list_foreach(harddisk->partition_list, p, nb_elts)
	    {
	      printk(" - hd%c%d start=%d size=%d Mb type=%s\n", 
		     c+1, nb_elts+1, p->start, p->size>>11, partition_type(p->fs_type));
	    }
	}
      if(ctrl->devices & ATA_ATAPI_MASTER)
	{
	  cdrom_t *cdrom;
	  ctrl->device[MASTER] = kmalloc(sizeof(cdrom_t));
	  if(ctrl->device[MASTER] == NULL)
	    {
	      printk("[test_ide] memory allocation error\n");
	      return -1;
	    }
	  cdrom = (cdrom_t *) ctrl->device[MASTER];
	  printk("hd%c (CD-ROM) ", c);
	}
      if(ctrl->devices & ATA_ATAPI_SLAVE)
	{
	  cdrom_t *cdrom;
	  ctrl->device[SLAVE] = kmalloc(sizeof(cdrom_t));
	  if(ctrl->device[SLAVE] == NULL)
	    {
	      printk("[test_ide] memory allocation error\n");
	      return -1;
	    }
	  cdrom = (cdrom_t *) ctrl->device[SLAVE];
	  printk("hd%c (CD-ROM) ", c+1);
	}
    }
  else
    printk("no controller found");

  printk("\n");

  return 0;
}


int test_ide(void)
{

  if(ide_init_babel_stuff() < 0)
    {
      __dbg_printk("[ide] error while initializing Babel\n");
      return -1;
    }
  
  
  /*
  printk("Primary : \n");
  init_ide(&controllers[PRIMARY_CONTROLLER]);
  initialize_devices(PRIMARY_CONTROLLER);

  printk("Secondary : \n");
  init_ide(&controllers[SECONDARY_CONTROLLER]);
  initialize_devices(SECONDARY_CONTROLLER);

  register_irq_handler(14, ide_handler);
  */

  
  return 0;
}

--=-=-=


-- 
PETAZZONI Thomas - thomas.petazzoni@enix.org - UIN : 34937744
(Perso)      http://www.enix.org/~thomas/
(KOS)        http://kos.enix.org/ 
(Club LinUT) http://club-linut.enix.org

--=-=-=--