/*
 * nasd_check.c
 *
 * Fault, sanity checking for NASD drive.
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>
#include <nasd/nasd_drive_options.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_freelist.h>
#include <nasd/nasd_itypes.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_cache.h>
#include <nasd/nasd_common.h>
#include <nasd/nasd_timer.h>
#include <nasd/nasd_security_dr.h>
#include <nasd/nasd_layout.h>

/*
 * Note that this does not take partition locks. To be protected
 * against modification, the caller should hold a partition lock.
 */
nasd_status_t
nasd_od_check_startup()
{
  nasd_status_t rc, check_rc;

  check_rc = NASD_SUCCESS;

  rc = nasd_od_check_npt();
  if (rc) {
    nasd_printf("DRIVE-CHECK: failed checking NPT error 0x%x (%s)\n",
      rc, nasd_error_string(rc));
    check_rc = NASD_FAIL;
  }

  if (check_rc == NASD_SUCCESS) {
    nasd_printf("DRIVE-CHECK: all sanity checks passed\n");
  }

  return(check_rc);
}

/*
 * Note that this does not take partition locks. To be protected
 * against modification, the caller should hold a partition lock.
 */
nasd_status_t
nasd_od_check_npt()
{
  nasd_blkcnt_t npt_sz, npt2_sz;
  nasd_odc_ent_t *npte, *npte2;
  nasd_status_t rc, check_rc;
  nasd_blkno_t nbb, nb, nb2;
  int npti;

  check_rc = NASD_SUCCESS;

  npt_sz = nasd_odc_state->disk->npt_ext.last
    - nasd_odc_state->disk->npt_ext.first + 1;
  npt2_sz = nasd_odc_state->disk->npt2_ext.last
    - nasd_odc_state->disk->npt2_ext.first + 1;

  if ((npt_sz != npt2_sz) || (npt_sz != nasd_odc_state->npt_sz)) {
    nasd_printf("DRIVE-CHECK: failed NPT size checks\n");
    nasd_printf("DRIVE-CHECK: npt  = %u..%u size %u\n",
      nasd_odc_state->disk->npt_ext.first, nasd_odc_state->disk->npt_ext.last,
      npt_sz);
    nasd_printf("DRIVE-CHECK: npt2 = %u..%u size %u\n",
      nasd_odc_state->disk->npt2_ext.first, nasd_odc_state->disk->npt2_ext.last,
      npt2_sz);
    nasd_printf("DRIVE-CHECK: npt_sz = %u\n", npt_sz);
    check_rc = NASD_FAIL;
  }

  for(nbb=0;nbb<nasd_odc_state->npt_sz;nbb++) {
    nb = nasd_odc_state->disk->npt_ext.first + nbb;
    nb2 = nasd_odc_state->disk->npt2_ext.first + nbb;

    rc = nasd_odc_block_get(NULL, nb,
      NASD_ODC_L_FORCE|NASD_ODC_L_BLOCK|NASD_ODC_L_LOAD,
      &npte, NASD_ID_NULL, 0, NASD_ODC_T_NPT1, NULL);
    if (rc) {
      nasd_printf("DRIVE-CHECK: nbb=%u nb=%u could not get npte\n",
        nbb, nb);
      check_rc = NASD_FAIL;
      continue;
    }

    rc = nasd_odc_block_get(NULL, nb2,
      NASD_ODC_L_FORCE|NASD_ODC_L_BLOCK|NASD_ODC_L_LOAD,
      &npte2, NASD_ID_NULL, 0, NASD_ODC_T_NPT2, NULL);
    if (rc) {
      nasd_printf("DRIVE-CHECK: nbb=%u nb2=%u could not get npte2\n",
        nbb, nb);
      nasd_odc_block_release(npte);
      check_rc = NASD_FAIL;
      continue;
    }

    NASD_ODC_RLOCK_BLOCK_DATA(npte);
    NASD_ODC_RLOCK_BLOCK_DATA(npte2);

    NASD_ODC_LOCK_BLOCK(npte);
    nasd_odc_wait_not_busy_invalid(npte);
    NASD_ODC_UNLOCK_BLOCK(npte);

    NASD_ODC_LOCK_BLOCK(npte2);
    nasd_odc_wait_not_busy_invalid(npte2);
    NASD_ODC_UNLOCK_BLOCK(npte2);

    for(npti=0;npti<NASD_OD_NODES_PER_NPT_BLOCK;npti++) {
      if (npte->data.pte[npti].blkno != npte2->data.pte[npti].blkno) {
        nasd_printf("DRIVE-CHECK: NPT blocks do not match\n");
        nasd_printf("DRIVE-CHECK: npti=%d nb=%u nb2=%u nbb=%u\n",
          npti, nb, nb2, nbb);
        nasd_printf("DRIVE-CHECK: npte->data.pte[npti].blkno = %u\n",
          npte->data.pte[npti].blkno);
        nasd_printf("DRIVE-CHECK: npte2->data.pte[npti].blkno = %u\n",
          npte2->data.pte[npti].blkno);
        check_rc = NASD_FAIL;
      }
    }

    NASD_ODC_RUNLOCK_BLOCK_DATA(npte2);
    NASD_ODC_RUNLOCK_BLOCK_DATA(npte);

    nasd_odc_block_release(npte);
    nasd_odc_block_release(npte2);
  }

  return(check_rc);
}

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
