#!/bin/ash
#
# $Id: installer-raid-functions,v 1.11 2002/08/27 13:11:32 malekith Exp $
#
# Software and hardware RAID functions for PLD Linux installer.
#
# (c) 2001 Michal Moskal <malekith@pld.org.pl>
#
# This file can be modified and/or redistributed under
# the terms of GPL version 2 (without any options :^).
#

####
# Software RAID
####

# load needed raid modules
# example raid entry:
# dest_part2_device="/dev/md0:raid0,/dev/sda2,/dev/sdb2"
# used in installer-prep
load_soft_raid_modules () {
  if test "$have_md" ; then
    id=1
    while true
    do
      eval "var=\$dest_part${id}_device"
      test "$var" || break
      id=$(($id + 1))
      if echo "$var" | grep -q raid ; then
        lev=`echo $var | sed -e 's/.*raid//' | sed -e 's/\([l0-9]*\).*/\1/'`
        # this will also validate, that we can have just raid0,1,5
        # or raidl == linear, since other modules simply does not exist
  	if [ "$KERNEL_VERCODE" -gt 2 ] ; then
          load_module md
  	fi
        if [ "$lev" = "l" ] ; then
          load_module linear
        elif [ "$lev" = "4" ] ; then
          load_module raid5
        else
          load_module raid$lev
        fi
        d=`echo $var | sed -e 's/:.*//'`
        minor=`echo $d | sed -e 's|/dev/md||'`
        rm -f $d
        mknod $d b 9 $minor
      fi
    done
  fi
}

# used in installer-dest
prep_soft_raid () {
  # we can either use mdctl or raidtools. in either case raidtab
  # is generated and stored on destination partition, it also includes
  # (in comments) commands used to create raids with mdctl.
  mdctl=no
  if test -x /sbin/mdctl || test -x /bin/mdctl ; then
    mdctl=yes
  fi
  
  # extract information about raid devices to be configured
  id=0
  echo -n > /tmp/raidtab
  echo -n > /tmp/create_partitions.tmp
  while :
  do
    id=$(($id+1))
    log debug "Processing RAID dest_part$id"
    eval_partition_info $id
    log debug "dest_part${id}_device=$dest_part_device"
    
    test "$dest_part_device" || break
    
    # check if given partition is to be created on current $dev
    echo "$dest_part_device" | grep -q "^/dev/md" || continue
  
    # now we gotta parse...
    # /dev/md[0-9]+:raid[0145l],(/dev/[shm]d[a-z]?[0-9]+(:spare)?)+,OPTIONS+
    # OPTIONS:
    #  parity_algorithm={left,right}-{,a}symmetric, default=left-symmetric
    #  chunk_size=N, in kB, default: 32, expect raid5, where 128 is the default.
    #  persistent_superblock=0, default 1
    #  just_start=1, default to 0, just do raidstart, no mkraid.
    md_dev=`echo $dest_part_device | sed -e 's|/dev/md\([0-9]*\).*|\1|'`
    raid_lev=`echo $dest_part_device | sed -e 's|/dev/md[0-9]*:raid\([0-9l]\).*|\1|'`
    log debug "it is /dev/md$md_dev, raid-$raid_lev"
    parity_algorithm=left-symmetric
    persistent_superblock=1
    chunk_size=32
    if [ "$raid_lev" = 5 ] ; then
      chunk_size=128
    elif [ "$raid_lev" = l ] ; then
      raid_lev=linear
    fi
    just_start=0
    nr_normal=0
    nr_spare=0
    dev_normal=
    dev_spare=
    for drive in `echo $dest_part_device | \
    		  sed -e 's|/dev/md[0-9]*:raid[0-9l],||' | \
  		  sed -e 's/,/ /g'` ; do
      log debug "processing raid drive: $drive"
      if echo $drive | grep -q /dev ; then
        if echo $drive | grep -q :spare ; then
          dev_spare="$dev_spare `echo $drive | sed -e 's/:spare//'`"
  	nr_spare=$(($nr_spare+1))
        else
          dev_normal="$dev_normal $drive"
  	nr_normal=$(($nr_normal+1))
        fi
      else
        name=`echo $drive | sed -e 's/=.*//'`
        val=`echo $drive | sed -e 's/.*=//'`
        case $name in
          parity_algorithm | chunk_size | just_start | persistent_superblock )
  	    eval $name=$val
  	    ;;
  	  * )
  	    die "bad raidoption: $drive"
        esac
      fi
    done
  
    log debug "writing raidtab normal=$dev_normal, spare=$dev_spare"
    
    mdctl_opt=""
    if [ $nr_spare != 0 ] ; then
      mdctl_opt="$mdctl_opt --spare-disks=$nr_spare"
    fi
    if [ $raid_lev = 5 ] ; then
      mdctl_opt="$mdctl_opt --parity=$(echo ${parity_algorithm} | sed -e 's/-/_/')"
    fi
  
    # we have to split MDCTL*: stuff since raidtools are braindamaged
    # and cannot handle comments longer then 100 characters
    cat >> /tmp/raidtab <<EOF
# created from dest_part${id}:
# MDCTL$md_dev: mdctl --create /dev/md${md_dev} --chunk=${chunk_size} 
# MDCTL$md_dev:   --level=${raid_lev} --raid-disks=${nr_normal}
# MDCTL$md_dev:  $mdctl_opt 
# MDCTL$md_dev:   --run
EOF
    for f in $dev_normal $dev_spare ; do
      echo "# MDCTL$md_dev:         $f" >> /tmp/raidtab
    done

  cat >> /tmp/raidtab <<EOF
raiddev /dev/md${md_dev}
	raid-level		${raid_lev}
	persistent-superblock	${persistent_superblock}
	chunk-size		${chunk_size}
	nr-raid-disks		${nr_normal}
EOF
  
    if [ $nr_spare != 0 ] ; then
      echo "	nr-spare-disks		${nr_spare}" >> /tmp/raidtab
    fi
    if [ $raid_lev = 5 ] ; then
      echo "	parity-algorithm	${parity_algorithm}" >> /tmp/raidtab
    fi
    
    nr=0
    for drive in $dev_normal ; do
      echo "	device			$drive"	>> /tmp/raidtab
      echo "	raid-disk		$nr" >> /tmp/raidtab
      nr=$(($nr+1))
    done
    
    nr=0
    for drive in $dev_spare ; do
      echo "	device			$drive"	>> /tmp/raidtab
      echo "	spare-disk		$nr" >> /tmp/raidtab
      nr=$(($nr+1))
    done
    
    echo "# end of dest_part${id}" >> /tmp/raidtab
    echo "" >> /tmp/raidtab
  
    if [ "$dest_part_filesystem" = "ext2" ] ; then
      if echo $dest_part_format_options | grep -q stride ; then
        : already there...
      else
        if echo $dest_part_format_options | grep -q '.*-b *[0-9][0-9]*' ; then
          block_size=`echo $dest_part_format_options | sed -e 's/.*-b *\([0-9][0-9]*\).*/\1/'`
        else
          # it's not quite this way...
          block_size=4096
        fi
        
        dest_part_format_options="$dest_part_format_options -R stride=$(($chunk_size*1024/$block_size))"
      fi
    fi
    
    if [ "X$just_start" = X1 ] ; then
      part_type=raid-raidstart
    else
      part_type=raid-mkraid
    fi
   
    echo \
	    "${md_dev:?}" \
	    "no_size" \
	    "$part_type" \
	    "${dest_part_filesystem:?}" \
	    "${dest_part_format_partition:?}" \
            "${dest_part_mnt_point:?}" \
  	    "${dest_part_options:-defaults}" \
  	    "${dest_part_format_options}" \
  		      >>/tmp/create_partitions.tmp
  done
  
  sort -n /tmp/create_partitions.tmp | sed -e 's|^|/dev/md |' >> /tmp/create_partitions
  rm -f /tmp/create_partitions.tmp
}

# used in installer-dest
start_soft_raid () {
  grep "^/dev/md " /tmp/create_partitions | \
  while read device minor size part_type rest; do
    case $part_type in
      raid-raidstart )
        log info "$(nls "Starting RAID device /dev/md%s" $minor)"
        if test "x$dry_run" = "xno"; then
  	  if [ $mdctl = yes ] ; then
            log_wrap mdctl --run /dev/md$minor
  	  else
            log_wrap raidstart --configfile /tmp/raidtab /dev/md$minor
  	  fi
        fi
        ;;
      raid-mkraid )
        log info "$(nls "Creating RAID device /dev/md%s" $minor)"
        if test "x$dry_run" = "xno"; then
  	  if [ $mdctl = yes ] ; then
            log_wrap $(echo $(grep MDCTL$minor: /tmp/raidtab | \
  	  	sed -e "s/. MDCTL$minor://"))
  	  else
            log_wrap mkraid --force --configfile /tmp/raidtab /dev/md$minor
  	  fi
        fi
        ;;
      * )
        die "bad raid part-type ($part_type)"
        ;;
    esac
  done
}

####
# Hardware RAID
####

# used in installer-prep

mk_hdraid_devices () {
  local dev c d p major_off major max_disks max_parts
  
  dev=$1
  major_off=$2
  max_disks=$3
  max_parts=$((256/$max_disks))

  if [ "$KERNEL_VERCODE" -gt 2 ] ; then
    return 0 # devfs
  fi
  
  log info "Making devices in $dev"
  rm -rf $dev
  mkdir -p $dev
  for c in 0 1 2 ; do
    major=$(($c+$major_off))
    d=0
    while [ $d -lt $max_disks ] ; do
      if echo " $dest_devices " | grep -q " $dev/c${c}d${d} " ; then
        :
      else
        d=$(($d+1))
        continue
      fi
      mknod $dev/c${c}d${d} b $major $(($d*$max_parts))
      p=0
      while [ $p -lt $max_parts ] ; do
        mknod $dev/c${c}d${d}p${p} b $major $(($d*$max_parts+$p))
	p=$(($p+1))
      done
      d=$(($d+1))
      echo -n .
    done
  done
}

setup_DAC960 () {
  load_package hdraid-mod DAC960.o
  load_module DAC960

  mk_hdraid_devices /dev/rd 48 32
}

setup_cpqarray () {
  load_package hdraid-mod cpqarray.o
  load_module cpqarray

  mk_hdraid_devices /dev/ida 72 16
}

setup_cciss () {
  load_package hdraid-mod cciss.o
  load_module cciss

  mk_hdraid_devices /dev/cciss 104 16
}

setup_ataraid () {
  load_ide_modules
  load_package hdraid-mod ataraid.o hptraid.o pdcraid.o
  load_module ataraid
  if lsmod | grep -q "^hptraid " ; then
    :
  elif lsmod | grep -q "^pdcraid " ; then
    :
  else
    insmod /hptraid.o || insmod /pdcraid.o
  fi
  # devfs doesn't create /dev/ataraid/dXpY devices...
  for d in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
    mknod /dev/ataraid/d${d} b 114 $(($d * 16)) || :
    for p in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
      mknod /dev/ataraid/d${d}p${p} b 114 $(($d * 16 + $p)) || :
    done
  done
}

make_i2o_devices () {
  local dev l cnt major minor dev
  
  dev=/dev/i2o
  major=80

  if [ "$KERNEL_VERCODE" -gt 2 ] ; then
    # hmm.. I hope so
    return 0 # devfs
  fi
  
  log info "Making devices in $dev"
  rm -rf $dev
  mkdir -p $dev
  mknod /dev/i2o/ctl c 10 166
  
  minor=0
  
  for l in a b c d e f g h i j k l m n o p ; do
    if echo " $dest_devices " | grep -q " $dev/hd$l " ; then
      :
    else
      minor=$(($minor+16))
    fi
    mknod $dev/hd$l b $major $minor
    minor=$(($minor+1))
    cnt=1
    while [ $cnt -lt 16 ] ; do
      mknod $dev/hd$l$cnt b $major $minor
      cnt=$(($cnt+1))
      minor=$(($minor+1))
    done
  done
}

setup_i2o () {
  load_package scsi-mod scsi_mod.o
  load_package i2o-mod
  load_module scsi_mod
  load_module i2o_pci
  load_module i2o_core
  #load_module i2o_scsi
  load_module i2o_block # needed???
  load_module i2o_proc

  make_i2o_devices
}

# vim:ft=sh
