/*
 * nasd_cheops_cl_drive.c
 *
 * Authors: Khalil Amiri, CMU SCS/ECE, July 18 1997
 *          Sean Levy, CMU SCS, July 1999
 */
/*
 * 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 <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <string.h>

#include <nasd/nasd_pdrive.h>
#include <nasd/nasd_pdrive_client.h>
#include <nasd/nasd_pdev.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_drive_types.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_cheops_ios.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_general.h>
#include <nasd/nasd_cheops_types.h>
#include <nasd/nasd_cheops_common.h>
#include <nasd/nasd_cheops_cache.h>
#include <nasd/nasd_cheops_mgr_structs.h>
#include <nasd/nasd_cheops_mgr_common.h>

#define _NASD_CHEOPS_CL_DRIVE_DEBUG 1

extern _nasd_cheops_cache_t *_nasd_cheops_dr_handle_cachep;
nasd_error_string_t error_text;

int
_nasd_cheops_null_dr(
  int di,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_drive_handle_t h = NULL;
  nasd_partnum_t partnum;
  _nasd_cheops_dr_handle_t  dr_handle; 
  _nasd_cheops_cache_key_t  in_key;
  int rc;
     
  in_key.object_id = 0;
  in_key.record_id = di;
  rc = _nasd_cheops_cache_read(_nasd_cheops_dr_handle_cachep, 
			       in_key, (caddr_t) &dr_handle);
  if (rc) {
    (cheops_Msg "CHEOPS error: can not get handle for drive \n");
    return rc;
  }
  h = dr_handle.h;
  partnum = dr_handle.partnum;
     
  nasd_cl_p_null_dr(h, nasd_status, status);

  if (*status || *nasd_status) {
    fprintf(stderr,
	    "ERROR from drive noop, status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return 0;
}

int
_nasd_cheops_null_h_dr(nasd_drive_handle_t h,
		       nasd_status_t *nasd_status,
		       nasd_rpc_status_t *status)
{
  nasd_cl_p_null_dr(h, nasd_status, status);

  if (*status || *nasd_status) {
    fprintf(stderr,
	    "ERROR from drive noop, status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  } 
  if (*status)
    exit(1);
  else 
    return 0;
}

int
_nasd_cheops_part_create_h_dr(
  nasd_drive_handle_t h,
  nasd_partnum_t in_partnum,
  nasd_key_t in_key,
  int in_nblocks,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  int partnum, nblocks;

  nasd_security_param_t sp;
  nasd_p_part_creat_dr_args_t args;
  nasd_p_part_creat_dr_res_t res;
  nasd_key_t drive_key, part_key, red_key, black_key;
  nasd_status_t loc_nasd_status;

  /* Fill in capability and security param */
  args.in_min_protection = NASD_NO_PROTECTION;
  sp.type = NASD_DRIVE_KEY;
  sp.actual_protection = NASD_NO_PROTECTION;
  args.in_partnum = in_partnum;
  args.in_blkcnt = in_nblocks;
  bcopy(part_key,args.in_partition_key,sizeof(nasd_key_t));
  bcopy(red_key,args.in_red_key,sizeof(nasd_key_t));
  bcopy(black_key,args.in_black_key,sizeof(nasd_key_t));
 
  nasd_cl_p_part_creat_dr(h, drive_key, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;

  if (*nasd_status || *status) {
    fprintf(stderr,
	    "ERROR from drive nasd_cl_part_creat_dr, status=0x%x "
	    "(%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return 0;
}

int
_nasd_cheops_create_dr(
  int di,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t *out_identifier,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_p_create_dr_args_t args;
  nasd_p_create_dr_res_t res;
  nasd_security_param_t sp;
  nasd_drive_handle_t h=NULL;
  nasd_partnum_t partnum;
  _nasd_cheops_dr_handle_t  dr_handle; 
  _nasd_cheops_cache_key_t  in_key;
  int rc;
     
  in_key.object_id = 0;
  in_key.record_id = di;

  rc = _nasd_cheops_cache_read(_nasd_cheops_dr_handle_cachep, 
			       in_key, (caddr_t) &dr_handle);
  if (rc) {
    (cheops_Msg "CHEOPS error: can not get handle for drive \n");
    return rc;
  }

  h = dr_handle.h;
  partnum = dr_handle.partnum;
     
  /* @@@ fill in security param */
  bzero((char *)&sp, sizeof(sp));
  bzero((char *)&args, sizeof(args));
  args.in_partnum =  partnum;
     
  nasd_cl_p_create_dr(h, NULL, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;

  if (*status || res.nasd_status) {
    fprintf(stderr, "ERROR from drive nasd_cl_p_create_dr, "
	    "status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  *out_identifier = res.out_identifier;
  if (*status)
    exit(1);
  else
    return 0;
}

int
_nasd_cheops_create_h_dr(
  nasd_drive_handle_t h,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t *out_identifier,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_p_create_dr_args_t args;
  nasd_p_create_dr_res_t res;
  nasd_security_param_t sp;
			     
  bzero((char *)&args, sizeof(args));
  /* @@@ fill in security param */
  bzero((char *)&sp, sizeof(sp));
  args.in_partnum =  in_partnum;

  nasd_cl_p_create_dr(h, NULL, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;
  if (*status || res.nasd_status) {
    fprintf(stderr,
	    "ERROR from drive nasd_cl_p_create_dr, status=0x%x (%s) "
	    "nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  *out_identifier = res.out_identifier;
  if (*status)
    exit(1);
  else
    return 0;
}

int 
_nasd_cheops_remove_dr(
  int di,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t in_identifier,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_p_remove_dr_args_t args;
  nasd_p_remove_dr_res_t res;
  nasd_security_param_t sp;
     
  nasd_drive_handle_t h=NULL;
  nasd_partnum_t partnum;
  _nasd_cheops_dr_handle_t  dr_handle; 
  _nasd_cheops_cache_key_t  in_key;
  int rc;
     
  in_key.object_id = 0;
  in_key.record_id = di;
  rc = _nasd_cheops_cache_read(_nasd_cheops_dr_handle_cachep, 
			       in_key, (caddr_t) &dr_handle);
  if (rc) {
    (cheops_Msg "CHEOPS error: can not get handle for drive \n");
    return rc;
  }
  h = dr_handle.h;
  partnum = dr_handle.partnum;

  /* @@@ init security param */
  bzero(&sp, sizeof(sp));
  args.in_identifier = in_identifier;
  nasd_cl_p_remove_dr(h, NULL, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;

  if (*status || res.nasd_status) {
    fprintf(stderr, "ERROR from drive nasd_cl_p_remove_dr, "
	    "status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return 0;

}

int 
_nasd_cheops_remove_h_dr(
  nasd_drive_handle_t h,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t in_identifier,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_p_remove_dr_args_t args;
  nasd_p_remove_dr_res_t res;
  nasd_security_param_t sp;
     
  args.in_identifier = in_identifier;
  /* @@@ init security param */
  bzero(&sp, sizeof(sp));

  nasd_cl_p_remove_dr(h, NULL, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;

  if (*status || res.nasd_status) {
    fprintf(stderr, "ERROR from drive nasd_cl_p_remove_dr, "
	    "status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return 0;
}

int 
_nasd_cheops_getattr_dr(
  int di,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t in_id,
  nasd_attribute_t *out_attribute,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_p_getattr_dr_args_t args;
  nasd_p_getattr_dr_res_t res;
  nasd_security_param_t sp;
  nasd_drive_handle_t h=NULL;
  nasd_partnum_t partnum;
  _nasd_cheops_dr_handle_t  dr_handle; 
  _nasd_cheops_cache_key_t  in_key;
  int rc;
     
  in_key.object_id = 0;
  in_key.record_id = di;

  rc = _nasd_cheops_cache_read(_nasd_cheops_dr_handle_cachep, 
			       in_key, (caddr_t) &dr_handle);
  if (rc) {
    (cheops_Msg "CHEOPS error: can not get handle for drive \n");
    return rc;
  }
  h = dr_handle.h;
  partnum = dr_handle.partnum;

  args.in_identifier = in_id;
  args.in_partnum = partnum;
  /* @@@ init security param */
  bzero(&sp, sizeof(sp));
     
  nasd_cl_p_getattr_dr(h, NULL, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;
  *out_attribute = res.out_attribute;     

  if (*status || res.nasd_status) {
    fprintf(stderr, "ERROR from drive nasd_cl_p_getattr_dr, "
	    "status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return 0;
}

int
_nasd_cheops_setattr_dr(
  int di,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key, 
  nasd_identifier_t in_identifier,
  nasd_attribute_t *in_attribute,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)		       
{
  nasd_p_setattr_dr_args_t args;
  nasd_p_setattr_dr_res_t res;
  nasd_security_param_t sp;
  nasd_drive_handle_t h=NULL;
  nasd_partnum_t partnum;
  _nasd_cheops_dr_handle_t  dr_handle; 
  _nasd_cheops_cache_key_t  in_key;
  int rc;
     
  in_key.object_id = 0;
  in_key.record_id = di;

  rc = _nasd_cheops_cache_read(_nasd_cheops_dr_handle_cachep, 
			       in_key, (caddr_t) &dr_handle);
  if (rc) {
    (cheops_Msg "CHEOPS error: can not get handle for drive \n");
    return rc;
  }
  h = dr_handle.h;
  partnum = dr_handle.partnum;
     
  args.in_identifier = in_identifier;
  args.in_partnum = partnum;
  args.in_fieldmask = NASD_ATTR_MODIFY_TIME;

  args.in_fieldmask |= NASD_ATTR_FS_SPECIFIC;
  bzero((char *)&args.in_attribute, sizeof(args.in_attribute));
  args.in_attribute = *in_attribute;
  args.in_partnum = partnum;
  args.in_guard = 0;
  /* @@@ init security param */
  bzero(&sp, sizeof(sp));
     
  /* bcopy(in_attribute.fs_specific, ca, sizeof(ca)); */
  nasd_cl_p_setattr_dr(h, NULL, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;

  if (*status || res.nasd_status) {
    fprintf(stderr, "ERROR from drive nasd_cl_p_setattr_dr, "
	    "status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return 0;

}

int 
_nasd_cheops_getattr_h_dr(
  nasd_drive_handle_t h,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t in_id,
  nasd_attribute_t *out_attribute,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_p_getattr_dr_args_t args;
  nasd_p_getattr_dr_res_t res;    
  nasd_security_param_t sp;

  args.in_identifier = in_id;
  args.in_partnum = in_partnum;
  /* @@@ init security param */
  bzero(&sp, sizeof(sp));
      
  nasd_cl_p_getattr_dr(h, NULL, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;
  *out_attribute = res.out_attribute;

  if (*status || res.nasd_status) {
    fprintf(stderr, "ERROR from drive nasd_cl_p_getattr_dr, status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return 0;

}

int
_nasd_cheops_setattr_h_dr(
  nasd_drive_handle_t h,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t in_identifier,
  nasd_attribute_t *in_attribute,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)		       
{
  nasd_p_setattr_dr_args_t args;
  nasd_p_setattr_dr_res_t res;
  nasd_security_param_t sp;
     

  args.in_identifier = in_identifier;
  args.in_partnum = in_partnum;
  args.in_fieldmask = NASD_ATTR_MODIFY_TIME;
  args.in_fieldmask |= NASD_ATTR_FS_SPECIFIC;
  bzero((char *)&args.in_attribute, sizeof(nasd_attribute_t));
  args.in_attribute = *in_attribute;
  args.in_guard = 0;
  /* @@@ init security param */
  bzero(&sp, sizeof(sp));
  /* bcopy(in_attribute.fs_specific, ca, sizeof(ca)); */

  nasd_cl_p_setattr_dr(h, NULL, &sp, NULL, &args, &res, status);
  *nasd_status = res.nasd_status;

  if (*status || res.nasd_status) {
    fprintf(stderr, "ERROR from drive nasd_cl_p_setattr_dr, status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return 0;

}

int
_nasd_cheops_read_dr(
  int di,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t in_identifier,
  nasd_byte_t *buf,
  nasd_offset_t in_offset, 
  nasd_len_t in_len,
  nasd_uint64 bms_targ,
  nasd_len_t *out_len, 
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  int rc=0, fd=0;
  nasd_partnum_t partnum;
  nasd_security_param_t sp;
  nasd_capability_t capargs;
  nasd_drive_handle_t h=NULL;
  _nasd_cheops_dr_handle_t  dr_handle; 
  _nasd_cheops_cache_key_t  in_key;
  nasd_p_thrtl_op_dr_args_t trd_args;
  nasd_p_smpl_op_dr_args_t  rd_args;
  nasd_p_fastread_dr_res_t  rd_res;

  in_key.object_id = 0;
  in_key.record_id = di;
  rc = _nasd_cheops_cache_read(_nasd_cheops_dr_handle_cachep, 
			       in_key, (caddr_t) &dr_handle);
  if (rc) {
    (cheops_Msg "CHEOPS error: can not get handle for drive \n");
    return rc;
  }
  h = dr_handle.h;
  partnum = dr_handle.partnum;
  fd = dr_handle.fd;

  /* XXX init capargs */
  /* @@@ init security param */
  bzero(&sp, sizeof(sp));

  if (bms_targ) {
    fprintf(stderr,"_nasd_cheops_read_dr : obsolete incast-avoidance "
	    "throttling detected.  aborting.\n\t\t-rochberg");
    fflush (stderr);
    NASD_PANIC();
    trd_args.in_partnum = partnum;
    trd_args.in_identifier = in_identifier;
    trd_args.in_offset = in_offset;
    trd_args.in_bms_targ = bms_targ;
    trd_args.in_len = in_len;
    /* @@@ init security param */
    sp.partnum = partnum;
    nasd_cl_p_tread_simple_dr(h, NULL, &sp, NULL, &trd_args, buf,
			      &rd_res, status);
    *out_len = rd_res.out_datalen;
    *nasd_status = rd_res.nasd_status;
  }
  else {
    rd_args.in_partnum = partnum;
    rd_args.in_identifier = in_identifier;
    rd_args.in_offset = in_offset;
    rd_args.in_len = in_len;
    sp.partnum = partnum;
    nasd_cl_p_read_simple_dr(h, NULL, &sp, NULL, &rd_args, buf,
			     &rd_res, status);
    *out_len = rd_res.out_datalen;
    *nasd_status = rd_res.nasd_status;
  }

  if ((*nasd_status == NASD_SUCCESS) && (status == 0)) {
    if (*out_len != in_len) {
      (cheops_Msg "read_dr was incomplete to obj=0x%"NASD_ID_FMT
       ", offset=%"NASD_64u_FMT
       ", size=%d, nasd_status=0x%x (%s), status=0x%x\n",
       in_identifier, in_offset, in_len, *nasd_status,
       nasd_error_string(*nasd_status), *status);
      return _NASD_CHEOPS_ERR_READINCOMP;
    } 
    else {
      return 0;
    }
  }

  if (*status || *nasd_status) {
    (cheops_Msg "read_dr failed to obj=0x%"NASD_ID_FMT
     ", offset=%"NASD_64u_FMT
     ", size=%d, nasd_status=0x%x (%s), status=0x%x\n",
     in_identifier, in_offset, in_len, *nasd_status,
     nasd_error_string(*nasd_status), *status);
  }
  if (*status)
    exit(1);     

  return (*nasd_status);
}

int
_nasd_cheops_write_dr(
  int di,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t in_identifier,
  nasd_byte_t *buf,
  nasd_offset_t in_offset, 
  nasd_len_t in_len,
  nasd_len_t *out_len,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_capability_t capargs;
  _nasd_cheops_dr_handle_t  dr_handle;
  nasd_drive_handle_t                  h = NULL;
  int rc;
  nasd_partnum_t partnum;
  _nasd_cheops_cache_key_t  in_key;
  nasd_p_smpl_op_dr_args_t  wr_args;
  nasd_p_fastwrite_dr_res_t  wr_res;
  nasd_security_param_t sp;

  in_key.object_id = 0;
  in_key.record_id = di;

  rc = _nasd_cheops_cache_read(_nasd_cheops_dr_handle_cachep, 
			       in_key, (caddr_t) &dr_handle);
  if (rc) {
    (cheops_Msg "CHEOPS error: can not get handle for drive \n");
    return rc;
  }
  h = dr_handle.h;
  partnum = dr_handle.partnum;
  /* @@@ init security param */
  bzero(&sp, sizeof(sp));
  wr_args.in_partnum = partnum;
  wr_args.in_identifier = in_identifier;
  wr_args.in_offset = in_offset;
  wr_args.in_len = in_len;
  sp.partnum = partnum;

  nasd_cl_p_write_simple_dr(h, NULL, &sp, NULL, &wr_args, buf,
			    &wr_res, status);
  *out_len = wr_res.out_datalen;
  *nasd_status = wr_res.nasd_status;

  if ((*nasd_status == NASD_SUCCESS) && (*status == 0)) {
    if (*out_len != in_len) {
      (cheops_Msg "write_dr was incomplete: to obj=0x%"NASD_ID_FMT
       ", offset=%"NASD_64u_FMT
       ", size=%d, nasd_status=0x%x (%s), status=0x%x\n",
       in_identifier, in_offset, in_len, *nasd_status,
       nasd_error_string(*nasd_status), *status);
      return _NASD_CHEOPS_ERR_WRITEINCOMP;
    }
    else {	  	  
      return 0;
    }
  }

  if (*status || wr_res.nasd_status) {
    (cheops_Msg "write_dr was incomplete: to obj=0x%"NASD_ID_FMT
     ", offset=%"NASD_64u_FMT
     ", size=%d, nasd_status=0x%x (%s), status=0x%x\n",
     in_identifier, in_offset, in_len, *nasd_status,
     nasd_error_string(*nasd_status), *status);
  }
  if (*status)
    exit(1);
  else
    return (*nasd_status);     
}

#if 0
int
_nasd_cheops_tswrite_dr(
  int di,
  nasd_partnum_t in_partnum,
  nasd_key_t req_key,
  nasd_identifier_t in_identifier,
  nasd_byte_t *buf,
  nasd_offset_t in_offset, 
  nasd_len_t in_len,
  nasd_host_tag_t host_tag,
  nasd_len_t *out_len,
  nasd_status_t *nasd_status,
  nasd_rpc_status_t *status)
{
  nasd_capability_args_t capargs;
  _nasd_cheops_dr_handle_t  dr_handle;
  nasd_drive_handle_t                  h = NULL;
  int rc;
  nasd_partnum_t partnum;
  _nasd_cheops_cache_key_t  in_key;
  nasd_p_tswrite_dr_args_t  tswr_args;
  nasd_p_tswrite_dr_res_t  tswr_res;

  in_key.object_id = 0;
  in_key.record_id = di;
  rc = _nasd_cheops_cache_read(_nasd_cheops_dr_handle_cachep, 
			       in_key, (caddr_t) &dr_handle);
  if (rc) {
    (cheops_Msg "CHEOPS error: can not get handle for drive \n");
    return rc;
  }
  h = dr_handle.h;
  partnum = dr_handle.partnum;

  tswr_args.in_partnum = partnum;
  tswr_args.in_identifier = in_identifier;
  tswr_args.in_offset = in_offset;
  tswr_args.in_len = in_len;
  tswr_args.in_host_tag = host_tag;      
  tswr_args.in_capability_args = capargs;
  tswr_args.in_security_param.type = capargs.type;
  tswr_args.in_security_param.partnum = partnum;
  tswr_args.in_security_param.actual_protection = capargs.min_protection;

  nasd_cl_p_tswrite_dr(h, req_key, &tswr_args, buf, &tswr_res, status);
  *out_len = tswr_res.out_datalen;
  *nasd_status = tswr_res.nasd_status;

  if ((*nasd_status == NASD_SUCCESS) && (*status == 0)) {
    if (*out_len != in_len) {
      (cheops_Msg "write_dr failed to obj=0x%"NASD_ID_FMT
       ", offset=%"NASD_64u_FMT
       ", size=%d, nasd_status=0x%x (%s), status=0x%x\n",
       in_identifier, in_offset, in_len, *nasd_status,
       nasd_error_string(*nasd_status), *status);
      return _NASD_CHEOPS_ERR_WRITEINCOMP;
    }
    else {	         
      return 0;
    }
  }

  if (*status || tswr_res.nasd_status) {
    fprintf(stderr, "ERROR from drive nasd_cl_p_write_dr, "
	    "status=0x%x (%s) nasd_status=0x%x (%s)\n",
	    *status, nasd_cl_error_string(h, *status, error_text),
	    *nasd_status, nasd_error_string(*nasd_status));
  }
  if (*status)
    exit(1);
  else
    return (*nasd_status);  
}
#endif

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