/*
 * nasd_cheops_raidmap.h
 *
 * RAID generic mapping data structures
 *
 * Author: Khalil Amiri, CMU SCS/ECE, July 20 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.
 */


#ifndef _NASD_CHEOPS_RAIDMAP_H_
#define _NASD_CHEOPS_RAIDMAP_H_

#include <stdio.h>
#include <malloc.h>

#include <nasd/nasd_types.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_cheops_types.h>
#include <nasd/nasd_cheops_common.h>

/* TODO  ---anonymize rest of data structures nasd_asm, etc,... */

/*
 * Data structures for raid access mapping *
 */

/* physical access descriptor to a single object */
typedef struct NASD_pda_s {
  nasd_edrfs_identifier_t       data_obj_id;         /* data object: disk id, object id */
  nasd_edrfs_identifier_t       parity_obj_id;       /* parity object: disk id, object id */
  int                 col_id;                      /* logical drive column id this pda belongs to */
  int                 lblock;
  nasd_offset_t       start_address;       
  nasd_len_t          len;                 
  nasd_byte_t         *buf;                 /* buffer for the (whole) parent access */
  nasd_offset_t       databuf_offset;              /* offset into the data buffer */
  int                 pcol_id;
} NASD_pda_t;

typedef struct NASD_stripe_access_s {
  NASD_pda_t                  pda_list[NASD_CHEOPS_MAX_STRIPE_SIZE]; 
  nasd_boolean_t              isfull;
  /*  nasd_stripe_vector_t        oldv;
  nasd_stripe_vector_t        newv;  */
  struct NASD_stripe_access_s *next;
} NASD_stripe_access_t;

/* nasd access stripe map */
typedef struct nasd_asm_s {
  NASD_stripe_access_t *first_stripe_access; /* list of stripe access descriptors, one per stripe */  
  nasd_host_tag_t host_tag;
  int num_su_accessed;
  nasd_len_t datalen;
  nasd_byte_t     *buf;
} nasd_asm_t;

/* generic description of a layout */
typedef struct NASD_layout_s {
  int              numCol;                                /* stripe width */
  int              stripeUnitSize;        
  int              dataStripeSize;        
  int              numDataCol;
  nasd_edrfs_identifier_t    identifier_list[NASD_CHEOPS_MAX_STRIPE_SIZE];  /* list of physical NASD objects */
  nasd_cheops_raid_level_t        layoutType;                             /* raid level */
  struct NASD_layout_switch_s     *map;                                /* mapping and access methods */
} NASD_layout_t;

/* class definition for striping layout descriptors                */
/* class contains layout name, layout type and mapping methods     */
typedef struct NASD_layout_switch_s {
  nasd_cheops_raid_level_t    layoutType; 
  char                 *config_name;
  void                 (*MapDataAccess)(NASD_layout_t *, nasd_offset_t , int *, nasd_offset_t *);
  void                 (*MapParityAccess)(NASD_layout_t *, nasd_offset_t, int *, nasd_offset_t *);
  void                 (*IdentifyStripe)(NASD_layout_t *, nasd_offset_t, nasd_disk_ident_t **, int *);
  int                  (*Read)(nasd_asm_t *, nasd_len_t *);
  int                  (*Write)(nasd_asm_t *, nasd_len_t *);
} NASD_layout_switch_t;

NASD_layout_switch_t *
_nasd_cheops_get_layout(nasd_cheops_raid_level_t layoutType);

/*
 * mapping prototype definitions *
 */
void
_nasd_cheops_noraid_MapDataAccess(NASD_layout_t    *LayoutPtr, 
		       nasd_offset_t      logical_addr,
		       int      *col,
		       nasd_offset_t      *offset);
void
_nasd_cheops_noraid_MapParityAccess(NASD_layout_t    *LayoutPtr, 
			 nasd_offset_t      logical_addr,
			 int      *col,
			 nasd_offset_t      *offset);
void
_nasd_cheops_noraid_IdentifyStripe(NASD_layout_t *LayoutPtr, 
			nasd_offset_t  offset,
			nasd_disk_ident_t **diskids, 
			int *outRow);

int
_nasd_cheops_noraid_read(nasd_asm_t *asm, nasd_len_t *out_len);

int
_nasd_cheops_noraid_write(nasd_asm_t *asm, nasd_len_t *out_len);

void
_nasd_cheops_raid0_MapDataAccess(NASD_layout_t    *LayoutPtr, 
		       nasd_offset_t      logical_addr,
		       int      *col,
		       nasd_offset_t      *offset);
void
_nasd_cheops_raid0_MapParityAccess(NASD_layout_t    *LayoutPtr, 
			 nasd_offset_t      logical_addr,
			 int      *col,
			 nasd_offset_t      *offset);
void
_nasd_cheops_raid0_IdentifyStripe(NASD_layout_t *LayoutPtr, 
			nasd_offset_t  offset,
			nasd_disk_ident_t **diskids, 
			int *outRow);

int
_nasd_cheops_raid0_read(nasd_asm_t *asm, nasd_len_t *out_len);

int
_nasd_cheops_raid0_write(nasd_asm_t *asm, nasd_len_t *out_len);

void
_nasd_cheops_raid1_MapDataAccess(NASD_layout_t    *LayoutPtr, 
		       nasd_offset_t      logical_addr,
		       int      *col,
		       nasd_offset_t      *offset);

void
_nasd_cheops_raid1_MapParityAccess(NASD_layout_t    *LayoutPtr, 
			 nasd_offset_t      logical_addr,
			 int      *col,
			 nasd_offset_t      *offset);
void
_nasd_cheops_raid1_IdentifyStripe(NASD_layout_t *LayoutPtr, 
			nasd_offset_t  offset,
			nasd_disk_ident_t **diskids, 
			int *outRow);

int 
_nasd_cheops_raid1_read(nasd_asm_t *asm, nasd_len_t *out_len);


int
_nasd_cheops_raid1_write(nasd_asm_t *asm, nasd_len_t *out_len);

void
_nasd_cheops_raid5_MapDataAccess(NASD_layout_t    *LayoutPtr, 
		       nasd_offset_t      logical_addr,
		       int      *col,
		       nasd_offset_t      *offset);

void
_nasd_cheops_raid5_MapParityAccess(NASD_layout_t    *LayoutPtr, 
			 nasd_offset_t      logical_addr,
			 int      *col,
			 nasd_offset_t      *offset);
void
_nasd_cheops_raid5_IdentifyStripe(NASD_layout_t *LayoutPtr, 
			nasd_offset_t  offset,
			nasd_disk_ident_t **diskids, 
			int *outRow);

int 
_nasd_cheops_raid5_read(nasd_asm_t *asm, nasd_len_t *out_len);

int
_nasd_cheops_raid5_write(nasd_asm_t *asm, nasd_len_t *out_len);

/* various routines mapping addresses in the logical address space. */
/* These work across all layouts.                                   */
/* DON'T PUT ANY LAYOUT-SPECIFIC CODE HERE.                         */

/* return the identifier of the stripe containing the given address */
#define _nasd_cheops_LogicalAddressToStripeID(_layoutPtr_, _addr_) \
( ((_addr_) / (_layoutPtr_)->stripeUnitSize) / (_layoutPtr_)->numDataCol )
     
/* return the logical address of the start of the indicates stripe ID */
#define _nasd_cheops_StripeIDToLogicalAddress(_layoutPtr_, _sid_) \
  ( ((_sid_) * (_layoutPtr_)->stripeUnitSize) * (_layoutPtr_)->numDataCol )

/* return the identifier of the stripe containing the given stripe unit id */
#define _nasd_cheops_StripeUnitIDToStripeID(_layoutPtr_, _addr_) \
  ( (_addr_) / (_layoutPtr_)->numDataCol )

/* return the identifier of the stripe unit containing the given address */
#define _nasd_cheops_LogicalAddressToStripeUnitID(_layoutPtr_, _addr_) \
  ( ((_addr_) / (_layoutPtr_)->stripeUnitSize) )

/* return the Logical address of next stripe boundary beyond the given address */
#define _nasd_cheops_LogicalAddressOfNextStripeBoundary(_layoutPtr_, _addr_) \
  ( (((_addr_)/(_layoutPtr_)->dataStripeSize)+1) * (_layoutPtr_)->dataStripeSize )

/* return the logical address of the start of the stripe containing the given address */
#define _nasd_cheops_LogicalAddressOfPrevStripeBoundary(_layoutPtr_, _addr_) \
  ( (((_addr_)/(_layoutPtr_)->dataStripeSize)+0) * (_layoutPtr_)->dataStripeSize )

/* return the logical address of next stripe unit boundary beyond the given address */
#define _nasd_cheops_LogicalAddressOfNextStripeUnitBoundary(_layoutPtr_, _addr_) \
  ( (((_addr_)/(_layoutPtr_)->stripeUnitSize)+1L)*(_layoutPtr_)->stripeUnitSize )

/* return the logical address of the start of the stripe unit containing logical address _addr_ */
#define _nasd_cheops_LogicalAddressOfPrevStripeUnitBoundary(_layoutPtr_, _addr_) \
  ( (((_addr_)/(_layoutPtr_)->stripeUnitSize)+0)*(_layoutPtr_)->stripeUnitSize )

/* returns the offset into the stripe.  used by LogicalAddressStripeAligned */
#define _nasd_cheops_LogicalAddressStripeOffset(_layoutPtr_, _addr_) \
  ( (_addr_) % ((_layoutPtr_)->dataStripeSize) )

/* returns the offset into the stripe unit.  */
#define _nasd_cheops_StripeUnitOffset(_layoutPtr_, _addr_) \
  ( (_addr_) % ((_layoutPtr_)->stripeUnitSize) )

/* returns nonzero if the given logical address is stripe-aligned */
#define _nasd_cheops_LogicalAddressStripeAligned( __layoutPtr__, __addr__ ) \
  ( _nasd_cheops_LogicalAddressStripeOffset(__layoutPtr__, __addr__) == 0 )

/* returns nonzero if the given address is stripe-unit aligned */
#define _nasd_cheops_StripeUnitAligned( __layoutPtr__, __addr__ ) \
  ( _nasd_cheops_StripeUnitOffset(__layoutPtr__, __addr__) == 0 )

/* convert a Logical address to/from a parity stripe ID.  Conversion to Logical address is easy,
 * since we're asking for the address of the first sector in the parity stripe.  Conversion to a
 * parity stripe ID is more complex, since stripes are not contiguously allocated in
 * parity stripes.
 */
#define _nasd_cheops_LogicalAddressToParityStripeID(_layoutPtr_, _addr_, _ru_num_) \
  _nasd_cheops_MapStripeIDToParityStripeID( (_layoutPtr_), _nasd_cheops_LogicalAddressToStripeID( (_layoutPtr_), (_addr_) ), (_ru_num_) )

#define _nasd_cheops_ParityStripeIDToLogicalAddress(_layoutPtr_, _psid_) \
  ( (_psid_) * (_layoutPtr_)->SUsPerPU * (_layoutPtr_)->numDataCol * (_layoutPtr_)->stripeUnitSize )

#endif /* !_NASD_CHEOPS_RAIDMAP_H_ */
