/*
 * nasd_cheops_cl_raid0.c
 *
 * RAID0 access module
 */
/*
 * Copyright (c) 1996,1997,1998,1999 Carnegie Mellon University.
 * All rights reserved.
 *
 * 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_RAID0_DEBUG 0

int
_nasd_cheops_raid0_read(nasd_asm_t *a, nasd_len_t *out_len)
{
  int rc =0, i;
  nasd_uint64 bms=0;
	_nasd_cheops_aggr_io_t *pio; /* parent io */
	_nasd_cheops_io_t *prev_io, *new_io, *xio;
	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: CHEOPS Error: can not initialize mutex\n");
    return rc; 
  }
	rc = nasd_cond_init(&(pio->ios_all_done));
  if (rc) {
    fprintf(stderr, "CHEOPS: CHEOPS Error: can not initialize condition variable\n");
    return rc;
  }
	pio->num_ios = a->num_su_accessed;
	pio->num_done = 0;
	pio->in_datalen = a->datalen;
	pio->first_io = NULL;
	pio->out_datalen = 0;
	pio->status = pio->nasd_status = 0;

#if _NASD_CHEOPS_RAID0_DEBUG > 1
	fprintf(stderr, "CHEOPS: raid0_read: issuing io with %d children\n", pio->num_ios);
	_nasd_cheops_print_asm(a);
#endif
	prev_io= NULL;
	for (sac= a->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);
	      new_io->bms_targ = bms;
	      _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(a); 
	_nasd_cheops_io_freeall(pio); 

	return rc;
}

int
_nasd_cheops_raid0_write(nasd_asm_t *a, 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;
  int n_actual_ios = 0;

#if _NASD_CHEOPS_RAID0_DEBUG > 0
  fprintf(stderr, "CHEOPS: raid0_write called\n");
#endif /* _NASD_CHEOPS_RAID0_DEBUG */

	/* 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 = a->num_su_accessed;
	pio->num_done = 0;
	pio->in_datalen = a->datalen;
	pio->first_io = NULL;
	pio->out_datalen = 0;
	pio->status = pio->nasd_status = 0;

#if _NASD_CHEOPS_RAID0_DEBUG > 0
	fprintf(stderr, "CHEOPS: raid0_write: sending pio with %d children\n", pio->num_ios);
	_nasd_cheops_print_asm(a);
#endif
	prev_io = NULL;
	for (sac = a->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) {
          fprintf(stderr, "CHEOPS: malloc failed ...\n");
          return ENOMEM;
	      } else {
          new_io->cnext = prev_io;	      
	      }
#if 0
	      new_io->type = _NASD_CHEOPS_TSWRITE_IO; 
#else	
	      new_io->type = _NASD_CHEOPS_RAID0_WRITE_IO;
#endif
	      new_io->host_tag = a->host_tag;
	      prev_io = new_io;
	      _nasd_cheops_init_io(&sac->pda_list[i], pio, new_io);
	      _nasd_cheops_enq_io(new_io);
        n_actual_ios++;
	    }
	  }
	}

#if _NASD_CHEOPS_RAID0_DEBUG > 0
  fprintf(stderr, "CHEOPS: raid0_write queued up %d (%d) i/os ...\n",
          n_actual_ios, pio->num_ios);
#endif /* _NASD_CHEOPS_RAID0_DEBUG */

	/* 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);
#if _NASD_CHEOPS_RAID0_DEBUG > 0
    fprintf(stderr, "CHEOPS: raid0_write woke up, num_done=%d num_ios=%d...\n",
     pio->num_done, pio->num_ios);
#endif /* _NASD_CHEOPS_RAID0_DEBUG */
	}
	NASD_UNLOCK_MUTEX(pio->flag_mutex);

#if _NASD_CHEOPS_RAID0_DEBUG > 0
  fprintf(stderr, "CHEOPS: raid0_write all i/os completed\n");
#endif /* _NASD_CHEOPS_RAID0_DEBUG */

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

	/* 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(a); 
	_nasd_cheops_io_freeall(pio); 

#if _NASD_CHEOPS_RAID0_DEBUG > 0
  fprintf(stderr, "CHEOPS: raid0_write returning rc=%d\n", rc);
#endif /* _NASD_CHEOPS_RAID0_DEBUG */

	return rc;
}

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