/*
 * Copyright (c) 1998,1999,2000
 *	Traakan, Inc., Los Altos, CA
 *	All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Project:  NDMJOB
 * Ident:    $Id: $
 *
 * Description:
 *
 */


#define SMC_MAX_SENSE_DATA	127

/* carefully layed out so that 16-byte/line hex dumps look nice */
struct smc_scsi_req {
	unsigned char	completion_status;
	unsigned char	status_byte;
	unsigned char	data_dir;
	unsigned char	n_cmd;

	unsigned char	cmd[12];

	unsigned char *	data;
	unsigned	n_data_avail;
	unsigned	n_data_done;
	unsigned long	_pad;

	unsigned char	n_sense_data;
	unsigned char	sense_data[SMC_MAX_SENSE_DATA];
};

#define SMCSR_CS_GOOD	0
#define SMCSR_CS_FAIL	1
/* more? */

#define SMCSR_DD_NONE	0
#define SMCSR_DD_IN	1	/* adapter->app */
#define SMCSR_DD_OUT	2	/* app->adapter */



struct smc_volume_tag {
	unsigned char	volume_id[32];
	unsigned short	volume_seq;
};



struct smc_element_address_assignment {
	unsigned	mte_addr;	/* media transport element */
	unsigned	mte_count;

	unsigned	se_addr;	/* storage element */
	unsigned	se_count;

	unsigned	iee_addr;	/* import/export element */
	unsigned	iee_count;

	unsigned	dte_addr;	/* data transfer element */
	unsigned	dte_count;
};


#define SMC_ELEM_TYPE_ALL	0
#define SMC_ELEM_TYPE_MTE	1
#define SMC_ELEM_TYPE_SE	2
#define SMC_ELEM_TYPE_IEE	3
#define SMC_ELEM_TYPE_DTE	4

struct smc_element_descriptor {
	unsigned char	element_type_code;
	unsigned short	element_address;

	/* Flags, use SCSI spec names for convenience */
	unsigned	PVolTag : 1;	/* MSID primary vol tag info present */
	unsigned	AVolTag : 1;	/* MSID alternate vol tag present */
	unsigned	InEnab	: 1;	/* --I- supports import */
	unsigned	ExEnab	: 1;	/* --I- supports export */
	unsigned	Access	: 1;	/* -SID access by a MTE allowed */
	unsigned	Except	: 1;	/* MSID element in abnormal state */
	unsigned	ImpExp	: 1;	/* --I- placed by operator */
	unsigned	Full	: 1;	/* MSID contains a unit of media */
	unsigned	Not_bus	: 1;	/* ---D if ID_valid, not same bus */
	unsigned	ID_valid: 1;	/* ---D scsi_sid valid */
	unsigned	LU_valid: 1;	/* ---D scsi_lun valid */
	unsigned	SValid	: 1;	/* MSID src_se_addr and Invert valid */
	unsigned	Invert	: 1;	/* MSID inverted by MOVE/EXCHANGE */

	unsigned char	asc;		/* Additional sense code */
	unsigned char	ascq;		/* Additional sense code qualifier */
	unsigned short	src_se_addr;	/* if Svalid, last *STORAGE* element */

	unsigned char	scsi_sid;	/* if ID_valid, SID of drive */
	unsigned char	scsi_lun;	/* if LU_valid, LUN of drive */

	struct smc_volume_tag primary_vol_tag;	/* if PVolTag */
	struct smc_volume_tag alternate_vol_tag;/* if AVolTag */
};



#ifndef SMC_MAX_ELEMENT
#define SMC_MAX_ELEMENT		80
#endif

struct smc_ctrl_block {
	unsigned char		ident[32];

	unsigned char		valid_elem_aa;
	unsigned char		valid_elem_desc;

	struct smc_element_address_assignment
				elem_aa;

	struct smc_element_descriptor
				elem_desc[SMC_MAX_ELEMENT];
	unsigned		n_elem_desc;

	struct smc_scsi_req	scsi_req;

	int			(*issue_scsi_req)(struct smc_ctrl_block *smc);
	void *			app_data;

	int			dont_ask_for_voltags;

	char			errmsg[64];
};


extern int	smc_inquire (struct smc_ctrl_block *smc);
extern int	smc_test_unit_ready (struct smc_ctrl_block *smc);
extern int	smc_get_elem_aa (struct smc_ctrl_block *smc);
extern int	smc_init_elem_status (struct smc_ctrl_block *smc);
extern int	smc_read_elem_status (struct smc_ctrl_block *smc);

extern int	smc_move (struct smc_ctrl_block *smc,
			unsigned from_addr, unsigned to_addr, int invert,
			unsigned chs_addr);
extern int	smc_position (struct smc_ctrl_block *smc,
			unsigned to_addr, int invert);

extern int	smc_handy_move_to_drive (struct smc_ctrl_block *smc,
			unsigned from_se_ix);
extern int	smc_handy_move_from_drive (struct smc_ctrl_block *smc,
			unsigned to_se_ix);

extern char *	smc_elem_type_code_to_str(int code);

extern int	smc_pp_element_address_assignments (
			struct smc_element_address_assignment *eaa,
			int lineno, char *buf);

extern int	smc_pp_element_descriptor (struct smc_element_descriptor *edp,
			int lineno, char *ret_buf);
