Subversion Repositories shark

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Project: S.Ha.R.K.
 *
 * Coordinators:
 *   Giorgio Buttazzo    <giorgio@sssup.it>
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *
 * Authors     :
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
 *   Luca Abeni          <luca@gandalf.sssup.it>
 *   (see the web pages for full authors list)
 *
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
 *
 * http://www.sssup.it
 * http://retis.sssup.it
 * http://shark.sssup.it
 */


/***************************************

  CVS :        $Id: ide.c,v 1.1.1.1 2002-03-29 14:12:49 pj Exp $
 
  Revision:    $Revision: 1.1.1.1 $

  Last update: $Date: 2002-03-29 14:12:49 $

  This module contains IDE initialization, IDE glue between
  the "block device" module and the IDE low level module and some
  usefull function used by the low level module.

***************************************/


/*
 * Copyright (C) 19992,2000 Massimiliano Giorgi
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


#include "glue.h"

#include <fs/sysmacro.h>
#include <fs/major.h>
#include <fs/magic.h>
#include <fs/bdevinit.h>
#include <fs/assert.h>
#include <fs/maccess.h>
#include <fs/assert.h>

#include "sysind.h"
#include "bdev.h"
#include "phdsk.h"
#include "lodsk.h"
#include "ide.h"
#include "idereq.h"

/*
 * FLAGS
 */


/*+ if defined: scan for device on interface also if soft reset fail +*/
#define FORCE_SCANNING 1
//#undef FORCE_SCANNING

/*+ if defined: use PIO (polled) I/O on all interfaces, disable DMA +*/
#define FORCE_PIOMODE 1
//#undef FORCE_PIOMODE

/*+ if 1: search only master device (no slave) +*/
/*+ if 0: search master and slave device +*/
#define ONLY_MASTER 1

/*
 * DEBUG
 */


/*+ if defined: trace initialization ++*/
#define TRACE_INIT KERN_DEBUG
#undef TRACE_INIT

/*+ if defined: trace ide_scan() [to find devices] +*/
#define TRACE_IDESCAN KERN_DEBUG
#undef TRACE_IDESCAN

/*+ if defined: trace ide_scandisk() [to find logical layout] +*/
#define TRACE_IDESCANDEV KERN_DEBUG
#undef TRACE_IDESCANDEV

/**/

/*+ these are debug macros... +*/

#ifdef TRACE_INIT
#define printk0(fmt,args...) \
        printk(TRACE_INIT "ide_init: " fmt,##args)

#else
#define printk0(fmt,args...)
#endif

#ifdef TRACE_IDESCAN
#define printk1(fmt,args...) \
        printk(TRACE_IDESCAN "ide_scan: " fmt,##args)

#else
#define printk1(fmt,args...)
#endif

#ifdef TRACE_IDESCANDEV
#define printk2(fmt,args...) \
        printk(TRACE_IDESCANDEV "ide_scandisk: " fmt,##args)

#else
#define printk2(fmt,args...)
#endif

/*
 *
 *
 */


/*+ Name used by this block device +*/
static char device_name[]="ide";

// /dev/ide/hd-i0mp1

/*+ Mantains informatio about a single interface +*/
/* warning: must not cross 4KBytes boundaries (required for DMA operations) */
struct ideinfo ide[MAXIDEINTERFACES]={{0}};
//struct ideinfo ide[MAXIDEINTERFACES] __attribute__((nocommon));
//struct ideinfo ide[MAXIDEINTERFACES] __attribute__((section("ide_section")))=
//{0};

/*+ Mantains information about every physical device +*/
static struct ideminorinfo mtable[MAXIDEMINOR];

/*
 *
 *
 *
 */


//#ifndef NDEBUG
void ide_dump_status(void)
{
  int i;

  printk(KERN_INFO "ide block device status:");
  for (i=0;i<MAXIDEINTERFACES;i++)
    if (!is_ide_free(i)) {
      printk(KERN_INFO "  ide%i:",i);
      printk(KERN_INFO "    errors: %i",ide[i].errors);
    }
}
//#endif

/*
 * how parameters are mapped to device minor number:
 *
 *   7   6   5   4   3   2   1   0
 * ---------------------------------
 * I   .   .   I   I   .   .   .   I
 * ---------------------------------
 *       ^       ^         ^
 *       I       I         I-- logical disk (aka partition)
 *       I       I------------ drive id     (aka master,slave)
 *       I-------------------- interface
 */


/*++++++++++++++++++++++++++++++++++++++
 
  Convert an interface id, driver id, logical disk to a device id.

  __dev_t idemakedev
    return a device id

  int ideif
    ide interface sequential number

  int drv
    ide channel (IDE_MASTER, IDE_SLAVE)

  int lodsk
    logical disk (aka partition) on than device
  ++++++++++++++++++++++++++++++++++++++*/


static __inline__ __dev_t idemakedev(int ideif,int drv,int lodsk)
{
  return makedev(MAJOR_B_IDE,((ideif&0x7)<<5)|((drv&0x1)<<4)|(lodsk&0xf));
}

/*++++++++++++++++++++++++++++++++++++++
 
  Extract an interface id from a device id.

  int idehwif
    return an interface id

  __dev_t dev
    device id to parse
  ++++++++++++++++++++++++++++++++++++++*/


static __inline__ int idehwif(__dev_t dev)
{
  return minor(dev)>>5;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Extract a drive id from a device id.

  int idedriveid
    return a device id

  __dev_t dev
    device id to parse
  ++++++++++++++++++++++++++++++++++++++*/


static __inline__ int idedriveid(__dev_t dev)
{
  return (minor(dev)&0x10)?1:0;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Extract a logical disk id from a device id.

  int idelodsk
    return a logical disk id

  __dev_t dev
    device id to parse
  ++++++++++++++++++++++++++++++++++++++*/


static __inline__ int idelodsk(__dev_t dev)
{
  return minor(dev)&0xf;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Extract the minor part of a device number.

  int idemindex
    return a device minor number

  __dev_t dev
    device id to parse
  ++++++++++++++++++++++++++++++++++++++*/


static __inline__ int idemindex(__dev_t dev)
{
  return minor(dev);
}


/*++++++++++++++++++++++++++++++++++++++
 
  Parse a device minor number from a device id and a logical disk id.

  int idemindexext
    return a device minor number

  __dev_t dev
    device id to parse

  int lodsk
    logical disk id to parse
  ++++++++++++++++++++++++++++++++++++++*/


static __inline__ int idemindexext(__dev_t dev, int lodsk)
{
  return minor(dev)+(lodsk&0xf);
}

/* --- */

//#ifndef NDEBUG
int ide_dump_startsize(__dev_t dev, __blkcnt_t *start, __blkcnt_t *size)
{
  int i;
  if (major(dev)!=MAJOR_B_IDE) return -1;
  i=idemindex(dev);
  if (mtable[i].used) {
    *start=mtable[i].start;
    *size=mtable[i].size;
    return 0;
  }
  return -1;
}
//#endif

/*
 *
 * to manage struct ata_diskid
 *
 */


/*++++++++++++++++++++++++++++++++++++++
 
  Dump, using printk(), the "important" information returned by an ide
  device in response to an ATA IDENTIFY request.

  struct ata_diskid *ptr
    pointer to the structure returned by an IDENTIFY command
   
  struct ide_diskinfo *info
    pointer to the disk information structure (build decoding an
    ata_diskid structure)
  ++++++++++++++++++++++++++++++++++++++*/


static void ide_dump_diskid(struct ata_diskid *ptr,
                            struct ide_diskinfo *info)
{
  char atabuf[256];
  int i,j;
 
  if (is_ATA4(ptr)||is_ATA3(ptr)||is_ATA2(ptr)||is_ATA(ptr)) {
    i=0;
    if (is_ATA(ptr)) {
      atabuf[i++]='1';
      atabuf[i++]=' ';
    }
    if (is_ATA2(ptr)) {
      atabuf[i++]='2';
      atabuf[i++]=' ';
    }
    if (is_ATA3(ptr)) {
      atabuf[i++]='3';
      atabuf[i++]=' ';
    }
    if (is_ATA4(ptr)) {
      atabuf[i++]='4';
      atabuf[i++]=' ';
    }
    atabuf[i++]='\0';
  } else
    /* actualy only ATA disk are recognized */
    sprintf(atabuf,"?");

  printk(IDELOG "    device         : hard disk");
  printk(IDELOG "    model          : %s",ptr->model);
  printk(IDELOG "    serial         : %s",ptr->serial);
  printk(IDELOG "    firmware rev   : %s",ptr->firmware);
  printk(IDELOG "    default C/H/S  : %i/%i/%i",
         ptr->def_cyls,ptr->def_heads,ptr->def_sects);
  printk(IDELOG "    total capacity : ~%4.3f GBytes",
         (double)ptr->lba_capacity/(1024.0*1024.0*2.0));
  printk(IDELOG "    ATA            : %s",atabuf);
  printk(IDELOG "    LBA            : %s",is_LBAcapable(ptr)?"yes":"no");

  i=0;
  if (info->max_pio_mode<0) strcpy(atabuf,"none");
  else {
    for (j=info->max_pio_mode;j>=0;j--) {
      strcpy(atabuf+i,"pio"); i+=3;
      atabuf[i++]=j+'0';
      atabuf[i++]=' ';
    }
    atabuf[i++]='\0';
  }
  printk(IDELOG "    PIO modes      : %s",atabuf);

  i=0;
  if (info->max_dma_mode<0) strcpy(atabuf,"none");
  else {
    for (j=info->max_dma_mode;j>=0;j--) {
      strcpy(atabuf+i,"mword"); i+=5;
      atabuf[i++]=j+'0';
      atabuf[i++]=' ';
    }
    atabuf[i++]='\0';
  }  
  printk(IDELOG "    DMA modes      : %s",atabuf);
 
  i=0;
  if (info->max_udma_mode<0) strcpy(atabuf,"none");
  else {
    for (j=info->max_udma_mode;j>=0;j--) {
      strcpy(atabuf+i,"udma"); i+=4;
      atabuf[i++]=j+'0';
      atabuf[i++]=' ';
    }
    atabuf[i++]='\0';
  }
  printk(IDELOG "    UDMA modes     : %s",atabuf);    
}

/*++++++++++++++++++++++++++++++++++++++
 
  Dump, using printk(), the "important" information returned by an ide
  device in response to an ATAPI PACKET IDENTIFY request.

  struct atapi_diskid *ptr
    pointer to the structure returned by a PACKET IDENTIFY command
  ++++++++++++++++++++++++++++++++++++++*/


static void ide_dump_atapidiskid(struct atapi_diskid *ptr)
{
  char atabuf[16];
  //__uint8_t *p;
  char *dev;
  int i=0;
 
  if (is_ATAPIdevice(ptr)) {
    strcpy(atabuf,"ATAPI ");
    i=6;
  }
 
  if (is_ATA4(ptr)||is_ATA3(ptr)||is_ATA2(ptr)||is_ATA(ptr)) {
    if (is_ATA(ptr)) {
      atabuf[i++]='1';
      atabuf[i++]=' ';
    }
    if (is_ATA2(ptr)) {
      atabuf[i++]='2';
      atabuf[i++]=' ';
    }
    if (is_ATA3(ptr)) {
      atabuf[i++]='3';
      atabuf[i++]=' ';
    }
    if (is_ATA4(ptr)) {
      atabuf[i++]='4';
      atabuf[i++]=' ';
    }
    atabuf[i++]='\0';
  } else {
    /* actualy only ATA disk are recognized */
    atabuf[i++]='?';
    atabuf[i++]='\0';
  }

  if (is_directdev(ptr)) dev="direct";
  else if (is_sequentialdev(ptr)) dev="sequential";
  else if (is_printerdev(ptr)) dev="printer";
  else if (is_processordev(ptr)) dev="processor";
  else if (is_writeoncedev(ptr)) dev="write once";
  else if (is_cdromdev(ptr)) dev="cd-rom";
  else if (is_scannerdev(ptr)) dev="scanner";
  else if (is_opticalmemorydev(ptr)) dev="optical memory";
  else if (is_mediachengerdev(ptr)) dev="media changer";
  else if (is_communicatordev(ptr)) dev="communicator";
  else if (is_arraydev(ptr)) dev="array";
  else dev="?";
 
  printk(IDELOG "    device         : %s",dev);
  printk(IDELOG "    model          : %s",ptr->model);
  printk(IDELOG "    serial         : %s",ptr->serial);
  printk(IDELOG "    firmware rev   : %s",ptr->firmware);
  printk(IDELOG "    ATA            : %s",atabuf);  
}
 
/*
 *
 * Interface the "block device" module to the low-level routine
 *
 */


/*
void dump_buffer(__uint8_t *buf)
{
  int i;
  for (i=0;i<512;i++) {
    cprintf("%02x ",(int)*(buf+i));
    if (i%16==15) cprintf("\n");
  }
}
*/



/*++++++++++++++++++++++++++++++++++++++
 
  Try to lock a device.
  (A device can be locked if the device is a partition and the whole
  disk is not locked or if the device is the whole disk and any partititions
  have been locked).
 
  int ide_trylock
    return ?_ERR on error, ?_OK on success and, ?_CANT on failure
   
  __devt_t device
    device to use
  ++++++++++++++++++++++++++++++++++++++*/


static int ide_trylock(__dev_t device)
{
  int i,ind,ind2;
 
  ind=idemindex(device);
  assertk(ind>=0&&ind<MAXIDEMINOR);
 
  if (!mtable[ind].used) return TRYLOCK_ERR;

  if (mtable[ind].blocked) return TRYLOCK_CANT;
 
  if (idelodsk(device)==0) {
    for (i=1;;i++) {
      ind2=idemindex(idemakedev(idehwif(device),idedriveid(device),i));
      assertk(ind2>=0&&ind2<MAXIDEMINOR);
      if (ind2==ind) {
        mtable[ind].blocked=1;
        return TRYLOCK_OK;
      }
      if (!mtable[ind2].used) continue;
      if (mtable[ind2].blocked) return TRYLOCK_CANT;
    }
  }

  ind2=idemindex(idemakedev(idehwif(device),idedriveid(device),0));
  assertk(ind2>=0&&ind2<MAXIDEMINOR);
  assertk(mtable[ind2].used==1);

  if (mtable[ind2].blocked) return TRYLOCK_CANT;

  mtable[ind].blocked=1;
  return TRYLOCK_OK;
}

static int ide_tryunlock(__dev_t device)
{
  int ind;
 
  ind=idemindex(device);
  assertk(ind>=0&&ind<MAXIDEMINOR);
 
  if (!mtable[ind].used) return TRYUNLOCK_ERR;
  if (!mtable[ind].blocked) return TRYUNLOCK_ERR;
  mtable[ind].blocked=0;
  return TRYUNLOCK_OK;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Read a block of data (sector) from a device into a buffer.

  int bd_ide_read
    return 0 on success, other values on error

  __dev_t device
    device id to read from

  __blkcnt_t blocknum
    block number to read

  __uint8_t *buffer
    buffer for the readed data
  ++++++++++++++++++++++++++++++++++++++*/


static int bd_ide_read(__dev_t device, __blkcnt_t blocknum, __uint8_t *buffer)
{
  register int ideif=idehwif(device);
  register int index=idemindex(device);
  int res;
 
  magic_assert(ide[ideif].magic,IDE_MAGIC,
               "ide%i: interface overwritten",ideif);
  magic_assert(mtable[index].magic,IDE_MAGIC_MINOR,
               "ide%i: minor %i overwritten",ideif,minor(device));
 
  if (major(device)!=MAJOR_B_IDE) {
    printk(IDEERRLOG "ide%i: major %i is not EIDE",ideif,major(device));
    return -1;
  }
 
  if (minor(device)>MAXIDEMINOR) {
    printk(IDEERRLOG "ide%i: minor %i out of range",ideif,minor(device));
    return -1;
  }
 
  if (!mtable[index].used) {
    printk(IDEERRLOG "ide%i: minor %i not present",ideif,minor(device));
    return -1;
  }

  //cprintf("index=%i\n",index);
  //cprintf("blocknum=%li\n",(long)blocknum);
  //cprintf("size=%li\n",(long)mtable[index].size);
  //cprintf("start=%li\n",(long)mtable[index].start);  
  //cprintf("sizeof(size)=%i\n",sizeof(mtable[index].size));
 
  /*
  if (blocknum<0||blocknum>=mtable[index].size) {
    printk(IDEERRLOG "ide%i: request block out of range",ideif);
    return -1;
  }
  */

 
  res=ide_read(ideif,idedriveid(device),
                  mtable[index].start+blocknum,
                  buffer);

  //if (blocknum==0x9ea19)
  //  dump_buffer(buffer);
 
  //cprintf("index=%i\n",index);
  //cprintf("blocknum=%li\n",(long)blocknum);
  //cprintf("size=%li\n",(long)mtable[index].size);
  //cprintf("sizeof(size)=%i\n\n",sizeof(mtable[index].size));

  return res;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Move the head on a specified cylinder.

  int bd_ide_seek
    return 0 on success, other values on error

  __dev_t device
    device id to read from

  __blkcnt_t blocknum
    block number to moving into
  ++++++++++++++++++++++++++++++++++++++*/


static int bd_ide_seek(__dev_t device, __blkcnt_t blocknum)
{
  register int ideif=idehwif(device);
  register int index=idemindex(device);
  int res;
 
  magic_assert(ide[ideif].magic,IDE_MAGIC,
               "ide%i: interface overwritten",ideif);
  magic_assert(mtable[index].magic,IDE_MAGIC_MINOR,
               "ide%i: minor %i overwritten",ideif,minor(device));

  if (major(device)!=MAJOR_B_IDE) {
    printk(IDEERRLOG "ide%i: major %i is not EIDE",ideif,major(device));
    return -1;
  }
 
  if (minor(device)>MAXIDEMINOR) {
    printk(IDEERRLOG "ide%i: minor %i out of range",ideif,minor(device));
    return -1;
  }
 
  if (!mtable[index].used) {
    printk(IDEERRLOG "ide%i: minor %i not present",ideif,minor(device));
    return -1;
  }

  res=ide_seek(ideif,idedriveid(device),
                  mtable[index].start+blocknum);

  return res;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Write a block of data (sector) from a buffer into a device (not yet
  implemented, return always error).

  int bd_ide_write
    return 0 on success, other value on errors

  __dev_t device
    device id to write into

  __blkcnt_t blocknum
    block number to write

  __uint8_t *buffer
    buffer to write into
  ++++++++++++++++++++++++++++++++++++++*/


static int bd_ide_write(__dev_t device, __blkcnt_t blocknum, __uint8_t *buffer)
{
  register int ideif=idehwif(device);
  register int index=idemindex(device);
  int res;
 
  magic_assert(ide[ideif].magic,IDE_MAGIC,
               "ide%i: interface overwritten",ideif);
  magic_assert(mtable[index].magic,IDE_MAGIC_MINOR,
               "ide%i: minor %i overwritten",ideif,minor(device));

  if (major(device)!=MAJOR_B_IDE) {
    printk(IDEERRLOG "ide%i: major %i is not EIDE",ideif,major(device));
    return -1;
  }
 
  if (minor(device)>MAXIDEMINOR) {
    printk(IDEERRLOG "ide%i: minor %i out of range",ideif,minor(device));
    return -1;
  }
 
  if (!mtable[index].used) {
    printk(IDEERRLOG "ide%i: minor %i not present",ideif,minor(device));
    return -1;
  }

  res=ide_write(ideif,idedriveid(device),
                  mtable[index].start+blocknum,
                  buffer);

  return res;
}

/*
 *
 * Initialization
 *
 */


/*+ Data used to register the IDE module to the block device manager +*/
static struct block_device_operations ide_operations={
  ide_trylock,
  ide_tryunlock,
  bd_ide_read,
  bd_ide_seek,
  bd_ide_write
};

/* this information are saved from the initialization routine for
 * futher reference
 */


/*+ initialization parameter (for the "glue" initialization) +*/
void *ide_parm_initserver=NULL;

/*+ show information during startup? +*/
int ide_showinfo_flag=0;

/*++++++++++++++++++++++++++++++++++++++
 
  This function try to register an IDE interface, scan for device and
  identify the logical struct of the device

  int ide_tryregister
    return 0 on successe <0 on error

  int port0
    first port of the ide interface (ide port)

  int port1
    second port of the ide interface (control port)

  int irq
    irq of the ide interface
   
  int dma
    dma 16bits channel (if using not bus master mode)

  int bmdma
    port for the bus master dma operations
  ++++++++++++++++++++++++++++++++++++++*/


static int ide_tryregister(int port0, int port1, int irq, int dma, int bmdma)
{
  int ideif,res,j;
 
  ideif=ide_register(port0,port1,irq,dma,bmdma);
  printk0("registering IDE at 0x%04x,0x%04x,%i,%i,0x%04x... ",
          port0,port1,irq,dma,bmdma);
  if (ideif>=0) {
    res=ide_scan(ideif);
    printk0("found %i peripheral(s)",res);
    if (res>0) {
      for (j=IDE_MASTER;j<=IDE_SLAVE;j++) {
        if (ide[ideif].pdisk[j]!=NULL) {
          printk0("scanning %s for logical layout",
                  j==IDE_MASTER?"master":"slave");
          ide_scandisk(ideif,j);
        }
      }
      return 0;
    }
    return -1;
  } else
    printk0("registering failed");
  return -2;
}

/*++++++++++++++++++++++++++++++++++++++

  This function parse a string to find "command line options" for the
  IDE subsystem; see source for comments.

  int ide_scanparms
    return 0 on success, other values on error

  char *str
    string to parse
  ++++++++++++++++++++++++++++++++++++++*/


static int ide_scanparms(char *str)
{
  int port0,port1,irq,dma=-1,bmdma=-1;
  char *ptr;
  int ret;

  /* available string options:

     ide=port,sec_port,irq
     example
     "ide=0x1f0,0x3f0,14"

     try to register this ide interface
   */


  printk0("(start) searching for parameters");  
  if (str==NULL) {
    printk0("(end) searching for parameters");  
    return 0;
  }
 
  ptr=str;
  for (;;) {
    ptr=strscn(ptr,"ide=");
    if (ptr==NULL) return 0;
    ret=sscanf(ptr,"ide=%x,%x,%i,%i,%x",&port0,&port1,&irq,&dma,&bmdma);
    if (ret==3||ret==5) {
      {
        int len;
        char *s;
        s=strchr(ptr,' ');
        if (s!=NULL) len=s-ptr+1;
        else len=strlen(ptr);
        memset(ptr,len,' ');
      }
      ide_tryregister(port0,port1,irq,dma,bmdma);
    }
    ptr++;
  }
  printk0("(end) searching for parameters");  
  return 0;
}

/*++++++++++++++++++++++++++++++++++++++

  This function initialize the IDE subsystem; must be called before every
  other function.

  It initialize internal data structure, register itself to the bdev
  (block dev) manager and try to initialize "standard" IDE interface;
  non-standard ide interface can be initialize using the struct IDE_PARMS
  (see include/fs/fsinit.h).

  int ide_init
    return 0 on success, other on failure

  BDEV_PARMS *parms
    pointer to a structure contains general and specific initialization
    data
  ++++++++++++++++++++++++++++++++++++++*/


int ide_init(BDEV_PARMS *parms)
{
  struct block_device bd;
  __uint32_t addr;
  int res;
  int i;

  printk0("START");
 
  init_idereq();
  printk0("init_idereq()... done");
 
  for (i=0;i<MAXIDEINTERFACES;i++) {
   
    magic_set(ide[i].magic,IDE_MAGIC);
   
    ide[i].server=NIL;
    ide[i].io_port=0;
    ide[i].io_port2=0;
    ide[i].irq=0;
    ide[i].pdisk[IDE_MASTER]=NULL;
    ide[i].info[IDE_MASTER].use_lba=0;
    ide[i].pdisk[IDE_SLAVE]=NULL;
    ide[i].info[IDE_SLAVE].use_lba=0;    
    //ide[i].reqhead=NIL;
    //ide[i].reqtail=NIL;
    ide[i].errors=0;

    /* some check on the ide[].prd struct */    
    addr=__lin_to_phy(ide[i].prd);

    /* must be 32bits aligned! */
    assertk((addr&3)==0); /* this is granted by aligned(4) of the struct */

    /* must not cross 4KBytes boundaries! */
    if ((addr&0xfffff000)!=((addr+sizeof(ide[i].prd)-1)&0xfffff000)) {
      printk(KERN_EMERG "ide[%i].prd cross 4Kbytes boundary!",i);
      printk(KERN_EMERG "ide[] table is located at 0x%08lx",(long)&ide);
      printk(KERN_EMERG "ide[%i] is located at 0x%08lx",
             i,(long unsigned)(&ide[i]));
      printk(KERN_EMERG "ide[%i].prd is located at 0x%08lx",
             i,(long unsigned)(&ide[i].prd));
      printk(KERN_EMERG "ide[%i].prd is located at 0x%08lx (phy) for 0x%04x",
             i,(long unsigned)addr,(int)sizeof(ide[i].prd));
     
      /* now! */
      assertk(0==-1);
    }
   
  }

  for (i=0;i<MAXIDEMINOR;i++) {
   
    magic_set(mtable[i].magic,IDE_MAGIC_MINOR);

    mtable[i].start=0;
    mtable[i].size=0;
    mtable[i].used=0;
    mtable[i].blocked=0;
  }

  ide_parm_initserver=IDEPARMS(parms).parm_initserver;
  ide_showinfo_flag=parms->showinfo;
  bd.bd_sectorsize=IDE_SECTOR_SIZE;
  bd.bd_op=&ide_operations;

  printk0("static data initialization... done");
 
  res=bdev_register(makedev(MAJOR_B_IDE,0),device_name,&bd);
  if (res) return -1;

  printk0("registering IDE to block-dev... done");

  /* Well... bus master dma operations i/o ports would be reported
   * by the pci device management module
   */

  ide_tryregister(0x1f0,0x3f0,14,3,0xe000);
  ide_tryregister(0x170,0x370,15,-1,0xe008);

  ide_scanparms(parms->config);

  printk0("END");
  return 0;    
}

/*
 *
 *
 */


/*++++++++++++++++++++++++++++++++++++++
 
  Scan for device on an IDE interface: reset the device, issue a
  IDENTIFY command and optional a PACKET IDENTIFY; if a hard disk
  is found it is registered to the "physical disk" module.

  int ide_scan
    return the number of device found on the interface (0,1 or 2)

  int ideif
    the interface to scan (every interface has a progess number)
  ++++++++++++++++++++++++++++++++++++++*/


int ide_scan(int ideif)
{
  struct ata_diskid   info;
  struct atapi_diskid info2;
  struct phdskinfo    disk;
  struct phdskinfo    *phdskptr;
  int                 drv;
  int                 res;
  //int                 ind;
  int                 found;
  int                 atapi;
  int                 fl;
 
  printk1("START");
 
  magic_assert(ide[ideif].magic,IDE_MAGIC,
               "ide: interface(%i) overwritten",ideif);

  if (ide[ideif].pdisk[IDE_MASTER]!=NULL||
      ide[ideif].pdisk[IDE_SLAVE]!=NULL)
    return 0;

  /* phase 0 */
  /* softreset */

  printk1("making a soft reset...");
  res=do_ide_softreset(ideif);
  if (res) {
    printk1("soft reset fail");
#ifndef FORCE_SCANNING
    printk1("END");
    return 0;
#endif
    printk1("FORCE_SCANNING");
  } else
    printk1("soft reset... done");
 
  /* phase 1 */
  /* searching for disk drive */

  found=0;
  for (drv=IDE_MASTER;drv<=(ONLY_MASTER?IDE_MASTER:IDE_SLAVE);drv++) {

    printk1("scanning for %s",drv==IDE_MASTER?"master":"slave");
   
    atapi=0;
    res=ide_identify(ideif,drv,&info);
   
    printk1("identify... done (device %sfound)",res==IDE_OK?"":"NOT ");
     
    if (res!=IDE_OK) {
      atapi=1;
      res=ide_pidentify(ideif,drv,&info2);
      printk1("pidentify... done (device %sfound)",res==IDE_OK?"":"NOT ");
    }
   
    if (res==IDE_OK) {
       
      if (ide_showinfo_flag&&!found) {
        printk(IDELOG "ide%i: 0x%3x,%i,%i,0x%04x",ideif,
               ide[ideif].io_port,ide[ideif].irq,
               (ide[ideif].dma==255)?-1:ide[ideif].dma,
               ide[ideif].io_bmdma);
      }
      found++;
             
      /* if this is an ATAPI device... */      
      if (atapi) {
        if (ide_showinfo_flag) {
          printk(IDELOG "ide%i: %s device",
                 ideif,drv==IDE_MASTER?"master":"slave");
          ide_dump_atapidiskid(&info2);
        }
        /* ATAPI devices not managed yet! */
        continue;
      }

      disk.pd_device=idemakedev(ideif,drv,0);

      disk.pd_sectsize=IDE_SECTOR_SIZE;      
      disk.pd_size=(__uint32_t)info.act_cyls*info.act_heads*info.act_sects;

      disk.pd_logeom.cyls=disk.pd_phgeom.cyls=info.act_cyls;
      disk.pd_logeom.heads=disk.pd_phgeom.heads=info.act_heads;
      disk.pd_logeom.sectors=disk.pd_phgeom.sectors=info.act_sects;

      if (is_LBAcapable(&info)) {
        ide[ideif].info[drv].use_lba=TRUE;
        disk.pd_ide_check_geom=0;
      } else {
        ide[ideif].info[drv].use_lba=FALSE;
        disk.pd_ide_check_geom=0;
      }

      /* for PIO capabilities */
      {
        __int8_t support;
        if (info.fields_valid&2) {
          if (info.eide_PIO_modes&2) support=4;
          else if (info.eide_PIO_modes&1) support=3;
          else support=info.PIO_mode;  
        } else
          support=info.PIO_mode;       
        ide[ideif].info[drv].max_pio_mode=support;
      }
      /* for DMA capabilities */
      {
        __int8_t support;
        if (info.DMA_mword&4) support=2;
        else if (info.DMA_mword&2) support=1;
        else if (info.DMA_mword&1) support=0;
        else support=-1;
        ide[ideif].info[drv].max_dma_mode=support;
      }
      /* for ULTRA DMA capabilities */
      {
        __int8_t support;
        if (!(info.fields_valid&4)) support=-1;
        else if (info.UDMA_cap&4) support=2;
        else if (info.UDMA_cap&2) support=1;
        else if (info.UDMA_cap&1) support=0;
        else support=-1;
        ide[ideif].info[drv].max_udma_mode=support;
      }
     
      /* Well... BM-DMA used by default (if possible)*/
      ide[ideif].info[drv].use_dma=0;
      fl=0;
      if (ide[ideif].info[drv].max_dma_mode!=-1) fl=1;
      if (ide[ideif].info[drv].max_udma_mode!=-1) fl=1;
#ifdef FORCE_PIOMODE
      fl=0; // so use PIO mode
#endif
      ide[ideif].info[drv].use_bm_dma=fl;
     
      /* Show informations... if request */
      if (ide_showinfo_flag) {
        printk(IDELOG "ide%i: %s device",
               ideif,drv==IDE_MASTER?"master":"slave");
        ide_dump_diskid(&info,&ide[ideif].info[drv]);
      }

      sprintf(disk.pd_name,"hd%c",'a'+ideif*2+drv);

      /* Register physical disk information */
      phdskptr=phdsk_register(&disk);
      if (phdskptr==NULL) continue;
      ide[ideif].pdisk[drv]=phdskptr;
     
      /* Well, the queueing algorithm must know the physical disk layout */
      ide[ideif].queue[drv].disk=phdskptr;

      /* Activate look a head... (if possible) */
      res=ide_enablelookahead(ideif,drv);
      if (ide_showinfo_flag)
        printk(IDELOG "ide%i: look ahead %s for %s device",
               ideif,
               res==IDE_OK?"activated":"not activated",
               drv==IDE_MASTER?"master":"slave"
               );      
    }      
  }

  if (found==0) {
    printk(IDELOG "ide: no device found on 0x%x,%i, unregistering interface",
           ide[ideif].io_port,ide[ideif].irq);

    ide_unregister(ideif);

  }
 
  return found;
}
                         
/* --- */

/*++++++++++++++++++++++++++++++++++++++
 
  This function is called by the "logical disk" module to inform this module
  that a logical disk partition is found [see ide_scandisk()].

  int _callback
    must return 0 to continue searching for new partition, -1 to stop
    scanning

  int ind
    partition index (for linux users: it is the number after the device
    name, ex. hda1, hdb5 )

  struct lodskinfo *ptr
    information on partition found

  void *data
    private data for this module: is a pointer to a __dev_t to identify
    the device where this partition reside
  ++++++++++++++++++++++++++++++++++++++*/


static int _callback(int ind, struct lodskinfo *ptr, void *data)
{
  char name[32];
  int index;
  __dev_t dev;
 
  printk2("found logical device %i",ind);
 
  assertk(ind>0);
  if (ind>MAXIDELODSK) {
    printk(IDELOG "ide: found more than %i partitions... skipped!",
           MAXIDELODSK);
    return -1;
  }
 
  index=idemindexext(*(__dev_t *)data,ind);
  mtable[index].start=ptr->start;  
  mtable[index].size=ptr->size;
  mtable[index].used=1;

 
  dev=makedev(major(*(__dev_t *)data),index);
  sprintf(name,"hd%c%i",
          idehwif(dev)*2+idedriveid(dev)+'a',
          ind
          );
 
  index=bdev_register_minor(dev,name,ptr->fs_ind);
 
  return 0;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Scan an IDE device to find its logical structure; it use the service
  from the "logical disk" module to perform this.

  int ide_scandisk
    return 0 on success, other on error

  int hwif
    ide interface where there is the device

  int drv
    device to scan (IDE_MASTER, IDE_SLAVE)

  ++++++++++++++++++++++++++++++++++++++*/


int ide_scandisk(int hwif, int drv)
{
  char name[8];
  __dev_t device;
  int index;

  printk2("START");
   
  //cprintf("hwif=%i drv=%i\n",hwif,drv);
  device=idemakedev(hwif,drv,0);
  //cprintf("device=%i\n",(int)device);
  index=idemindex(device);
  //cprintf("minor=%i\n",(int)minor(device));
  //cprintf("---index=%i\n",index);
 
  mtable[index].start=0;
  mtable[index].size=ide[hwif].pdisk[drv]->pd_size;
  mtable[index].used=1;  
  sprintf(name,"hd%c",hwif*2+drv+'a');

  bdev_register_minor(device,name,FS_DEFAULT);
 
  lodsk_scan(device,
             _callback,
             (void*)&device,
             ide_showinfo_flag,
             name);

  printk2("END");
  return 0;
}