/*
 * nasd_cheops_cl_raid5.c
 *
 * RAID5 access module
 *
 * Author: Khalil Amiri, CMU SCS/ECE, July 18 1997
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1996,1997,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 <stdio.h>
#include <malloc.h>
#include <sys/errno.h>
#include <string.h>

#include <nasd/nasd_types.h>
#include <nasd/nasd_cheops_types.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_cheops_types.h>
#include <nasd/nasd_cheops_common.h>
#include <nasd/nasd_cheops_raidmap.h>
#include <nasd/nasd_cheops_ios.h>
#include <nasd/nasd_cheops_client_internal.h>
#include "nasd_cheops_time.h"

#define _NASD_CHEOPS_RAID5_DEBUG 3

int
_nasd_cheops_raid5_read(nasd_asm_t *asm, nasd_len_t *out_len)
{
  int rc =0, i;
  _nasd_cheops_aggr_io_t *pio; /* parent io */
  _nasd_cheops_io_t *prev_io, *new_io;
  NASD_stripe_access_t *sac;

  /* enqueue io items corresponding to each pda in the asm  */
  NASD_Malloc(pio, sizeof(_nasd_cheops_aggr_io_t), (_nasd_cheops_aggr_io_t *));
  if (pio == NULL)
    return ENOMEM;

  rc =  nasd_mutex_init(&(pio->flag_mutex));
  if (rc) {
    fprintf(stderr, "CHEOPS: Error: can not initialize mutex\n");
    return rc; 
  }
  rc = nasd_cond_init(&(pio->ios_all_done));
  if (rc) {
    fprintf(stderr, "CHEOPS: Error: can not initialize condition variable\n");
    return rc;
  }
  pio->num_ios = asm->num_su_accessed;
  pio->num_done = 0;
  pio->in_datalen = asm->datalen;
  pio->first_io = NULL;
  pio->out_datalen = 0;
  pio->status = pio->nasd_status = 0;

#if _NASD_CHEOPS_RAID5_DEBUG > 0
  fprintf(stderr, "CHEOPS: raid5_read: issuing io with %d children\n",
	  pio->num_ios);
  _nasd_cheops_print_asm(asm);
#endif
  prev_io= NULL;
  for (sac= asm->first_stripe_access; sac != NULL; sac = sac->next) {
    if (!sac)
      break;
    for (i=0; i< NASD_CHEOPS_MAX_STRIPE_SIZE; i++) {
      if (sac->pda_list[i].buf != NULL ) {
	NASD_Malloc(new_io, sizeof(_nasd_cheops_io_t), (_nasd_cheops_io_t *));
	bzero((char *)new_io, sizeof(_nasd_cheops_io_t));
	if (new_io == NULL) {
	  return ENOMEM;
	} else {
	  new_io->cnext = prev_io;	      
	}
	new_io->type = _NASD_CHEOPS_READ_IO;
	prev_io = new_io;
	_nasd_cheops_init_io(&sac->pda_list[i], pio, new_io);
	_nasd_cheops_enq_io(new_io);  
      }
    }
  }
	
  /* wait until all ios complete */ 
  NASD_LOCK_MUTEX(pio->flag_mutex);
  while ( pio->num_done < pio->num_ios ) {
    NASD_WAIT_COND(pio->ios_all_done, pio->flag_mutex);
  }
  NASD_UNLOCK_MUTEX(pio->flag_mutex);
	
  pio->first_io= new_io; /* child ios are chained in the reverse order they were enqueued */

  /* warning!: pio can not be touched until 
     all ios complete, cuz otherwise we could into races with the doio threads */

  *out_len = pio->out_datalen;
  if (pio->status)
    rc = pio->status;
  else
    rc = pio->nasd_status;
  /* if everything is ok, free the pdas, and the io items */
  _nasd_cheops_asm_freeall(asm); 
  _nasd_cheops_io_freeall(pio); 

  return 0;
}

int
_nasd_cheops_raid5_write(nasd_asm_t *asm, nasd_len_t *out_len)
{
  int rc =0, i;
  _nasd_cheops_aggr_io_t *pio;                /* parent io */
  _nasd_cheops_io_t      *prev_io, *new_io;
  NASD_stripe_access_t   *sac;

  /* enqueue io items corresponding to each pda in the asm  */
  NASD_Malloc(pio, sizeof(_nasd_cheops_aggr_io_t), (_nasd_cheops_aggr_io_t *));
  if (pio == NULL)
    return ENOMEM;

  rc =  nasd_mutex_init(&(pio->flag_mutex));
  if (rc) {
    fprintf(stderr, "CHEOPS: Error: can not initialize mutex\n");
    return rc; 
  }
  rc = nasd_cond_init(&(pio->ios_all_done));
  if (rc) {
    fprintf(stderr, "CHEOPS: Error: can not initialize condition variable\n");
    return rc;
  }
  pio->num_ios = asm->num_su_accessed;
  pio->num_done = 0;
  pio->in_datalen = asm->datalen;
  pio->first_io = NULL;
  pio->out_datalen = 0;
  pio->status = pio->nasd_status = 0;

#if _NASD_CHEOPS_RAID5_DEBUG > 2
  fprintf(stderr, "CHEOPS: raid5 write: sending pio with %d children\n",
	  pio->num_ios);
  _nasd_cheops_print_asm(asm);
#endif

  prev_io = NULL;
  for (sac= asm->first_stripe_access; sac != NULL; sac = sac->next) {

    for (i=0; i< NASD_CHEOPS_MAX_STRIPE_SIZE; i++) {
      if (sac->pda_list[i].buf != NULL) {
	NASD_Malloc(new_io, sizeof(_nasd_cheops_io_t), (_nasd_cheops_io_t *));
	bzero((char *)new_io, sizeof(_nasd_cheops_io_t));
	if (new_io == NULL) {
	  fprintf(stderr, "CHEOPS: malloc failed ...\n");
	  return ENOMEM;
	} else {
	  new_io->cnext = prev_io;	      
	}
	new_io->type = _NASD_CHEOPS_TSWRITE_IO;
	prev_io = new_io;
	_nasd_cheops_init_io(&sac->pda_list[i], pio, new_io);
	_nasd_cheops_enq_io(new_io);  
      }
    }

  }

  /* wait until all ios complete */
  NASD_LOCK_MUTEX(pio->flag_mutex);
  while ( pio->num_done < pio->num_ios ) {
    NASD_WAIT_COND(pio->ios_all_done, pio->flag_mutex);
  }
  NASD_UNLOCK_MUTEX(pio->flag_mutex);

  pio->first_io= new_io; /* child ios are chained in the reverse order they were enqueued */

  /* warning!: pio can not be touched until 
     all ios complete, cuz otherwise we could into races with the doio threads */

  *out_len = pio->out_datalen;	
  if (pio->status)
    rc = pio->status;
  else
    rc = pio->nasd_status;

  /* if everything is ok, free the pdas, and the io items */
  _nasd_cheops_asm_freeall(asm); 
  _nasd_cheops_io_freeall(pio); 

  return rc;
}

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