/* wjm 14-nov-1997: allow for VAXC compilation, check for read() error */
/* wjm 21-nov-1997: #ifdef PK2K, split transfers into 6kB pieces */
/* wjm 23-nov-1997: heavily edited, simplify logic, etc. ... NOTE "???" below */

/* Copyright 1994 Yggdrasil Computing, Inc. */
/* Written by Adam J. Richter (adam@yggdrasil.com) */

/* Rewritten February 1997 by Eberhard Heuser-Hofmann*/
/* using the OpenVMS generic scsi-interface */
/* see the README-file, how to setup your machine */
/* update to provide Yamaha CDR 400 support */
/* February 1998 */  
/* This file may be copied under the terms and conditions of version 2
   of the GNU General Public License, as published by the Free
   Software Foundation (Cambridge, Massachusetts).

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* The second notice comes from sys$examples:gktest.c (OpenVMS 7.0)*/

/*
** COPYRIGHT (c) 1993 BY
** DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS.
** ALL RIGHTS RESERVED.
**
** THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
** ONLY  IN  ACCORDANCE  OF  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
** INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR  ANY  OTHER
** COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
** OTHER PERSON.  NO TITLE TO AND  OWNERSHIP OF THE  SOFTWARE IS  HEREBY
** TRANSFERRED.
**
** THE INFORMATION IN THIS SOFTWARE IS  SUBJECT TO CHANGE WITHOUT NOTICE
** AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT
** CORPORATION.
**
** DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE  OR  RELIABILITY OF ITS
** SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
*/


#ifdef __DECC
#ifdef VAX
#pragma module cdwrite "V01-04"
#else
#pragma module cdwrite "V01-04"
#endif
#endif

/*
**
** INCLUDE FILES
**
*/

#include <stdio.h>
#include <stdlib.h>
#ifdef __DECC
#include <unistd.h>
#else
#include <unixio.h>
#endif
#include <string.h>
#ifdef __DECC
#include <fcntl.h>
#else
#include <file.h>
#endif
#include <stdarg.h>
#include <ctype.h>
#include <iodef.h>
#include <descrip.h>
#include <starlet.h>

/*
**
** MACRO DEFINITIONS
**
*/

#define GK_EFN 0		/* Event flag number */

#define SCSI_DATA_LENGTH 0x24	/* Length of inquiry buffer */
#define SCSI_DATA2_LENGTH 0x48	/* mode select3 yamaha 400 */

/* SCSI command opcodes */
#define TEST_UNIT_READY		0x00
#define REZERO_UNIT		0x01
#define REQUEST_SENSE		0x03
#define WRITE_6			0x0a
#define WRITE_10		0x2a
#define INQUIRY			0x12
#define MODE_SELECT		0x15
#define START_STOP		0x1b
#define ALLOW_MEDIUM_REMOVAL	0x1e
#define READ_CAPACITY		0x25
#define SYNCRONIZE_CACHE	0x35

/* SCSI-commands - PHILIPS specific. If we fix the program to use multiple
   writers, this would be something that needs attention. */
#define RESERVE_TRACK	0xE4
#define WRITE_TRACK	0xE6
#define LOAD_UNLOAD	0xE7
#define FIXATION	0xE9	/* Write table of contents */
#define RECOVER		0xEC

/*  yamaha CDR 400  */
#define SETCDSPEED		0xBB
#define CLOSETRACK		0x5B
#define MODE_SELECT1		0x55

#define SPEED 2
#define DUMMY_WRITE 1
#define TRACK_NUMBER 0

#define CD_BLOCK_SIZE	 2048
#ifdef PK2K
#define BLOCKS_PER_WRITE    3
#define BLOCKS_PER_READ    24	/* must be a multiple of BLOCKS_PER_WRITE */
#define BWR1 (READ_BLOCK_SIZE * ((5000*1024)/READ_BLOCK_SIZE))
#else
#define BLOCKS_PER_WRITE   25
#define BLOCKS_PER_READ    BLOCKS_PER_WRITE
#define BWR1 (READ_BLOCK_SIZE * ((5000*1024)/READ_BLOCK_SIZE))
#endif
#define READ_BLOCK_SIZE	 (CD_BLOCK_SIZE * BLOCKS_PER_READ)
#define WRITE_BLOCK_SIZE (CD_BLOCK_SIZE * BLOCKS_PER_WRITE)


/*
** SCSI definitions:
**
** Ideally, these definitions should come from a header file provided
** with the system.  At the time that this example was written and at
** the time of last update, no such file was available. For now, we
** define right here fields we need from the SCSI descriptor for this
** example; this should be replaced with the appropriate #include,
** should such a header file become available.  The reader should note
** that some of the field names and types in that header file may
** differ slightly from what's shown here; when and if the header file
** becomes available, code which does depend on the names should use
** the appropriate header file names.  Code which depends on getting
** the types right may need to re-cast these members when referencing
** them.
*/

/* Generic SCSI command descriptor */

struct SCSI$DESC {
	unsigned int	SCSI$L_OPCODE;		/* SCSI Operation Code */
	unsigned int	SCSI$L_FLAGS;		/* SCSI Flags Bit Map */
	char *		SCSI$A_CMD_ADDR;	/* ->SCSI command buffer */
	unsigned int	SCSI$L_CMD_LEN;		/* SCSI command length, bytes */
	char *		SCSI$A_DATA_ADDR;	/* ->SCSI data buffer */
	unsigned int	SCSI$L_DATA_LEN;	/* SCSI data length, bytes */
	unsigned int	SCSI$L_PAD_LEN;		/* SCSI pad length, bytes */
	unsigned int	SCSI$L_PH_CH_TMOUT;	/* SCSI phase change timeout, sec */
	unsigned int	SCSI$L_DISCON_TMOUT;	/* SCSI disconnect timeout, sec */
	unsigned int	SCSI$L_RES_1;		/* Reserved */
	unsigned int	SCSI$L_RES_2;		/* Reserved */
	unsigned int	SCSI$L_RES_3;		/* Reserved */
	unsigned int	SCSI$L_RES_4;		/* Reserved */
	unsigned int	SCSI$L_RES_5;		/* Reserved */
	unsigned int	SCSI$L_RES_6;		/* Reserved */
};

/* SCSI Input/Output Status Block */

#ifdef __ALPHA
#pragma member_alignment save
#pragma nomember_alignment
#endif

struct SCSI$IOSB {
	unsigned short int SCSI$W_VMS_STAT;	/* VMS status code */
	unsigned long int  SCSI$L_IOSB_TFR_CNT; /* Actual #bytes transferred */
	char		   SCSI$B_IOSB_FILL_1;
	unsigned char	   SCSI$B_IOSB_STS;	/* SCSI device status */
};

#ifdef __ALPHA
#pragma member_alignment restore
#endif


/* SCSI status codes and flag field constants */

#define SCSI$K_GOOD_STATUS	0
#define SCSI$K_WRITE		0X0	/* direction of transfer=write */
#define SCSI$K_READ		0X1	/* direction of transfer=read */
#define SCSI$K_FL_ENAB_DIS	0X2	/* enable disconnects */
#define SCSI$K_FL_ENAB_SYNC	0X4	/* enable sync */

/* end of SCSI definitions */

/* data declarations */

static char
	scsi_status,
	scsi_command_6[6], 
	scsi_command_10[10],
	scsi_command_12[12],
	scsi_data[SCSI_DATA_LENGTH], 
	scsi_data1[READ_BLOCK_SIZE], 
	scsi_data2[SCSI_DATA2_LENGTH];
static char
	gk_device[] = {"CDWR"};

static unsigned short int
	gk_chan, 
	transfer_length;

static int
	i, 
	status;

static $DESCRIPTOR(gk_device_desc, gk_device);

static struct SCSI$IOSB gk_iosb ;

static struct SCSI$DESC gk_desc;


long lib$wait();
void lib$stop();

void scsiprbytes(s, cp, n)
		char	*s;
	register unsigned char	*cp;
	register int	n;
{
	printf(s);
	while (--n >= 0)
		printf(" %02X", *cp++);
	printf("\n");
}


void inquire(void) {

	scsi_command_6[0] = INQUIRY;
	scsi_command_6[1] = 0;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = SCSI_DATA_LENGTH;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = SCSI_DATA_LENGTH;	/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


/* Issue the QIO to send the inquiry command and receive the inquiry data */

	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

	if (!(status & 1)) lib$stop(status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop(gk_iosb.SCSI$W_VMS_STAT);

/* Yes, was SCSI Status OK from QIO? */

	if (gk_iosb.SCSI$B_IOSB_STS != SCSI$K_GOOD_STATUS) {
		printf ("Bad SCSI status returned: %02.2x\n",
			gk_iosb.SCSI$B_IOSB_STS);
		abort();
	}

/* The command succeeded. Display the SCSI data returned from the target */

	transfer_length = gk_iosb.SCSI$L_IOSB_TFR_CNT;
	printf ("SCSI inquiry data returned %u bytes of data: \n",
		transfer_length);
	for (i = 8; i < transfer_length; i++) {
		if (isprint (scsi_data[i]))
			printf ("%c", scsi_data[i]);
		else
			printf (".");
	}
	printf ("\n");
}


void request_sense(void) {

	scsi_command_6[0] = REQUEST_SENSE;
	scsi_command_6[1] = 1;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 18;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 18;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

/* The command succeeded. Display the SCSI data returned from the target */

	transfer_length = gk_iosb.SCSI$L_IOSB_TFR_CNT;
	printf ("request_sense returned %u bytes of data: ", transfer_length);
	for (i = 0; i < transfer_length; i++) {
		if (isprint (scsi_data[i]))
			printf ("%c", scsi_data[i]);
		else
			printf (".");
	}
	printf ("\n\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}
void quiet_request_sense(void) {

	scsi_command_6[0] = REQUEST_SENSE;
	scsi_command_6[1] = 1;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 18;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 18;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

/* The command succeeded. Display the SCSI data returned from the target */

	transfer_length = gk_iosb.SCSI$L_IOSB_TFR_CNT;

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void test_unit_ready(void) {
	scsi_command_6[0] = TEST_UNIT_READY;
	scsi_command_6[1] = 0;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 0;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	printf ("Wait until drive becomes ready ... \n");
	do {
		status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE,
				&gk_iosb, 0, 0, 
				&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

		if (!(status & 1)) lib$stop (status);

		if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
			lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	} while (gk_iosb.SCSI$B_IOSB_STS != 0);

	printf ("Drive is ready now!\n");
}


void quiet_test_unit_ready(void) {

	scsi_command_6[0] = TEST_UNIT_READY;
	scsi_command_6[1] = 0;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 0;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */

	do {
		status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE,
				&gk_iosb, 0, 0, 
				&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

		if (!(status & 1)) lib$stop (status);

		if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
			lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	} while (gk_iosb.SCSI$B_IOSB_STS != 0);
}


void unload(void) {

	scsi_command_10[0] = LOAD_UNLOAD;
	scsi_command_10[1] = 1;
	scsi_command_10[2] = 0;
	scsi_command_10[3] = 0;
	scsi_command_10[4] = 0;
	scsi_command_10[5] = 0;
	scsi_command_10[6] = 0;
	scsi_command_10[7] = 0;
	scsi_command_10[8] = 1;
	scsi_command_10[9] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_10[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 10;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("unload done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void load(void) {

	scsi_command_10[0] = LOAD_UNLOAD;
	scsi_command_10[1] = 1;
	scsi_command_10[2] = 0;
	scsi_command_10[3] = 0;
	scsi_command_10[4] = 0;
	scsi_command_10[5] = 0;
	scsi_command_10[6] = 0;
	scsi_command_10[7] = 0;
	scsi_command_10[8] = 0;
	scsi_command_10[9] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_10[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 10;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void disallow_removal(void) {

	scsi_command_6[0] = ALLOW_MEDIUM_REMOVAL;
	scsi_command_6[1] = 0;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 1;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Disallow media-removal done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void start_unit(void) {

	scsi_command_6[0] = START_STOP;
	scsi_command_6[1] = 1;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 1;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Start unit done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}

void rezero_unit(void) {

	scsi_command_6[0] = REZERO_UNIT;
	scsi_command_6[1] = 0;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 0;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


#if CDR100 == 1
	/* ??? wjm: this is called in a loop anyway. Why loop here ??? */
	/* ??? wjm: I don't see what's different for CDR100 ... ??? */

	do {
		status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE,
				&gk_iosb, 0, 0, 
				&gk_desc,sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

		if (!(status & 1)) lib$stop (status);

		if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
			lib$stop (gk_iosb.SCSI$W_VMS_STAT);

		status = gk_iosb.SCSI$B_IOSB_STS & 1;	/* ??? wjm: why '& 1' ??? */
	} while (gk_iosb.SCSI$B_IOSB_STS != 0);

# else

	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	status = gk_iosb.SCSI$B_IOSB_STS & 1;	/* ??? wjm: why '& 1' ??? */

#endif
}


void mode_select1(void) {
	scsi_command_6[0] = MODE_SELECT;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[5] = 0;
#if CDR100 == 1
	scsi_command_6[1] = 0x00;
	scsi_command_6[4] = 12;
#else
	scsi_command_6[1] = 0x10;
	scsi_command_6[4] = 20;
#endif

/* Mode select header: */

	scsi_data[0] = 0;	/* 6+0 reserved */
	scsi_data[1] = 0;	/* 6+1 medium type */
	scsi_data[2] = 0;	/* 6+2 */
	scsi_data[6] = 0;	/* 6+4+2 reserved */
	scsi_data[8] = 0;	/* 6+4+4 create new track ??? */
	scsi_data[9] = 0;	/* reserved... */
	scsi_data[11] = 0;
	scsi_data[12] = 0;
	scsi_data[13] = 0;
	scsi_data[14] = 0;
	scsi_data[15] = 0;
	scsi_data[16] = 0;
	scsi_data[17] = 0;
	scsi_data[18] = 0;	/* reserved */
	scsi_data[19] = 0;	/* 6+4+15, total byte count = 20 */
#if CDR100 == 1
	scsi_data[3] = 0x08;	/* 6+3 block descriptor length */
	scsi_data[4] = 0;	/* 6+4+0 page code */
	scsi_data[5] = 0;	/* 6+4+1 paramter length? */
	scsi_data[7] = 0;	/* 2048-byte non-mixed CDROM sectors */
	scsi_data[10] = 0x08;
#else
	scsi_data[3] = 0;	/* 6+3 block descriptor length */
	scsi_data[4] = 0x21;	/* 6+4+0 page code */
	scsi_data[5] = 14;	/* 6+4+1 paramter length? */
	scsi_data[7] = 1;	/* 2048-byte non-mixed CDROM sectors */
	scsi_data[10] = 0;
#endif

/* Mode Page 0x21 */


	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_WRITE |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */
#if CDR100 == 1
	gk_desc.SCSI$L_DATA_LEN = 12;		/* SCSI data length, bytes */
#else
	gk_desc.SCSI$L_DATA_LEN = 20;		/* SCSI data length, bytes */
#endif


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Mode select #1 done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void mode_select2(int speed, int dummy_write) {

	scsi_command_6[0] = MODE_SELECT;
	scsi_command_6[1] = 0x10;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
#if CDR100 == 1
	scsi_command_6[4] = 8;
#else
	scsi_command_6[4] = 12;
#endif
	scsi_command_6[5] = 0;

/* Mode select header: */

	scsi_data[0] = 0;	/* 6+0 reserved */
	scsi_data[1] = 0;	/* 6+1 medium type */
	scsi_data[2] = 0;	/* 6+2 */
	scsi_data[3] = 0;	/* 6+3 block descriptor length */
#if CDR100 == 1
	scsi_data[4] = 0x31;	/* 6+4+0 page code */
	scsi_data[5] = 0x02;	/* 6+4+1 paramter length? */
	scsi_data[6] = 0;	/* 6+4+2 reserved */
	scsi_data[7] = ((speed == 4 ? 0x20 : speed == 1 ? 0x00 : 0x10) |
			(dummy_write ? 0x01 : 0x00));
	/* 1 = dummy, 0 = real write*/
#else
/* Mode Page 0x23 */
	scsi_data[4] = 0x23;	/* 6+4+0 page code */
	scsi_data[5] = 6;	/* 6+4+1 paramter length? */
	scsi_data[6] = speed;	/* 6+4+2 reserved */
	scsi_data[7] = dummy_write;	/* 1 = dummy, 0 = real write*/
#endif
	scsi_data[8] = 0;	/* 6+4+4 create new track ??? */
	scsi_data[9] = 0;	/* reserved... */
	scsi_data[10] = 0;
	scsi_data[11] = 0;


	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_WRITE |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */
#if CDR100 == 1
	gk_desc.SCSI$L_DATA_LEN = 8;	/* SCSI data length, bytes */
#else
	gk_desc.SCSI$L_DATA_LEN = 12;	/* SCSI data length, bytes */
#endif


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Mode select #2 done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}

void mode_select3(int dummy_write) {
	scsi_command_10[0] = MODE_SELECT1;
	scsi_command_10[1] = 0x10;
	scsi_command_10[2] = 0;
	scsi_command_10[3] = 0;
	scsi_command_10[4] = 0;
	scsi_command_10[5] = 0;
	scsi_command_10[6] = 0;
	scsi_command_10[7] = 0;
	scsi_command_10[8] = 0x48;
	scsi_command_10[7] = 0;

/*	scsiprbytes("mode_select3 command",&scsi_command_10[0],10); */
/* Mode select header: */

	scsi_data2[0] = 0;
	scsi_data2[1] = 0;
	scsi_data2[2] = 0;
	scsi_data2[3] = 0;
	scsi_data2[4] = 0;
	scsi_data2[5] = 0;
	scsi_data2[6] = 0;
	scsi_data2[7] = 0x08;
	scsi_data2[8] = 0;
	scsi_data2[9] = 0;
	scsi_data2[10] = 0;
	scsi_data2[11] = 0;
	scsi_data2[12] = 0;
	scsi_data2[13] = 0;
	scsi_data2[14] = 0x08;
	scsi_data2[15] = 0;
	scsi_data2[16] = 0x05;
	scsi_data2[17] = 0x36;
	scsi_data2[18] = (dummy_write ? 0x11 : 0x01);
	scsi_data2[19] = 0x04;
	scsi_data2[20] = 0x08;
	scsi_data2[21] = 0;
	scsi_data2[22] = 0;
	scsi_data2[23] = 0;
	scsi_data2[24] = 0;
	scsi_data2[25] = 0;
	scsi_data2[26] = 0;
	scsi_data2[27] = 0;
	scsi_data2[28] = 0;
	scsi_data2[29] = 0;
	scsi_data2[30] = 0;
	scsi_data2[31] = 0x00000096;
	scsi_data2[32] = 0;
	scsi_data2[33] = 0x20;
	scsi_data2[34] = 0x20;
	scsi_data2[35] = 0x20;
	scsi_data2[36] = 0x20;
	scsi_data2[37] = 0x20;
	scsi_data2[38] = 0x20;
	scsi_data2[39] = 0x20;
	scsi_data2[40] = 0x20;
	scsi_data2[41] = 0x20;
	scsi_data2[42] = 0x20;
	scsi_data2[43] = 0x20;
	scsi_data2[44] = 0x20;
	scsi_data2[45] = 0x20;
	scsi_data2[46] = 0;
	scsi_data2[47] = 0;
	scsi_data2[48] = 0;
	scsi_data2[49] = 0x20;
	scsi_data2[50] = 0x20;
	scsi_data2[51] = 0x20;
	scsi_data2[52] = 0x20;
	scsi_data2[53] = 0x20;
	scsi_data2[54] = 0x30;
	scsi_data2[55] = 0x30;
	scsi_data2[56] = 0x30;
	scsi_data2[57] = 0x30;
	scsi_data2[58] = 0x30;
	scsi_data2[59] = 0x30;
	scsi_data2[60] = 0x30;
	scsi_data2[61] = 0;
	scsi_data2[62] = 0;
	scsi_data2[63] = 0;
	scsi_data2[64] = 0;
	scsi_data2[65] = 0;
	scsi_data2[66] = 0x08;
	scsi_data2[67] = 0;
	scsi_data2[68] = 0;
	scsi_data2[69] = 0;
	scsi_data2[70] = 0;
	scsi_data2[71] = 0;
/*	scsiprbytes("mode_select3 data",&scsi_data2[0],72); */



	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_WRITE |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_10[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 10;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data2[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */
	gk_desc.SCSI$L_DATA_LEN = 72;		/* SCSI data length, bytes */

	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Mode select #3 done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void setspeed(int speed) {

	scsi_command_12[0] = SETCDSPEED;
	scsi_command_12[1] = 0;
	scsi_command_12[2] =0xff ;
	scsi_command_12[3] = 0xff;
	scsi_command_12[4] = (speed == 4 ? 0x02 : speed == 2 ? 0x01 : 0x00);
	scsi_command_12[5] = (speed == 4 ? 0xC4 : speed == 2 ? 0x62 : 0xB1);
	scsi_command_12[6] = 0;
	scsi_command_12[7] = 0;
	scsi_command_12[8] = 0;
	scsi_command_12[9] = 0;
	scsi_command_12[10] = 0;
	scsi_command_12[10] = 0;

/*        scsiprbytes("setspeed-command",&scsi_command_12[0],12);   */

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_12[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 12;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("setspeed done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}

void write_track(void) {

	scsi_command_10[0] = WRITE_TRACK;
	scsi_command_10[1] = 0;
	scsi_command_10[2] = 0;
	scsi_command_10[3] = 0;
	scsi_command_10[4] = 0;
	scsi_command_10[5] = TRACK_NUMBER;
	scsi_command_10[6] = 1;
	scsi_command_10[7] = 0;
	scsi_command_10[8] = 0;
	scsi_command_10[9] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_10[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 10;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("write_track done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void write_6(void) {
	int i;

	scsi_command_6[0] = WRITE_6 ;
	scsi_command_6[1] = 0;
	scsi_command_6[2] = BLOCKS_PER_WRITE >> 16;
	scsi_command_6[3] = BLOCKS_PER_WRITE >> 8;
	scsi_command_6[4] = BLOCKS_PER_WRITE;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_WRITE |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
    /*	gk_desc.SCSI$A_DATA_ADDR = &scsi_data1[0]; */	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = WRITE_BLOCK_SIZE;	/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */

	for(i = 0; i < READ_BLOCK_SIZE; i += WRITE_BLOCK_SIZE) {

		gk_desc.SCSI$A_DATA_ADDR = &scsi_data1[i];

		status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE,
				&gk_iosb, 0, 0, 
				&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

		if (!(status & 1)) lib$stop (status);

		if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
			lib$stop (gk_iosb.SCSI$W_VMS_STAT);

		status = gk_iosb.SCSI$B_IOSB_STS;
		if(status != SCSI$K_GOOD_STATUS) break;
	}
}

void write_10(int iblnr) {

	int i;
	scsi_command_10[0] = WRITE_10 ;
	scsi_command_10[1] = 0;
	scsi_command_10[2] = 0;
	scsi_command_10[3] = (iblnr >> 16) & 0x00000FF;
	scsi_command_10[4] = (iblnr >> 8) & 0x00000FF;
	scsi_command_10[5] = iblnr & 0x00000FF;
	scsi_command_10[6] = 0;
	scsi_command_10[7] = 0;
	scsi_command_10[8] = BLOCKS_PER_WRITE;
	scsi_command_10[9] = 0;

/*        scsiprbytes("write_10-command",&scsi_command_10[0],10);
        scsiprbytes("write_10-data 0..9",&scsi_data1[0],10);	*/

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_WRITE |	/* SCSI Flags Bit Map */
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_10[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 10;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data1[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = WRITE_BLOCK_SIZE;	/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */

		status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE,
				&gk_iosb, 0, 0, 
				&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

		if (!(status & 1)) lib$stop (status);

		if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
			lib$stop (gk_iosb.SCSI$W_VMS_STAT);

		status = gk_iosb.SCSI$B_IOSB_STS;
}


void sync_cache(void) {

	scsi_command_10[0] = SYNCRONIZE_CACHE;
	scsi_command_10[1] = 0;
	scsi_command_10[2] = 0;
	scsi_command_10[3] = 0;
	scsi_command_10[4] = 0;
	scsi_command_10[5] = 0;
	scsi_command_10[6] = 0;
	scsi_command_10[7] = 0;
	scsi_command_10[8] = 0;
	scsi_command_10[9] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_10[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 10;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Flush Cache done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void fixation(void) {

	scsi_command_10[0] = FIXATION;
	scsi_command_10[1] = 0;
	scsi_command_10[2] = 0;
	scsi_command_10[3] = 0;
	scsi_command_10[4] = 0;
	scsi_command_10[5] = 0;
	scsi_command_10[6] = 0;
	scsi_command_10[7] = 0;
	scsi_command_10[8] = 1;
	scsi_command_10[9] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_10[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 10;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Fixation done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}

void closetrack(void) {

	scsi_command_10[0] = CLOSETRACK;
	scsi_command_10[1] = 0;
	scsi_command_10[2] = 0x02;
	scsi_command_10[3] = 0;
	scsi_command_10[4] = 0;
	scsi_command_10[5] = 0;
	scsi_command_10[6] = 0;
	scsi_command_10[7] = 0;
	scsi_command_10[8] = 0;
	scsi_command_10[9] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_10[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 10;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Close Track done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}

void stop_unit(void) {
	scsi_command_6[0] = START_STOP;
	scsi_command_6[1] = 1;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 0;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	printf ("Stop unit done\n");

	status = gk_iosb.SCSI$B_IOSB_STS;
}


void allow_removal(void) {

	scsi_command_6[0] = ALLOW_MEDIUM_REMOVAL;
	scsi_command_6[1] = 0;
	scsi_command_6[2] = 0;
	scsi_command_6[3] = 0;
	scsi_command_6[4] = 0;
	scsi_command_6[5] = 0;

	gk_desc.SCSI$L_FLAGS = SCSI$K_FL_ENAB_SYNC |
				SCSI$K_READ |
				SCSI$K_FL_ENAB_DIS;	/* SCSI Flags Bit Map */
	gk_desc.SCSI$A_CMD_ADDR = &scsi_command_6[0];	/* ->SCSI command buffer */
	gk_desc.SCSI$L_CMD_LEN = 6;		/* SCSI command length, bytes */
	gk_desc.SCSI$A_DATA_ADDR = &scsi_data[0];	/* ->SCSI data buffer */
	gk_desc.SCSI$L_DATA_LEN = 0;		/* SCSI data length, bytes */
	gk_desc.SCSI$L_PH_CH_TMOUT = 0xff;	/* SCSI phase change timeout, sec */
	gk_desc.SCSI$L_DISCON_TMOUT = 0xff;	/* SCSI disconnect timeout, sec */


	status = sys$qiow ( GK_EFN, gk_chan, IO$_DIAGNOSE, &gk_iosb, 0, 0, 
			&gk_desc, sizeof(gk_desc), 0, 0, 0, 0);

/* Check the various returned status values */

	if (!(status & 1)) lib$stop (status);

	if (!(gk_iosb.SCSI$W_VMS_STAT & 1))
		lib$stop (gk_iosb.SCSI$W_VMS_STAT);

	status = gk_iosb.SCSI$B_IOSB_STS;
}


main (int argc, char **argv ) {
	int bytes_in,eof_in,fd,bges,brd;
	int speed_factor = 2;
	int dummy_write = 1;
	float t = 5.0;
#if	CDR100 ==1 || CDR400 ==1
	if (argc == 1) {
		fprintf (stderr,
 "Usage: cdwrite [-dummy/write] [-speed speed_factor (1/2/4)] \n");
		sys$exit(4);
	}
#else
	if (argc == 1) {
		fprintf (stderr,
 "Usage: cdwrite [-dummy/write] [-speed speed_factor (1/2)] \n");
		sys$exit(4);
	}
#endif
	while (argc > 1) {
		if (strcmp(argv[1], "-write") == 0) {
			dummy_write = 0;
			argv++;
			argc--;
		} else if (strcmp(argv[1], "-dummy") == 0) {
			dummy_write = 1;
			argv++;
			argc--;
		} else if (strcmp(argv[1], "-speed") == 0 &&
			   argv[2] != 0)  {
			switch (speed_factor = atoi(argv[2])) {
			  case 1:
			  case 2:
#if CDR100 == 1 || CDR400 == 1
			  case 4:
#endif
				argv += 2;
				argc -= 2;
				break;
			  default:
				fprintf (stderr, 
					 "%d is not a support speed factor\n");
				sys$exit(4);
			}
		} else {
			fprintf (stderr,
 "Usage: cdwrite [-dummy/write] [-speed speed_factor (1/2/4)]\n");
			sys$exit(4);
		}
	}

#if CDD2000 == 1
	fprintf (stderr, "Version 1.4, compiled for Philips CDD2000\n\n");
#endif
#if HP4020 == 1
	fprintf (stderr, "Version 1.4, compiled for HP 4020\n\n");
#endif
#if CDD2600 == 1
	fprintf (stderr, "Version 1.4, compiled for Philips CDD2600\n\n");
#endif
#if HP6020 == 1
	fprintf (stderr, "Version 1.4, compiled for HP 6020\n\n");
#endif
#if CDR100 == 1
	fprintf (stderr, "Version 1.4, compiled for Yamaha CDR100\n\n");
#endif
#if CDR400 == 1
	fprintf (stderr, "Version 1.4, compiled for Yamaha CDR400\n\n");
#endif

	fprintf (stderr,
		"Parameters:\n dummy=0 write=1: %d\n speed:           %d\n\n",
		!dummy_write,speed_factor);

/* Assign the device channel */

	status = sys$assign ( &gk_device_desc, &gk_chan, 0, 0);
	if (!(status & 1)) {
		printf ("Unable to assign channel to %s", &gk_device[0]);
		sys$exit (status);
	}

	gk_desc.SCSI$L_OPCODE = 1;	/* SCSI Operation Code */
	gk_desc.SCSI$L_PAD_LEN = 0;	/* SCSI pad length, bytes */
	gk_desc.SCSI$L_RES_1 = 0;	/* Reserved */
	gk_desc.SCSI$L_RES_2 = 0;	/* Reserved */
	gk_desc.SCSI$L_RES_3 = 0;	/* Reserved */
	gk_desc.SCSI$L_RES_4 = 0;	/* Reserved */
	gk_desc.SCSI$L_RES_5 = 0;	/* Reserved */
	gk_desc.SCSI$L_RES_6 = 0;	/* Reserved */

	inquire();

	test_unit_ready();

#if CDD2000 == 1 || HP4020 == 1

	do {
		unload();
	} while (status != SCSI$K_GOOD_STATUS);

/* wait a short time */
	lib$wait(&t);

	printf ("load-command\n");
	do {
		load();
	} while (status != SCSI$K_GOOD_STATUS);

	test_unit_ready();

# endif

	disallow_removal();
	if (status != SCSI$K_GOOD_STATUS) {
		printf ("Bad SCSI status returned: %02.2x\n", status);
		abort();
	}

	do {
		start_unit ();
	} while (status != SCSI$K_GOOD_STATUS);

	printf ("Rezero unit\n");
	do {
		rezero_unit ();
	} while (status != SCSI$K_GOOD_STATUS);

	test_unit_ready();

	do {
		start_unit ();
	} while (status != SCSI$K_GOOD_STATUS);

#if	CDR400 == 1
	do {
		mode_select3(dummy_write);
	} while (status != SCSI$K_GOOD_STATUS);
	
	setspeed(speed_factor);
	test_unit_ready();
	do {
		mode_select3(dummy_write);
	} while (status != SCSI$K_GOOD_STATUS);
	test_unit_ready();
	do {
		mode_select3(dummy_write);
	} while (status != SCSI$K_GOOD_STATUS);
#else
	do {
		mode_select1();
	} while (status != SCSI$K_GOOD_STATUS);
 
	do {
		mode_select2(speed_factor,dummy_write);
	} while (status != SCSI$K_GOOD_STATUS);

	do {
		write_track();
	} while (status != SCSI$K_GOOD_STATUS);
# endif
/*****/

	printf ("scsi_write executing. Now it's coffee time ...\n");

	fd = open ("VDA", O_RDONLY ,0,"ctx=stm","mbc=64");
	eof_in = 0;
	bges = 0;

	while(!eof_in) {

		/* fill input buffer */

		bytes_in = 0;
		while(bytes_in < READ_BLOCK_SIZE && !eof_in) {
			brd = read(fd,&scsi_data1[bytes_in],
					READ_BLOCK_SIZE - bytes_in);
			if(brd < 0) {
				perror("read(VDA)");
				abort();
			} else if(brd == 0) {
				eof_in = 1;
			} else {
				bytes_in += brd;
			}
		}
		if(bytes_in == 0) break;	/* must be at end of file */

		/* Act as if the input buffer was full, in effect padding
		 * the input file to a multiple of READ_BLOCK_SIZE bytes
		 */
#if	CDR400 == 1
		write_10(bges/CD_BLOCK_SIZE);
		if (status == 2) {
  		    printf ("Bad SCSI status returned: %02.2x\n", status);
		    abort();
		    }
#else

		quiet_test_unit_ready();
    
		write_6();

		if (status != SCSI$K_GOOD_STATUS) {
  			printf ("Bad SCSI status returned: %02.2x\n", status);
			abort();
		}
#endif
		bges += bytes_in;
		if ( (bges % BWR1) == 0) {
			printf ("%7d Kbytes written\n",bges/1024);
		}
	}

	printf (" %d bytes written\n",bges);

	close(fd);

	printf ("write_track finished\n");

/*****/

	sync_cache();
	if (status != SCSI$K_GOOD_STATUS) {
		printf ("Bad SCSI status returned: %02.2x\n", status);
		if (status == 2) request_sense();
		abort();
	}
#if	CDR400 ==1
	closetrack();
#else
	fixation();
	if (status != SCSI$K_GOOD_STATUS) {
		printf ("Bad SCSI status returned: %02.2x\n", status);
		if (status == 2) request_sense();
		abort();
	}

	sync_cache();
/*	if (status != SCSI$K_GOOD_STATUS) {
 *		printf ("Bad SCSI status returned: %02.2x\n", status);
 *		if (status == 2) request_sense();
 *		abort();
 *	}
 */
#endif
	do {
		stop_unit();
	} while (status != SCSI$K_GOOD_STATUS);

	printf ("Allow media-removal\n");
	do {
		allow_removal();
	} while (status != SCSI$K_GOOD_STATUS);
                                                 
	do {
		unload();
	} while (status != SCSI$K_GOOD_STATUS);

	printf ("CD-Writing finished\n");
}
