/*
 * pikdrive.c
 *
 * in-kernel pdrive user binary
 * (makes server syscall)
 *
 * Author: Jim Zelenka
 */
/*
 * 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 <nasd/nasd_drive_options.h>
#include <nasd/nasd_general.h>
#include <nasd/nasd_pdrive.h>
#include <nasd/nasd_sys.h>
#include <nasd/nasd_timer.h>
#include <nasd/nasd_drive_defaults.h>
#include <nasd/nasd_getopt.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>

#ifdef DEC_OSF
extern void sync(void);
#endif /* DEC_OSF */

char *progname;
int doformat = 0;

int is_secure = 0;

int svc_threads = NASD_DEF_SERVICE_THREADS;
int cache_blocks = 1024;
int stack_size = 0;
int use_tcp = 0;

nasd_layout_type_t layout = NASD_DEF_LAYOUT;

nasd_ioqueue_type_t ioqueue = NASD_DEF_IOQUEUE;

int io_outstanding = NASD_DEF_IO_OUTSTANDING;

unsigned long max_len = 0;

void
usage()
{
  fprintf(stderr, "USAGE: %s [options] devicename\n", progname);
  fprintf(stderr, "  -c   cache blocks [default %d]\n", cache_blocks);
  fprintf(stderr, "  -f   format\n");
  fprintf(stderr, "  -i   I/Os outstanding [default %d]\n",
    NASD_DEF_IO_OUTSTANDING);
  fprintf(stderr, "  -l   layout (default '%c')\n", NASD_DEF_LAYOUT);
  fprintf(stderr, "  -m   maximum disk length to use\n");
  fprintf(stderr, "  -q   disk queue policy (default '%c')\n",
    NASD_DEF_IOQUEUE);
  fprintf(stderr, "  -s   stack size (0 = system default) [default %d]\n",
    stack_size);
  fprintf(stderr, "  -t   service threads [default %d]\n",
    NASD_DEF_SERVICE_THREADS);
  fprintf(stderr, "  -T   use DCE-TCP\n");
  fflush(stderr);
  exit(1);
}

int
main(
  int     argc,
  char  **argv)
{
  int port, ret, md_level;
  struct nasd_serv srv;
  nasd_options_t opts;
  char c, *root_path;
  struct stat s;
  dev_t dev;

  progname = argv[0];
  md_level = 0;

  setbuf(stdout, NULL);
  setbuf(stderr, NULL);

  if (sscanf(NASD_PDRIVE_PORT, "%d", &port) != 1) {
    fprintf(stderr, "ERROR: %s internal error, cannot read port\n", progname);
    fflush(stderr);
    exit(1);
  }

  ret = nasd_srv(NASD_SC_GET_OPTIONS, &opts);
  if (ret) {
    perror("NASD_SC_GET_OPTIONS");
    fprintf(stderr, "ERROR: %s cannot get nasd options from kernel\n",
      progname);
    fflush(stderr);
    exit(1);
  }

  if (opts.opts1 & NASD_OPTS1_SECURITY)
    is_secure = 1;
  else
    is_secure = 0;

  if (!(opts.opts1&NASD_OPTS1_DRIVE)) {
    fprintf(stderr, "ERROR: kernel does not have drive support loaded\n");
    fflush(stderr);
    exit(1);
  }

  while (nasd_getopt(argc, argv, "c:fi:l:m:q:s:t:T", &c)) {
    switch(c) {
      case 'c':
        if (sscanf(nasd_optarg, "%d", &cache_blocks) != 1)
          usage();
        break;
      case 'f':
        doformat = 1;
        break;
      case 'i':
        if (sscanf(nasd_optarg, "%d", &io_outstanding) != 1)
          usage();
        break;
      case 'l':
        if (strlen(nasd_optarg) != 1) {
          usage();
        }
        layout = nasd_optarg[0];
        break;
      case 'm':
        if (sscanf(nasd_optarg, "%lu", &max_len) != 1)
          usage();
        if (max_len == 0)
          usage();
        break;
      case 'q':
        if (strlen(nasd_optarg) != 1) {
          usage();
        }
        ioqueue = nasd_optarg[0];
        break;
      case 's':
        if (sscanf(nasd_optarg, "%d", &stack_size) != 1)
          usage();
        break;
      case 't':
        if (sscanf(nasd_optarg, "%d", &svc_threads) != 1)
          usage();
        break;
      case 'T':
        use_tcp = 1;
        break;
      default:
        usage();
    }
  }
  if (nasd_optind >= argc)
    usage();
  root_path = argv[nasd_optind];

  nasd_optind++;
  if (nasd_optind < argc)
    usage();

  if (svc_threads < 1)
    usage();
  if (cache_blocks < 1)
    usage();
  if (stack_size && (stack_size < 8192))
    usage();
  if (io_outstanding < 1)
    usage();

  if (strlen((char *)root_path) >= MAXPATHLEN) {
    fprintf(stderr, "ERROR: device path name too long\n");
    usage();
  }

  ret = stat(root_path, &s);
  if (ret) {
    perror(root_path);
    exit(1);
  }

#if 0
  if (!S_ISCHR(s.st_mode)) {
    fprintf(stderr, "%s: %s is not a character device\n",
      progname, root_path);
    exit(1);
  }
#endif

  dev = s.st_rdev;    
 
  if (is_secure)
    printf("\nDrive compiled WITH security\n\n");
  else
    printf("\nDrive compiled WITHOUT security\n\n");

#if defined(DEC_OSF) && (NASD_CMU_PDL > 0)
{
  nasd_delaycounter_t delayer;

  printf("Clearing local cache\n");
  ret = PDL_cflush();
  if (ret) {
    perror("PDL_cflush.1");
    fflush(stdout);
    exit(1);
  }
  sync(); sync(); sync();

  NASD_BEGIN_DELAYCNT(&delayer);
  NASD_DELAY_FROM(&delayer, NASD_USEC_PER_SEC/2);

  ret = PDL_cflush();
  if (ret) {
    perror("PDL_cflush.1");
    fflush(stdout);
    exit(1);
  }
  sync(); sync(); sync();
}
#endif /* DEC_OSF && (NASD_CMU_PDL > 0) */

  printf("Ready to launch drive\n");
  fflush(stdout);

  strcpy(srv.root_path, root_path);
#ifdef LINUX
  srv.dev = (nasd_uint64)dev;
#else /* LINUX */
  srv.dev = dev;
#endif /* LINUX */
  srv.do_format = doformat;
  srv.cache_blocks = cache_blocks;
  srv.svc_threads = svc_threads;
  srv.stack_size = stack_size;
  srv.port = port;
  srv.verbose = 1;
  srv.use_tcp = use_tcp;
  srv.security_enabled = 0;
  srv.max_disk_len = max_len;
  srv.config.layout_type = layout;
  srv.config.ioqueue_type = ioqueue;
  srv.config.ios_outstanding = io_outstanding;

  if (sscanf(NASD_PDRIVE_PORT, "%hu", &srv.ipport) != 1) {
    NASD_PANIC();
  }

  fflush(stdout);
  fflush(stderr);
  ret = nasd_srv(NASD_SC_PSRV_GO, &srv);
  perror("nasd_srv(NASD_SC_PSRV_GO)");

  exit(0);
}

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