dodiskwrite.c 4.44 KB

#include <PR/leosp.h>
#include "ddwrite.h"
#include "ddwriteint.h"


/*
 * static functions prototypes
 */
static void 	existGetData(DDCmd *command);
static void 	notExistGetData(DDCmd *command);


/*
 * 実際にディスクに書き込むための関数。
 */
void __ddDoDiskWrite(DDCmd *command)
{

  if ( command->getdata != (s32 (*)(void *, u32))0 )
    existGetData(command);
  else
    notExistGetData(command);

  return;

} /* doDiskWrite() */


/*
 * getdata メンバが指定されていた場合、totalSize を何回かに分けて
 * RDRAM に転送して書き込む
 */
static void existGetData(DDCmd *command)
{
  LEOCmd	cmdBlock;
  LEOError	error = 0;
  u32		nblocks, nbytes;
  __byteInfo_s	byteInfo;
  s32		restbytes;
  s32		trError;
  s32		curLba;
  
  /* あと何バイト残っているか? */
  restbytes = (s32)command->totalSize;
  curLba = (s32)command->startLBA;

  while (restbytes > 0)
  {

    /*
     * まずは、用意されたバッファ内に何バイト、何ブロック分データを格納す
     * ることが可能かを調べる。
     */
    __ddGetnBlksInArea(&byteInfo, (u32)__ddInfo.diskType,
		       curLba, command->writeSize);

    nblocks = (u32)byteInfo.inNlbas;
    nbytes = (u32)byteInfo.inNbytes;

	if ( nbytes == 0 )
	  {
		__ddWriteError = DDWRITE_ERROR_INSUFFICIENT_BUFFERSIZE;
		return;
	  }

    /*
     * 残りのデータを全部格納できるのなら、最後のループになる。(LBA 境界に
     * 満たない部分を 0xff で埋めることに注意。
     */
    if (nbytes > (u32)restbytes)
    {
      /*
       * あと少しである。
       */
      trError = (*command->getdata)(command->writeBuf, (u32)restbytes);
    
      if (trError)
      {
	__ddWriteError = trError;
	return;
      }
    
      __ddGetnBlksInArea(&byteInfo, (u32)__ddInfo.diskType,
			 curLba, (u32)restbytes);
      
      /*
       * nbytes, nblocks の意味は「このループで転送するバイト数、
       * ブロック数」である。
       */ 
      nbytes = byteInfo.outNbytes;
      nblocks = byteInfo.outNlbas;

      /* キリの良くない部分を 0xff で埋める */
      __ddBfill((void *)((u32)command->writeBuf + (u32)restbytes),
		nbytes - (u32)restbytes, 0xffffffff);
  
    }
    else
    {
      /*
       * まだまだありそう。とりあえずバッファに格納できるだけ転送する。
       */
      trError = (*command->getdata)(command->writeBuf, nbytes);
    
      if (trError)
      {
	__ddWriteError = trError;
	return;
      }

    }
  
    /* 書き込み */
    LeoSysReadWrite(&cmdBlock, OS_WRITE, curLba,
		    command->writeBuf, nblocks, &__ddDiskQ);
    osRecvMesg(&__ddDiskQ, (OSMesg)&error, OS_MESG_BLOCK);
  
    if (error)
    {
      __ddWriteError = (s32)error;
      return;
    }

    restbytes -= (s32)nbytes;
    curLba += (s32)nblocks;

  } /* while (restbytes > 0) */

  __ddWriteError = (s32)0;
  return;
  
} /* existGetData() */


/*
 * getdata メンバが指定されていない場合、RDRAM 上にデータが格納
 * されている。
 *
 * 2段階に分けて書き込む。
 * まずはキリのいいブロック境界まで書き込み、そのあとで残りの部分を
 * 書き込む。これは、「残りの部分」の後ろを 0xff で埋めるためである。
 * (実際のデータの後ろに 0xff をつけるわけには行かない(暴走する!?)
 *  ので、残りの部分だけ内部バッファに転送した上で処理する)
 */
static void notExistGetData(DDCmd *command)
{
  LEOCmd	cmdBlock;
  LEOError	error = 0;
  u32		nblocks, nbytes;
  __byteInfo_s	byteInfo;

  /*
   * まずキリのいいブロック境界まで書き込む
   */
  /* キリのいい境界とは何ブロック目、何バイト目か? */
  __ddGetnBlksInArea(&byteInfo, (u32)__ddInfo.diskType,
		     (s32)command->startLBA, command->writeSize);

  nblocks = byteInfo.inNlbas;
  nbytes = byteInfo.inNbytes;

  /* 書き込み */
  LeoSysReadWrite(&cmdBlock, OS_WRITE, (s32)command->startLBA,
		  command->writeBuf, nblocks, &__ddDiskQ);
  osRecvMesg(&__ddDiskQ, (OSMesg)&error, OS_MESG_BLOCK);
  
  if (error)
  {
    __ddWriteError = (s32)error;
    return;
  }
  
  /* 残りがなければ終了 */
  if (byteInfo.restBytes == 0)
  {
      __ddWriteError = (s32)0;
      return;
  }

  /*
   * 残りを書き込む
   */

  /* 内部バッファに転送する */
  bcopy((void *)((u32)command->writeBuf + nbytes),
	__ddBufp1, (int)byteInfo.restBytes );

  /* キリの良くない部分を 0xff で埋める */
  __ddBfill((void *)((u32)__ddBufp1 + byteInfo.restBytes),
	    byteInfo.oneBlockSize - byteInfo.restBytes, 0xffffffff);

  /* 書き込み */
  LeoSysReadWrite(&cmdBlock, OS_WRITE, (s32)(command->startLBA + nblocks),
		  __ddBufp1, 1, &__ddDiskQ);
  osRecvMesg(&__ddDiskQ, (OSMesg)&error, OS_MESG_BLOCK);

  if (error)
  {
    __ddWriteError = (s32)error;
    return;
  }
  
  __ddWriteError = (s32)0;
  return;

} /* notExistGetData() */