Subversion Repositories shark

Rev

Rev 3 | Go to most recent revision | 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: bdev.c,v 1.2 2004-05-26 11:20:23 giacomo Exp $
 
  Revision:    $Revision: 1.2 $

  Last update: $Date: 2004-05-26 11:20:23 $

  This module contains the block device manager: it export some functions
  to the rest of the kernel that are mapped to a real device driver
  sub-system.

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


/*
 * Copyright (C) 1999 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/bdevconf.h>
#include <fs/bdev.h>
#include <fs/magic.h>
#include <fs/assert.h>
#include <fs/sysmacro.h>
#include <fs/bdevinit.h>
#include <fs/fsind.h>
//#include <fs/mutex.h>

#include "bdev.h"

/*+ Log Level to use +*/
#define BDEVLOG KERN_ERR

/*+ an entry for every block device +*/
static struct block_device bdev[MAXBLOCKDEVICE];

/*+ an index into bdev_minor +*/
int bdev_minor_index=0;

/*+ an entry for every block device minor number +*/
struct block_device_minor bdev_minor[MAXBLOCKDEVICEMINOR];

/*+ some operations must be done in mutual exclusion +*/
NOP_mutexattr_t        bdevdef_mutexattr=NOP_MUTEXATTR_INITIALIZER;
__b_mutex_t            mutex;
void                   *bmutexattr=NULL;
static BDEV_PARMS      defaultparms=BASE_BDEV;

/*++++++++++++++++++++++++++++++++++++++
 
  Initialize the block device manager and then initialize every
  block-device sub-system defined into bdevconf.h (Actualy it is
  impossible to load a module at run-time).

  int bdev_init
    return 0 on success, other value on error

  BDEV_PARMS *parms
    pointer to a structure that contains all device inizialization parameter
  ++++++++++++++++++++++++++++++++++++++*/


int bdev_init(BDEV_PARMS *parms)
{
  int i;

  if (parms==NULL) parms=&defaultparms;
 
  /* 'bmutexattr' initialization */
  bmutexattr=parms->bmutexattr;
  if (bmutexattr==NULL) bmutexattr=&bdevdef_mutexattr;
 
  /* initialize mutex */
  __b_mutex_init(&mutex);
 
  /* initialize the bdev[] table */
  for (i=0;i<MAXBLOCKDEVICE;i++) {    
    magic_set(bdev[i].magic,BLOCK_DEVICE_MAGIC);    
    bdev[i].bd_flag_used=0;
  }

  /* initialize the bdev_minor[] table */
  /*for (i=0;i<MAX*/
         
#ifdef IDE_BLOCK_DEVICE
  /* if requested initialize the IDE subsystem */
  ide_init(parms);
#endif

#ifdef LOOP_BLOCK_DEVICE
  /* if requested initialize the "loop device" subsystem */
  loop_init(parms);
#endif

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Every block device sub-system must call this function yo register
  itself to the device block manager.

  int bdev_register
    return 0 on success, -1 on failure

  __dev_t devmajor
    major block device number to register

  char *name
    the name of the device (must be a pointer to static data)

  struct block_device *dev
    information to hook the block device routine
  ++++++++++++++++++++++++++++++++++++++*/


int bdev_register(__dev_t devmajor, char *name, struct block_device *dev)
{
  __dev_t mj=major(devmajor);

  /* check for consistency */
  if (mj<=0||mj>=MAXBLOCKDEVICE) {
    printk(BDEVLOG "bdev: request to register invalid major %i",
           mj);
    return -1;
  }
  if (bdev[mj].bd_flag_used) {
    printk(BDEVLOG "bdev: requet to register used major %i",
           mj);
    return -1;
  }
  magic_assert(bdev[mj].magic,BLOCK_DEVICE_MAGIC,
               "bdev: device(%i,%i) overwritten prior to use",
               mj,minor(devmajor));

  /* register the device */
  memcpy(bdev+mj,dev,sizeof(struct block_device));
  bdev[mj].bd_flag_used=1;
  bdev[mj].bd_name=name;
  magic_set(bdev[mj].magic,BLOCK_DEVICE_MAGIC);
 
  return 0;
}

static __uint8_t part2sysind(__uint8_t par_ind)
{
  switch(par_ind) {
    case FSPAR_DOS12:
    case FSPAR_DOS16:
    case FSPAR_DOSBIG:
      return FS_MSDOS;
    case FSPAR_LNXNTV:
      return FS_EXT2;
  }
  return FS_DEFAULT;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Every block device sub-system must call this function to register
  itself to the device block manager (these information are used by
  the devfs filesystem to export device name to the system in a
  POSIX fanshion).

  int bdev_register_minor
    return a minor index on success, <0 on failure

  __dev_t device
    block device to register

  char *name
    the name of the device

  __uint8_t fsind
    file system indicator (see fsind.h)
  ++++++++++++++++++++++++++++++++++++++*/


int bdev_register_minor(__dev_t device, char *name,__uint8_t fsind)
{
  /* checks for bad requests */
  if (bdev_minor_index==MAXBLOCKDEVICEMINOR) return -1;
  if (major(device)>MAXBLOCKDEVICE) return -2;
  if (!bdev[major(device)].bd_flag_used) return -3;

  /* register minor device */
  strncpy(bdev_minor[bdev_minor_index].bdm_name,name,MAXDEVICENAME);
  bdev_minor[bdev_minor_index].bdm_name[MAXDEVICENAME-1]='\0';
  bdev_minor[bdev_minor_index].bdm_device=device;
  bdev_minor[bdev_minor_index].bdm_fsind=part2sysind(fsind);
   
  return bdev_minor_index++;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Find a device using its name.
 
  __dev_t bdev_find_byname
    return a device number on success, <0 on failure

  char *name
    the name of the device to find
  ++++++++++++++++++++++++++++++++++++++*/


__dev_t bdev_find_byname(char *name)
{
  char *s0,*s1,*s2;
  char saved;
  int i;

  /*
   * a name can be, for example, "/dev/ide/hda1";
   * after this code s0 is a pointer to "ide" (the major name) and s1 is
   * a pointer to "hda1" (the minor name)
   */

  s0=name;  
  s1=strchr(name,'/');
  if (s1==NULL) return -1;
  while ((s2=strchr(s1+1,'/'))!=NULL) {
    s0=s1+1;
    s1=s2;
  }
  saved=*s1;
  *s1++='\0';

  /* search for a device... */
  for (i=0;i<bdev_minor_index;i++)
    /* compare a minor name */
    if (!strcmp(s1,bdev_minor[i].bdm_name))
      /* compare a major name */
      if (!strcmp(bdev[major(bdev_minor[i].bdm_device)].bd_name,s0)) {
        *(s1-1)=saved;
        return bdev_minor[i].bdm_device;
      }
  *(s1-1)=saved;
  return -2;
}


/*++++++++++++++++++++++++++++++++++++++
 
  Find major and minor name using a device id (__dev_t).
 
  int bdev_findname
    return 0 on success; -1 on failure.
   
  __dev_t dev
    device identification

  char **major
    the major name is pointed here
   
  char **minor
    the minor name is pointed here
  ++++++++++++++++++++++++++++++++++++++*/


int bdev_findname(__dev_t dev, char **major,char **minor)
{
  int i;
 
  assertk(major!=NULL&&minor!=NULL);
 
  for (i=0;i<bdev_minor_index;i++)
    if (bdev_minor[i].bdm_device==dev) {
      *minor=bdev_minor[i].bdm_name;
      *major=bdev[major(dev)].bd_name;
      return 0;
    }

  return -1;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Find a device using its file system indicator (the first device
  that use this file system).
 
  __dev_t bdev_find_byfs
    return a device number on success, <0 on failure

  __uint8_t fsind
    file system indicator
  ++++++++++++++++++++++++++++++++++++++*/


__dev_t bdev_find_byfs(__uint8_t fsind)
{
  int i;
  for (i=0;i<bdev_minor_index;i++)
    if (bdev_minor[i].bdm_fsind==fsind)
      return bdev_minor[i].bdm_device;         
  return -1;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Scan all devices into the system: for every device found call
  the callback function, if it returns -1 continue scanning else
  the values passed is returned.
 
  __dev_t bdev_find_byfs
    return a device number on success, <0 on failure

  __uint8_t fsind
    file system indicator
  ++++++++++++++++++++++++++++++++++++++*/


int bdev_scan_devices(int(*callback)(__dev_t,__uint8_t))
{
  int res=0;
  int i;
 
  for (i=0;i<bdev_minor_index;i++) {
    res=callback(bdev_minor[i].bdm_device,
                 bdev_minor[i].bdm_fsind
                 );
    if (res!=-1) break;
  }
  return res;
}

//#ifndef NDEBUG

#include <fs/major.h>
extern int ide_dump_startsize(__dev_t, __blkcnt_t*, __blkcnt_t*);
extern void ide_dump_status(void);

void bdev_dump_names(void)
{
  int i;
  __blkcnt_t start,size;
 
  printk(KERN_INFO "block device names:");
  for (i=0;i<bdev_minor_index;i++) {
    start=size=0;
    if (major(bdev_minor[i].bdm_device)==MAJOR_B_IDE)
      ide_dump_startsize(bdev_minor[i].bdm_device,&start,&size);
    printk(KERN_INFO "    %s/%8s   %08x (start-%-8li size-%-8li sysind-%02x)",
           bdev[major(bdev_minor[i].bdm_device)].bd_name,
           bdev_minor[i].bdm_name,
           bdev_minor[i].bdm_device,
           (long int)start,(long int)size,
           bdev_minor[i].bdm_fsind         
           );
  }
 
}

void bdev_dump_status(void)
{
  int counter,i;
 
  printk(KERN_INFO "block device status:");
  printk(KERN_INFO "  registered devices:");
  for (counter=0,i=0;i<MAXBLOCKDEVICE;i++)
    if (bdev[i].bd_flag_used) {
      printk(KERN_INFO "    %s",bdev[i].bd_name);
      counter++;
    }  
  printk(KERN_INFO "  num. majors: %i",counter);
  printk(KERN_INFO "  num. minors: %i",bdev_minor_index);

#ifdef IDE_BLOCK_DEVICE
  ide_dump_status();
#endif
 
}

//#endif

/*++++++++++++++++++++++++++++++++++++++
 
  Try to lock a device.
  Locking a device means that the locking entity can do I/O on that
  device (no check is performed during I/O operations).
 
  int bdev_trylock
    return 1 on success, 0 on failure and, -1 on error
   
  __dev_t dev
    device to lock
  ++++++++++++++++++++++++++++++++++++++*/


int bdev_trylock(__dev_t dev)
{
  int res;

  magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC,
               "bdev: device(%04x:%04x) overwritten",
               major(dev),minor(dev));

  if (!bdev[major(dev)].bd_flag_used) {
    printk(BDEVLOG "bdev: device(%04x:%04x) not registered",
           major(dev),minor(dev));       
    return -1;
  }
 
  __b_mutex_lock(&mutex);
  res=bdev[major(dev)].bd_op->_trylock(dev);
  __b_mutex_unlock(&mutex);
                                   
  return res;
}

/*++++++++++++++++++++++++++++++++++++++
 
  Try to unlock a device.
 
  int bdev_tryunlock
    return 1 on success, 0 on failure and, -1 on error
 
  __dev_t dev
    device to unlock
  ++++++++++++++++++++++++++++++++++++++*/


int bdev_tryunlock(__dev_t dev)
{
  int res;

  magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC,
               "bdev: device(%04x:%04x) overwritten",
               major(dev),minor(dev));

  if (!bdev[major(dev)].bd_flag_used) {
    printk(BDEVLOG "bdev: device(%04x:%04x) not registered",
           major(dev),minor(dev));       
    return -1;
  }
 
  __b_mutex_lock(&mutex);
  res=bdev[major(dev)].bd_op->_tryunlock(dev);
  __b_mutex_unlock(&mutex);
                                   
  return res;
}

             
/*++++++++++++++++++++++++++++++++++++++
 
  The following function are used to "virtualize" the call of a function
  of a block device sub-system.
  Actually they are implemeted by function to perform some parameters
  check but they will be implemented by macro.
  +latex+ \\

  This function request to read a block number.

  int bdev_read
    return 0 on success, other value on error

  __dev_t dev
    device where to read from

  __blkcnt_t blocknum
    block number to read

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


int bdev_read(__dev_t dev, __blkcnt_t blocknum, __uint8_t *buffer)
{

  magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC,
               "bdev: device(%04x:%04x) overwritten",
               major(dev),minor(dev));

  if (!bdev[major(dev)].bd_flag_used) {
    printk(BDEVLOG "bdev: device(%04x:%04x) not registered",
           major(dev),minor(dev));       
    return -1;
  }
   
  if (blocknum<0) {
    printk(BDEVLOG "bdev: device(%04x:%04x) read request out of range",
           major(dev),minor(dev));       
    return -1;
  }

  return bdev[major(dev)].bd_op->read(dev,blocknum,buffer);
}

/*++++++++++++++++++++++++++++++++++++++
 
  This function request to move the head to a specified block of a device.

  int bdev_seek
    return 0 on success, other value on error

  __dev_t dev
    device to seek

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


int bdev_seek(__dev_t dev, __blkcnt_t blocknum)
{
  magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC,
               "bdev: device(%04x:%04x) overwritten",
               major(dev),minor(dev));

  if (!bdev[major(dev)].bd_flag_used) {
    printk(BDEVLOG "bdev: device(%04x:%04x) not registered",
           major(dev),minor(dev));       
    return -1;
  }
   
  if (blocknum<0) {
    printk(BDEVLOG "bdev: device(%04x:%04x) seek request out of range",
           major(dev),minor(dev));       
    return -1;
  }
   
  return bdev[major(dev)].bd_op->seek(dev,blocknum);
}

/*++++++++++++++++++++++++++++++++++++++
 
  Write a block into a device.

  int bdev_write
    return 0 on success, other value on error

  __dev_t dev
    device to write into

  __blkcnt_t blocknum
    block number to write

  __uint8_t *buffer
    buffer with data to write
  ++++++++++++++++++++++++++++++++++++++*/


int bdev_write(__dev_t dev, __blkcnt_t blocknum, __uint8_t *buffer)
{
  magic_assert(bdev[major(dev)].magic,BLOCK_DEVICE_MAGIC,              
               "bdev: device(%04x:%04x) overwritten",
               major(dev),minor(dev));

  if (!bdev[major(dev)].bd_flag_used) {
    printk(BDEVLOG "bdev: device(%04x:%04x) not registered",
           major(dev),minor(dev));       
    return -1;
  }

  if (blocknum<0) {
    printk(BDEVLOG "bdev: device(%04x:%04x) write request out of range",
           major(dev),minor(dev));       
    return -1;
  }

  return bdev[major(dev)].bd_op->write(dev,blocknum,buffer);
}