pfschecker.c 7.95 KB
/**************************************************************************
 *                                                                        *
 *               Copyright (C) 1995, Silicon Graphics, Inc.               *
 *                                                                        *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *                                                                        *
 **************************************************************************/

#include "osint.h"
#include "controller.h"

s32 corrupted_init(OSPfs *, __OSInodeCache *);
s32 corrupted(OSPfs *, __OSInodeUnit, __OSInodeCache *);

#define	CHECK_IPAGE(p)		(((p).ipage >= pfs->inode_start_page) && \
				 ((p).inode_t.bank < pfs->banks) && \
				 ((p).inode_t.page >= 0x01) && \
				 ((p).inode_t.page < 0x80))
  
s32
osPfsChecker(OSPfs *pfs)
{
  int j;
  s32 ret;
  __OSInodeUnit next_page;
  __OSInode checked_inode;
  __OSInode tmp_inode;
  __OSDir tmp_dir;
  __OSInodeUnit file_next_node[16];
  
  __OSInodeCache	cache;
  
  int fixed = 0;
  u8 bank, oldbank=254;
#ifdef _PFS_1M_EXTENSION
  u8 startbank;
#endif  
  s32 cc, cl;
  int offset;

  /* check  status */


  ret = __osCheckId(pfs);
  
  if (ret == PFS_ERR_NEW_PACK)
    ret = __osGetId(pfs);
  
  if (ret)
    return(ret);

#ifdef _PFS_1M_EXTENSION
  if (pfs->banks < PFS_ID_BANK_1M) {
    startbank = PFS_ID_BANK_256K;
  } else {
    startbank = PFS_ID_BANK_1M;
  }
#endif
  
  /*
   * loop through all files to make sure that there are no
   * file's start pages have been marked NOT_USED.
   */
  
  if ((ret = corrupted_init(pfs, &cache)) != 0) return(ret);
  
  for (j = 0; j < pfs->dir_size; j++) {
    if ((ret = __osContRamRead(pfs->queue, pfs->channel,
			       (u16)(pfs->dir_table + j),
			       (u8 *)&tmp_dir)) != 0){
      return(ret);
    }
    
    if ((tmp_dir.company_code != 0) || (tmp_dir.game_code != 0)) {
      
      if ((tmp_dir.company_code == 0) || (tmp_dir.game_code == 0)) {
	cc = -1;
      } else {
	/* file exist */
	next_page = tmp_dir.start_page;
      
	/* dir is valid */
	cl = cc = 0;
	bank = 255; 
	
	while(CHECK_IPAGE(next_page)){
	  
	  if (bank != next_page.inode_t.bank){
	    bank = next_page.inode_t.bank;
	    if (oldbank != bank) {
	      ret = __osPfsRWInode(pfs, &tmp_inode, PFS_READ, bank);
	      oldbank = bank;
	    }

	    if ((ret != 0) && (ret != PFS_ERR_INCONSISTENT)){
	      return(ret);
	    }
	  } 	 
	
	  if ((cc = corrupted(pfs, next_page, &cache) - cl) != 0){
	    break;
	  }
	  cl = 1;
	
	  next_page = tmp_inode.inode_page[next_page.inode_t.page];	  
	}
      }

      if ((cc != 0) || (next_page.ipage != PFS_EOF)){
	
	/* corrupted */
	bzero(&tmp_dir, sizeof(__OSDir));
	
#ifdef _PFS_1M_EXTENSION
	if ((ret = __osPfsSelectIdBank(pfs)) != 0) return(ret);
#else
	if (pfs->activebank != 0) {
	  if ((ret = __osPfsSelectBank(pfs, 0)) != 0)
	    return(ret);
	}
#endif
	if ((ret = __osContRamWrite(pfs->queue, pfs->channel,
				    (u16)(pfs->dir_table + j),
				    (u8 *)&tmp_dir, 0)) != 0){
	  return(ret);
	}
	
	/* free inode pages */
	fixed++;
      }
    } 
  }

	/* 
	 * return all pages that are not in any file back to NOT_USED.
	 */
        /* BY YASU */
        
        /* Get inode start page */
        for (j = 0; j < pfs->dir_size; j++) {   
          if ((ret = __osContRamRead(pfs->queue, pfs->channel,
                                     (u16)(pfs->dir_table +j),
                                     (u8 *)&tmp_dir)) != 0)
            return(ret);

          /* Check if file exists */
          if ((tmp_dir.company_code != 0) && (tmp_dir.game_code != 0) &&
              (tmp_dir.start_page.ipage >= (u16)pfs->inode_start_page)) {
            file_next_node[j].ipage = tmp_dir.start_page.ipage;
          } else {
            file_next_node[j].ipage = 0;
          }
        }
        
        /* Check all */
#ifdef _PFS_1M_EXTENSION
	for(bank = startbank; bank < pfs->banks; bank++) {
#else
	for(bank = 0; bank < pfs->banks; bank++) {
#endif	  
	  /* load inode */
	  ret =__osPfsRWInode(pfs, &tmp_inode, PFS_READ, bank);
	  if ((ret != 0) && (ret != PFS_ERR_INCONSISTENT))
	    return(ret);
	  
	  /* setup default inode structure */
#ifdef _PFS_1M_EXTENSION
	  offset = ((bank > PFS_ID_BANK_1M) ? 1 : pfs->inode_start_page);
#else
	  offset = ((bank > PFS_ID_BANK_256K) ? 1 : pfs->inode_start_page);
#endif
	  for (j = 0; j < offset; j ++){
	    checked_inode.inode_page[j].ipage =
	      tmp_inode.inode_page[j].ipage;
	  }
	  for (; j < PFS_INODE_SIZE_PER_PAGE; j++) 
	    checked_inode.inode_page[j].ipage = PFS_PAGE_NOT_USED;
            
	  /* read file info */
	  for (j = 0; j < pfs->dir_size; j++) {
	    while(file_next_node[j].inode_t.bank == bank &&
		  file_next_node[j].ipage >= (u16)pfs->inode_start_page){
	      u8 pp;
	      pp = file_next_node[j].inode_t.page;
	      file_next_node[j] =
		checked_inode.inode_page[pp] = tmp_inode.inode_page[pp];
	    } 
	  }
	  if ((ret = __osPfsRWInode(pfs, &checked_inode, PFS_WRITE, bank))
	      != 0)
	    return(ret);
	}

	if (fixed != 0)
		pfs->status |= PFS_CORRUPTED;
	else
		pfs->status &= ~PFS_CORRUPTED;
	return(0);
}

/* make distribution map*/
s32     corrupted_init(OSPfs *pfs, __OSInodeCache *cache)
{
  int           i, n;
  int           offset;
  u8            bank;
#ifdef _PFS_1M_EXTENSION
  u8		startbank;
#endif
  __OSInodeUnit	tpage;
  __OSInode     tmp_inode;
  s32           ret;
  
#ifdef _PFS_1M_EXTENSION
  if (pfs->banks < PFS_ID_BANK_1M) {
    startbank = PFS_ID_BANK_256K;
  } else {
    startbank = PFS_ID_BANK_1M;
  }
#endif
  
  for (i = 0; i < PFS_INODE_DIST_MAP; i ++){
    cache->map[i] = 0;
  }
  cache->bank = 255;
  
#ifdef _PFS_1M_EXTENSION
  for (bank = startbank; bank < pfs->banks; bank ++){
    offset = ((bank > PFS_ID_BANK_1M) ? 1 : pfs->inode_start_page);
#else
  for (bank = PFS_ID_BANK_256K; bank < pfs->banks; bank ++){
    offset = ((bank > PFS_ID_BANK_256K) ? 1 : pfs->inode_start_page);
#endif
    
    ret = __osPfsRWInode(pfs, &tmp_inode, PFS_READ, bank);
    if ((ret != 0) && (ret != PFS_ERR_INCONSISTENT)) return(ret);
    
    for (i = offset; i < PFS_INODE_SIZE_PER_PAGE; i ++){
      tpage = tmp_inode.inode_page[i];
      if (tpage.ipage >= pfs->inode_start_page){
	if (tpage.inode_t.bank != bank){
	  n = (int)((tpage.inode_t.page & 0x7f)/ PFS_SECTOR_SIZE)
	    + PFS_SECTOR_PER_BANK
	      * (int)(tpage.inode_t.bank % PFS_BANK_LAPPED_BY);
	  cache->map[n] |= (1 << (bank % PFS_BANK_LAPPED_BY));
	}
      }
    }
  }
  return(0);
}

s32
corrupted(OSPfs *pfs, __OSInodeUnit fpage, __OSInodeCache *cache)
{
	int j, n;
	s32 hit = 0;
	u8  bank;
#ifdef _PFS_1M_EXTENSION
	u8  startbank;
#endif
	int offset;
	s32 ret = 0;
	
#ifdef _PFS_1M_EXTENSION
	if (pfs->banks < PFS_ID_BANK_1M) {
	  startbank = PFS_ID_BANK_256K;
	} else {
	  startbank = PFS_ID_BANK_1M;
	}
#endif
  
	n = (int)(fpage.inode_t.page / PFS_SECTOR_SIZE)
	  + PFS_SECTOR_PER_BANK 
	    * (int)(fpage.inode_t.bank % PFS_BANK_LAPPED_BY);

#ifdef _PFS_1M_EXTENSION
	for (bank = startbank; bank < pfs->banks; bank++) {
	    offset = ((bank > PFS_ID_BANK_1M) ? 1 : pfs->inode_start_page);
#else
	for (bank = PFS_ID_BANK_256K; bank < pfs->banks; bank++) {
	    offset = ((bank > PFS_ID_BANK_256K) ? 1 : pfs->inode_start_page);
#endif
	    if ((bank == fpage.inode_t.bank) ||
		(cache->map[n] & (1 << (bank % PFS_BANK_LAPPED_BY))) != 0){
	      if (bank != cache->bank){
		ret = __osPfsRWInode(pfs, &(cache->inode), PFS_READ, bank);
		if ((ret != 0) && (ret != PFS_ERR_INCONSISTENT))
		        return(ret);
		cache->bank = bank;
	      }
	      for (j = offset; ((hit < 2) && (j < PFS_INODE_SIZE_PER_PAGE)); 
		   j++) {
		if (cache->inode.inode_page[j].ipage == fpage.ipage) {
		  hit++;
		}
	      }
	      if (hit >= 2)
		return(2);
	    }
	}
	return(hit);
}