code:
/*-
 * Copyright (c) 2000, 2002 Kenneth D. Merry
 * 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, this list of conditions, and the following disclaimer,
 *    without modification, immediately at the beginning of the file.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 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.
 *
 */
/*
 * Written by Julian Elischer (julian@tfs.com)
 * for TRW Financial Systems.
 *
 * TRW Financial Systems, in accordance with their agreement with Carnegie
 * Mellon University, makes this software available to CMU to distribute
 * or use in any manner that they see fit as long as this message is kept with
 * the software. For this reason TFS also grants any other persons or
 * organisations permission to use or modify this software.
 *
 * TFS supplies this software to be publicly redistributed
 * on the understanding that TFS is not responsible for the correct
 * functioning of this software in any circumstances.
 *
 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
 *
 *	from: scsi_cd.h,v 1.10 1997/02/22 09:44:28 peter Exp $
 * $FreeBSD: release/9.0.0/sys/cam/scsi/scsi_cd.h 111206 2003-02-21 06:19:38Z ken $
 */
#ifndef	_SCSI_SCSI_CD_H
#define _SCSI_SCSI_CD_H 1

/*
 *	Define two bits always in the same place in byte 2 (flag byte)
 */
#define	CD_RELADDR	0x01
#define	CD_MSF		0x02

/*
 * SCSI command format
 */

struct scsi_pause
{
	u_int8_t op_code;
	u_int8_t byte2;
	u_int8_t unused[6];
	u_int8_t resume;
	u_int8_t control;
};
#define	PA_PAUSE	1
#define PA_RESUME	0

struct scsi_play_msf
{
	u_int8_t op_code;
	u_int8_t byte2;
	u_int8_t unused;
	u_int8_t start_m;
	u_int8_t start_s;
	u_int8_t start_f;
	u_int8_t end_m;
	u_int8_t end_s;
	u_int8_t end_f;
	u_int8_t control;
};

struct scsi_play_track
{
	u_int8_t op_code;
	u_int8_t byte2;
	u_int8_t unused[2];
	u_int8_t start_track;
	u_int8_t start_index;
	u_int8_t unused1;
	u_int8_t end_track;
	u_int8_t end_index;
	u_int8_t control;
};

struct scsi_play_10
{
	u_int8_t op_code;
	u_int8_t byte2;
	u_int8_t blk_addr[4];
	u_int8_t unused;
	u_int8_t xfer_len[2];
	u_int8_t control;
};

struct scsi_play_12
{
	u_int8_t op_code;
	u_int8_t byte2;	/* same as above */
	u_int8_t blk_addr[4];
	u_int8_t xfer_len[4];
	u_int8_t unused;
	u_int8_t control;
};

struct scsi_play_rel_12
{
	u_int8_t op_code;
	u_int8_t byte2;	/* same as above */
	u_int8_t blk_addr[4];
	u_int8_t xfer_len[4];
	u_int8_t track;
	u_int8_t control;
};

struct scsi_read_header
{
	u_int8_t op_code;
	u_int8_t byte2;
	u_int8_t blk_addr[4];
	u_int8_t unused;
	u_int8_t data_len[2];
	u_int8_t control;
};

struct scsi_read_subchannel
{
	u_int8_t op_code;
	u_int8_t byte1;
	u_int8_t byte2;
#define	SRS_SUBQ	0x40
	u_int8_t subchan_format;
	u_int8_t unused[2];
	u_int8_t track;
	u_int8_t data_len[2];
	u_int8_t control;
};

struct scsi_read_toc
{
	u_int8_t op_code;
	u_int8_t byte2;
	u_int8_t unused[4];
	u_int8_t from_track;
	u_int8_t data_len[2];
	u_int8_t control;
};

struct scsi_read_cd_capacity
{
	u_int8_t op_code;
	u_int8_t byte2;
	u_int8_t addr_3;	/* Most Significant */
	u_int8_t addr_2;
	u_int8_t addr_1;
	u_int8_t addr_0;	/* Least Significant */
	u_int8_t unused[3];
	u_int8_t control;
};

struct scsi_set_speed
{
	u_int8_t opcode;
	u_int8_t byte2;
	u_int8_t readspeed[2];
	u_int8_t writespeed[2];
	u_int8_t reserved[5];
	u_int8_t control;
};

struct scsi_report_key
{
	u_int8_t opcode;
	u_int8_t reserved0;
	u_int8_t lba[4];
	u_int8_t reserved1[2];
	u_int8_t alloc_len[2];
	u_int8_t agid_keyformat;
#define RK_KF_AGID_MASK		0xc0
#define RK_KF_AGID_SHIFT	6
#define RK_KF_KEYFORMAT_MASK	0x3f
#define RK_KF_AGID		0x00
#define RK_KF_CHALLENGE		0x01
#define RF_KF_KEY1		0x02
#define RK_KF_KEY2		0x03
#define RF_KF_TITLE		0x04
#define RF_KF_ASF		0x05
#define RK_KF_RPC_SET		0x06
#define RF_KF_RPC_REPORT	0x08
#define RF_KF_INV_AGID		0x3f
	u_int8_t control;
};

/*
 * See the report key structure for key format and AGID definitions.
 */
struct scsi_send_key
{
	u_int8_t opcode;
	u_int8_t reserved[7];
	u_int8_t param_len[2];
	u_int8_t agid_keyformat;
	u_int8_t control;
};

struct scsi_read_dvd_structure
{
	u_int8_t opcode;
	u_int8_t reserved;
	u_int8_t address[4];
	u_int8_t layer_number;
	u_int8_t format;
#define RDS_FORMAT_PHYSICAL		0x00
#define RDS_FORMAT_COPYRIGHT		0x01
#define RDS_FORMAT_DISC_KEY		0x02
#define RDS_FORMAT_BCA			0x03
#define RDS_FORMAT_MANUFACTURER		0x04
#define RDS_FORMAT_CMGS_CPM		0x05
#define RDS_FORMAT_PROT_DISCID		0x06
#define RDS_FORMAT_DISC_KEY_BLOCK	0x07
#define RDS_FORMAT_DDS			0x08
#define RDS_FORMAT_DVDRAM_MEDIA_STAT	0x09
#define RDS_FORMAT_SPARE_AREA		0x0a
#define RDS_FORMAT_RMD_BORDEROUT	0x0c
#define RDS_FORMAT_RMD			0x0d
#define RDS_FORMAT_LEADIN		0x0e
#define RDS_FORMAT_DISC_ID		0x0f
#define RDS_FORMAT_DCB			0x30
#define RDS_FORMAT_WRITE_PROT		0xc0
#define RDS_FORMAT_STRUCTURE_LIST	0xff
	u_int8_t alloc_len[2];
	u_int8_t agid;
	u_int8_t control;
};

/*
 * Opcodes
 */
#define READ_CD_CAPACITY	0x25	/* slightly different from disk */
#define READ_SUBCHANNEL		0x42	/* cdrom read Subchannel */
#define READ_TOC		0x43	/* cdrom read TOC */
#define READ_HEADER		0x44	/* cdrom read header */
#define PLAY_10			0x45	/* cdrom play  'play audio' mode */
#define PLAY_MSF		0x47	/* cdrom play Min,Sec,Frames mode */
#define PLAY_TRACK		0x48	/* cdrom play track/index mode */
#define PLAY_TRACK_REL		0x49	/* cdrom play track/index mode */
#define PAUSE			0x4b	/* cdrom pause in 'play audio' mode */
#define SEND_KEY		0xa3	/* dvd send key command */
#define REPORT_KEY		0xa4	/* dvd report key command */
#define PLAY_12			0xa5	/* cdrom pause in 'play audio' mode */
#define PLAY_TRACK_REL_BIG	0xa9	/* cdrom play track/index mode */
#define READ_DVD_STRUCTURE	0xad	/* read dvd structure */
#define SET_CD_SPEED		0xbb	/* set c/dvd speed */

struct scsi_report_key_data_header
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
};

struct scsi_report_key_data_agid
{
	u_int8_t data_len[2];
	u_int8_t reserved[5];
	u_int8_t agid;
#define RKD_AGID_MASK	0xc0
#define RKD_AGID_SHIFT	6
};

struct scsi_report_key_data_challenge
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t challenge_key[10];
	u_int8_t reserved1[2];
};

struct scsi_report_key_data_key1_key2
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t key1[5];
	u_int8_t reserved1[3];
};

struct scsi_report_key_data_title
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t byte0;
#define RKD_TITLE_CPM		0x80
#define RKD_TITLE_CPM_SHIFT	7
#define RKD_TITLE_CP_SEC	0x40
#define RKD_TITLE_CP_SEC_SHIFT	6
#define RKD_TITLE_CMGS_MASK	0x30
#define RKD_TITLE_CMGS_SHIFT	4
#define RKD_TITLE_CMGS_NO_RST	0x00
#define RKD_TITLE_CMGS_RSVD	0x10
#define RKD_TITLE_CMGS_1_GEN	0x20
#define RKD_TITLE_CMGS_NO_COPY	0x30
	u_int8_t title_key[5];
	u_int8_t reserved1[2];
};

struct scsi_report_key_data_asf
{
	u_int8_t data_len[2];
	u_int8_t reserved[5];
	u_int8_t success;
#define RKD_ASF_SUCCESS	0x01
};

struct scsi_report_key_data_rpc
{
	u_int8_t data_len[2];
	u_int8_t rpc_scheme0;
#define RKD_RPC_SCHEME_UNKNOWN		0x00
#define RKD_RPC_SCHEME_PHASE_II		0x01
	u_int8_t reserved0;
	u_int8_t byte4;
#define RKD_RPC_TYPE_MASK		0xC0
#define RKD_RPC_TYPE_SHIFT		6
#define RKD_RPC_TYPE_NONE		0x00
#define RKD_RPC_TYPE_SET		0x40
#define RKD_RPC_TYPE_LAST_CHANCE	0x80
#define RKD_RPC_TYPE_PERM		0xC0
#define RKD_RPC_VENDOR_RESET_MASK	0x38
#define RKD_RPC_VENDOR_RESET_SHIFT	3
#define RKD_RPC_USER_RESET_MASK		0x07
#define RKD_RPC_USER_RESET_SHIFT	0
	u_int8_t region_mask;
	u_int8_t rpc_scheme1;
	u_int8_t reserved1;
};

struct scsi_send_key_data_rpc
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t region_code;
	u_int8_t reserved1[3];
};

/*
 * Common header for the return data from the READ DVD STRUCTURE command.
 */
struct scsi_read_dvd_struct_data_header
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
};

struct scsi_read_dvd_struct_data_layer_desc
{
	u_int8_t book_type_version;
#define RDSD_BOOK_TYPE_DVD_ROM	0x00
#define RDSD_BOOK_TYPE_DVD_RAM	0x10
#define RDSD_BOOK_TYPE_DVD_R	0x20
#define RDSD_BOOK_TYPE_DVD_RW	0x30
#define RDSD_BOOK_TYPE_DVD_PRW	0x90
#define RDSD_BOOK_TYPE_MASK	0xf0
#define RDSD_BOOK_TYPE_SHIFT	4
#define RDSD_BOOK_VERSION_MASK	0x0f
	/*
	 * The lower 4 bits of this field is referred to as the "minimum
	 * rate" field in MMC2, and the "maximum rate" field in MMC3.  Ugh.
	 */
	u_int8_t disc_size_max_rate;
#define RDSD_DISC_SIZE_120MM	0x00
#define RDSD_DISC_SIZE_80MM	0x10
#define RDSD_DISC_SIZE_MASK	0xf0
#define RDSD_DISC_SIZE_SHIFT	4
#define RDSD_MAX_RATE_0252	0x00
#define RDSD_MAX_RATE_0504	0x01
#define RDSD_MAX_RATE_1008	0x02
#define RDSD_MAX_RATE_NOT_SPEC	0x0f
#define RDSD_MAX_RATE_MASK	0x0f
	u_int8_t layer_info;
#define RDSD_NUM_LAYERS_MASK	0x60
#define RDSD_NUM_LAYERS_SHIFT	5
#define RDSD_NL_ONE_LAYER	0x00
#define RDSD_NL_TWO_LAYERS	0x20
#define RDSD_TRACK_PATH_MASK	0x10
#define RDSD_TRACK_PATH_SHIFT	4
#define RDSD_TP_PTP		0x00
#define RDSD_TP_OTP		0x10
#define RDSD_LAYER_TYPE_RO	0x01
#define RDSD_LAYER_TYPE_RECORD	0x02
#define RDSD_LAYER_TYPE_RW	0x04
#define RDSD_LAYER_TYPE_MASK	0x0f
	u_int8_t density;
#define RDSD_LIN_DENSITY_0267		0x00
#define RDSD_LIN_DENSITY_0293		0x10
#define RDSD_LIN_DENSITY_0409_0435	0x20
#define RDSD_LIN_DENSITY_0280_0291	0x40
/* XXX MMC2 uses 0.176um/bit instead of 0.353 as in MMC3 */
#define RDSD_LIN_DENSITY_0353		0x80
#define RDSD_LIN_DENSITY_MASK		0xf0
#define RDSD_LIN_DENSITY_SHIFT		4
#define RDSD_TRACK_DENSITY_074		0x00
#define RDSD_TRACK_DENSITY_080		0x01
#define RDSD_TRACK_DENSITY_0615		0x02
#define RDSD_TRACK_DENSITY_MASK		0x0f
	u_int8_t zeros0;
	u_int8_t main_data_start[3];
#define RDSD_MAIN_DATA_START_DVD_RO	0x30000
#define RDSD_MAIN_DATA_START_DVD_RW	0x31000
	u_int8_t zeros1;
	u_int8_t main_data_end[3];
	u_int8_t zeros2;
	u_int8_t end_sector_layer0[3];
	u_int8_t bca;
#define RDSD_BCA	0x80
#define RDSD_BCA_MASK	0x80
#define RDSD_BCA_SHIFT	7
	u_int8_t media_specific[2031];
};

struct scsi_read_dvd_struct_data_physical
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	struct scsi_read_dvd_struct_data_layer_desc layer_desc;
};

struct scsi_read_dvd_struct_data_copyright
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t cps_type;
#define RDSD_CPS_NOT_PRESENT	0x00
#define RDSD_CPS_DATA_EXISTS	0x01
	u_int8_t region_info;
	u_int8_t reserved1[2];
};

struct scsi_read_dvd_struct_data_disc_key
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	u_int8_t disc_key[2048];
};

struct scsi_read_dvd_struct_data_bca
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	u_int8_t bca_info[188]; /* XXX 12-188 bytes */
};

struct scsi_read_dvd_struct_data_manufacturer
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	u_int8_t manuf_info[2048];
};

struct scsi_read_dvd_struct_data_copy_manage
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t byte4;
#define RDSD_CPM_NO_COPYRIGHT	0x00
#define RDSD_CPM_HAS_COPYRIGHT	0x80
#define RDSD_CPM_MASK		0x80
#define RDSD_CMGS_COPY_ALLOWED	0x00
#define RDSD_CMGS_ONE_COPY	0x20
#define RDSD_CMGS_NO_COPIES	0x30
#define RDSD_CMGS_MASK		0x30
	u_int8_t reserved1[3];
};

struct scsi_read_dvd_struct_data_prot_discid
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	u_int8_t prot_discid_data[16];
};

struct scsi_read_dvd_struct_data_disc_key_blk
{
	/*
	 * Length is 0x6ffe == 28670 for CPRM, 0x3002 == 12990 for CSS2.
	 */
	u_int8_t data_len[2];
	u_int8_t reserved;
	u_int8_t total_packs;
	u_int8_t disc_key_pack_data[28668];
};
struct scsi_read_dvd_struct_data_dds
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	u_int8_t dds_info[2048];
};

struct scsi_read_dvd_struct_data_medium_status
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t byte4;
#define RDSD_MS_CARTRIDGE	0x80
#define RDSD_MS_OUT		0x40
#define RDSD_MS_MSWI		0x08
#define RDSD_MS_CWP		0x04
#define RDSD_MS_PWP		0x02
	u_int8_t disc_type_id;
#define RDSD_DT_NEED_CARTRIDGE	0x00
#define RDSD_DT_NO_CART_NEEDED	0x01
	u_int8_t reserved1;
	u_int8_t ram_swi_info;
#define RDSD_SWI_NO_BARE	0x01
#define RDSD_SWI_UNSPEC		0xff
};

struct scsi_read_dvd_struct_data_spare_area
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	u_int8_t unused_primary[4];
	u_int8_t unused_supl[4];
	u_int8_t allocated_supl[4];
};

struct scsi_read_dvd_struct_data_rmd_borderout
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	u_int8_t rmd[30720]; 	/* maximum is 30720 bytes */
};

struct scsi_read_dvd_struct_data_rmd
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	u_int8_t last_sector_num[4];
	u_int8_t rmd_bytes[32768];  /* This is the maximum */
};

/*
 * XXX KDM this is the MMC2 version of the structure.
 * The variable positions have changed (in a semi-conflicting way) in the
 * MMC3 spec, although the overall length of the structure is the same.
 */
struct scsi_read_dvd_struct_data_leadin
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t field_id_1;
	u_int8_t app_code;
	u_int8_t disc_physical_data;
	u_int8_t last_addr[3];
	u_int8_t reserved1[2];
	u_int8_t field_id_2;
	u_int8_t rwp;
	u_int8_t rwp_wavelength;
	u_int8_t optimum_write_strategy;
	u_int8_t reserved2[4];
	u_int8_t field_id_3;
	u_int8_t manuf_id_17_12[6];
	u_int8_t reserved3;
	u_int8_t field_id_4;
	u_int8_t manuf_id_11_6[6];
	u_int8_t reserved4;
	u_int8_t field_id_5;
	u_int8_t manuf_id_5_0[6];
	u_int8_t reserved5[25];
};

struct scsi_read_dvd_struct_data_disc_id
{
	u_int8_t data_len[2];
	u_int8_t reserved[4];
	u_int8_t random_num[2];
	u_int8_t year[4];
	u_int8_t month[2];
	u_int8_t day[2];
	u_int8_t hour[2];
	u_int8_t minute[2];
	u_int8_t second[2];
};

struct scsi_read_dvd_struct_data_generic_dcb
{
	u_int8_t content_desc[4];
#define SCSI_RCB
	u_int8_t unknown_desc_actions[4];
#define RDSD_ACTION_RECORDING	0x0001
#define RDSD_ACTION_READING	0x0002
#define RDSD_ACTION_FORMAT	0x0004
#define RDSD_ACTION_MODIFY_DCB	0x0008
	u_int8_t vendor_id[32];
	u_int8_t dcb_data[32728];
};

struct scsi_read_dvd_struct_data_dcb
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	struct scsi_read_dvd_struct_data_generic_dcb dcb;
};

struct read_dvd_struct_write_prot
{
	u_int8_t data_len[2];
	u_int8_t reserved0[2];
	u_int8_t write_prot_status;
#define RDSD_WPS_MSWI		0x08
#define RDSD_WPS_CWP		0x04
#define RDSD_WPS_PWP		0x02
#define RDSD_WPS_SWPP		0x01
	u_int8_t reserved[3];
};

struct read_dvd_struct_list_entry
{
	u_int8_t format_code;
	u_int8_t sds_rds;
#define RDSD_SDS_NOT_WRITEABLE	0x00
#define RDSD_SDS_WRITEABLE	0x80
#define RDSD_SDS_MASK		0x80
#define RDSD_RDS_NOT_READABLE	0x00
#define RDSD_RDS_READABLE	0x40
#define RDSD_RDS_MASK		0x40
	u_int8_t struct_len[2];
};

struct read_dvd_struct_data_list
{
	u_int8_t data_len[2];
	u_int8_t reserved[2];
	struct read_dvd_struct_list_entry entries[0];
};

struct scsi_read_cd_cap_data
{
	u_int8_t addr_3;	/* Most significant */
	u_int8_t addr_2;
	u_int8_t addr_1;
	u_int8_t addr_0;	/* Least significant */
	u_int8_t length_3;	/* Most significant */
	u_int8_t length_2;
	u_int8_t length_1;
	u_int8_t length_0;	/* Least significant */
};

struct cd_audio_page
{
	u_int8_t page_code;
#define	CD_PAGE_CODE		0x3F
#define	AUDIO_PAGE		0x0e
#define	CD_PAGE_PS		0x80
	u_int8_t param_len;
	u_int8_t flags;
#define	CD_PA_SOTC		0x02
#define	CD_PA_IMMED		0x04
	u_int8_t unused[2];
	u_int8_t format_lba;
#define	CD_PA_FORMAT_LBA	0x0F
#define	CD_PA_APR_VALID		0x80
	u_int8_t lb_per_sec[2];
	struct	port_control
	{
		u_int8_t channels;
#define	CHANNEL			0x0F
#define	CHANNEL_0		1
#define	CHANNEL_1		2
#define	CHANNEL_2		4
#define	CHANNEL_3		8
#define	LEFT_CHANNEL		CHANNEL_0
#define	RIGHT_CHANNEL		CHANNEL_1
		u_int8_t volume;
	} port[4];
#define	LEFT_PORT		0
#define	RIGHT_PORT		1
};

union cd_pages
{
	struct cd_audio_page audio;
};

struct cd_mode_data_10
{
	struct scsi_mode_header_10 header;
	struct scsi_mode_blk_desc  blk_desc;
	union cd_pages page;
};

struct cd_mode_data
{
	struct scsi_mode_header_6 header;
	struct scsi_mode_blk_desc blk_desc;
	union cd_pages page;
};

union cd_mode_data_6_10
{
	struct cd_mode_data mode_data_6;
	struct cd_mode_data_10 mode_data_10;
};

struct cd_mode_params
{
	STAILQ_ENTRY(cd_mode_params)	links;
	int				cdb_size;
	int				alloc_len;
	u_int8_t			*mode_buf;
};

__BEGIN_DECLS
void scsi_report_key(struct ccb_scsiio *csio, u_int32_t retries,
		     void (*cbfcnp)(struct cam_periph *, union ccb *),
		     u_int8_t tag_action, u_int32_t lba, u_int8_t agid,
		     u_int8_t key_format, u_int8_t *data_ptr,
		     u_int32_t dxfer_len, u_int8_t sense_len,
		     u_int32_t timeout);

void scsi_send_key(struct ccb_scsiio *csio, u_int32_t retries,
		   void (*cbfcnp)(struct cam_periph *, union ccb *),
		   u_int8_t tag_action, u_int8_t agid, u_int8_t key_format,
		   u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
		   u_int32_t timeout);

void scsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries,
			     void (*cbfcnp)(struct cam_periph *, union ccb *),
			     u_int8_t tag_action, u_int32_t address,
			     u_int8_t layer_number, u_int8_t format,
			     u_int8_t agid, u_int8_t *data_ptr,
			     u_int32_t dxfer_len, u_int8_t sense_len,
			     u_int32_t timeout);

__END_DECLS

#endif /*_SCSI_SCSI_CD_H*/


code:
/* $FreeBSD: release/9.0.0/sys/cam/scsi/scsi_ch.h 208905 2010-06-08 05:14:18Z mjacob $ */
/*	$NetBSD: scsi_changer.h,v 1.11 1998/02/13 08:28:32 enami Exp $	*/

/*-
 * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
 * All rights reserved.
 *
 * Partially based on an autochanger driver written by Stefan Grefen
 * and on an autochanger driver written by the Systems Programming Group
 * at the University of Utah Computer Science Department.
 *
 * 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, 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgements:
 *	This product includes software developed by Jason R. Thorpe
 *	for And Communications, http://www.and.com/
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
 */

/*
 * SCSI changer interface description
 */

/*-
 * Partially derived from software written by Stefan Grefen
 * (grefen@goofy.zdv.uni-mainz.de soon grefen@convex.com)
 * based on the SCSI System by written Julian Elischer (julian@tfs.com)
 * for TRW Financial Systems.
 *
 * TRW Financial Systems, in accordance with their agreement with Carnegie
 * Mellon University, makes this software available to CMU to distribute
 * or use in any manner that they see fit as long as this message is kept with
 * the software. For this reason TFS also grants any other persons or
 * organisations permission to use or modify this software.
 *
 * TFS supplies this software to be publicly redistributed
 * on the understanding that TFS is not responsible for the correct
 * functioning of this software in any circumstances.
 *
 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
 */

#ifndef _SCSI_SCSI_CH_H
#define _SCSI_SCSI_CH_H 1

#include <sys/cdefs.h>

/*
 * SCSI command format
 */

/*
 * Exchange the medium in the source element with the medium
 * located at the destination element.
 */
struct scsi_exchange_medium {
	u_int8_t	opcode;
#define EXCHANGE_MEDIUM		0xa6
	u_int8_t	byte2;
	u_int8_t	tea[2];	/* transport element address */
	u_int8_t	src[2];	/* source address */
	u_int8_t	fdst[2]; /* first destination address */
	u_int8_t	sdst[2]; /* second destination address */
	u_int8_t	invert;
#define EXCHANGE_MEDIUM_INV1	0x01
#define EXCHANGE_MEDIUM_INV2	0x02
	u_int8_t	control;
};

/*
 * Cause the medium changer to check all elements for medium and any
 * other status relevant to the element.
 */
struct scsi_initialize_element_status {
	u_int8_t	opcode;
#define INITIALIZE_ELEMENT_STATUS	0x07
	u_int8_t	byte2;
	u_int8_t	reserved[3];
	u_int8_t	control;
};

/*
 * Request the changer to move a unit of media from the source element
 * to the destination element.
 */
struct scsi_move_medium {
	u_int8_t	opcode;
	u_int8_t	byte2;
	u_int8_t	tea[2];	/* transport element address */
	u_int8_t	src[2];	/* source element address */
	u_int8_t	dst[2];	/* destination element address */
	u_int8_t	reserved[2];
	u_int8_t	invert;
#define MOVE_MEDIUM_INVERT	0x01
	u_int8_t	control;
};

/*
 * Position the specified transport element (picker) in front of
 * the destination element specified.
 */
struct scsi_position_to_element {
	u_int8_t	opcode;
	u_int8_t	byte2;
	u_int8_t	tea[2];	/* transport element address */
	u_int8_t	dst[2];	/* destination element address */
	u_int8_t	reserved[2];
	u_int8_t	invert;
#define POSITION_TO_ELEMENT_INVERT	0x01
	u_int8_t	control;
};

/*
 * Request that the changer report the status of its internal elements.
 */
struct scsi_read_element_status {
	u_int8_t	opcode;
	u_int8_t	byte2;
#define READ_ELEMENT_STATUS_VOLTAG	0x10	/* report volume tag info */
	/* ...next 4 bits are an element type code... */
	u_int8_t	sea[2];	/* starting element address */
	u_int8_t	count[2]; /* number of elements */
	u_int8_t	reserved0;
	u_int8_t	len[3];	/* length of data buffer */
	u_int8_t	reserved1;
	u_int8_t	control;
};

struct scsi_request_volume_element_address {
	u_int8_t	opcode;
	u_int8_t	byte2;
#define REQUEST_VOLUME_ELEMENT_ADDRESS_VOLTAG	0x10
	/* ...next 4 bits are an element type code... */
	u_int8_t	eaddr[2];	/* element address */
	u_int8_t	count[2];	/* number of elements */
	u_int8_t	reserved0;
	u_int8_t	len[3];		/* length of data buffer */
	u_int8_t	reserved1;
	u_int8_t	control;
};

/* XXX scsi_release */

/*
 * Changer-specific mode page numbers.
 */
#define	CH_ELEMENT_ADDR_ASSIGN_PAGE	0x1D
#define	CH_TRANS_GEOM_PARAMS_PAGE	0x1E
#define	CH_DEVICE_CAP_PAGE		0x1F

/*
 * Data returned by READ ELEMENT STATUS consists of an 8-byte header
 * followed by one or more read_element_status_pages.
 */
struct read_element_status_header {
	u_int8_t	fear[2];  /* first element address reported */
	u_int8_t	count[2]; /* number of elements available */
	u_int8_t	reserved;
	u_int8_t	nbytes[3]; /* byte count of all pages */
};

struct read_element_status_page_header {
	u_int8_t	type;	/* element type code; see type codes below */
	u_int8_t	flags;
#define READ_ELEMENT_STATUS_AVOLTAG	0x40
#define READ_ELEMENT_STATUS_PVOLTAG	0x80
	u_int8_t	edl[2];	/* element descriptor length */
	u_int8_t	reserved;
	u_int8_t	nbytes[3]; /* byte count of all descriptors */
};

/*
 * Format of a volume tag
 */

struct volume_tag {
	u_int8_t	vif[32];	/* volume identification field */
	u_int8_t	reserved[2];
	u_int8_t	vsn[2];		/* volume sequence number */
};

struct read_element_status_descriptor {
	u_int8_t	eaddr[2];	/* element address */
	u_int8_t	flags1;

#define READ_ELEMENT_STATUS_FULL	0x01
#define READ_ELEMENT_STATUS_IMPEXP	0x02
#define READ_ELEMENT_STATUS_EXCEPT	0x04
#define READ_ELEMENT_STATUS_ACCESS	0x08
#define READ_ELEMENT_STATUS_EXENAB	0x10
#define READ_ELEMENT_STATUS_INENAB	0x20

#define READ_ELEMENT_STATUS_MT_MASK1	0x05
#define READ_ELEMENT_STATUS_ST_MASK1	0x0c
#define READ_ELEMENT_STATUS_IE_MASK1	0x3f
#define READ_ELEMENT_STATUS_DT_MASK1	0x0c

	u_int8_t	reserved0;
	u_int8_t	sense_code;
	u_int8_t	sense_qual;

	/*
	 * dt_scsi_flags and dt_scsi_addr are valid only on data transport
	 * elements.  These bytes are undefined for all other element types.
	 */
	u_int8_t	dt_scsi_flags;

#define READ_ELEMENT_STATUS_DT_LUNMASK	0x07
#define READ_ELEMENT_STATUS_DT_LUVALID	0x10
#define READ_ELEMENT_STATUS_DT_IDVALID	0x20
#define READ_ELEMENT_STATUS_DT_NOTBUS	0x80

	u_int8_t	dt_scsi_addr;

	u_int8_t	reserved1;

	u_int8_t	flags2;
#define READ_ELEMENT_STATUS_INVERT	0x40
#define READ_ELEMENT_STATUS_SVALID	0x80
	u_int8_t	ssea[2];	/* source storage element address */

	struct volume_tag pvoltag;	/* omitted if PVOLTAG == 0 */
	struct volume_tag avoltag;	/* omitted if AVOLTAG == 0 */

	/* Other data may follow */
};

/* XXX add data returned by REQUEST VOLUME ELEMENT ADDRESS */

/* Element type codes */
#define ELEMENT_TYPE_MASK	0x0f	/* Note: these aren't bits */
#define ELEMENT_TYPE_ALL	0x00
#define ELEMENT_TYPE_MT		0x01
#define ELEMENT_TYPE_ST		0x02
#define ELEMENT_TYPE_IE		0x03
#define ELEMENT_TYPE_DT		0x04

/*
 * XXX The following definitions should be common to all SCSI device types.
 */
#define PGCODE_MASK	0x3f	/* valid page number bits in pg_code */
#define PGCODE_PS	0x80	/* indicates page is savable */

/*
 * Send volume tag information to the changer
 */

struct scsi_send_volume_tag {
	u_int8_t	opcode;
#define SEND_VOLUME_TAG	0xb6
	u_int8_t	byte2;
	u_int8_t	ea[2];		/* element address */
	u_int8_t	reserved2;
  	u_int8_t	sac;		/* send action code */

#define SEND_VOLUME_TAG_ASSERT_PRIMARY		0x08
#define SEND_VOLUME_TAG_ASSERT_ALTERNATE	0x09
#define SEND_VOLUME_TAG_REPLACE_PRIMARY		0x0a
#define SEND_VOLUME_TAG_REPLACE_ALTERNATE	0x0b
#define SEND_VOLUME_TAG_UNDEFINED_PRIMARY	0x0c
#define SEND_VOLUME_TAG_UNDEFINED_ALTERNATE	0x0d

	u_int8_t	reserved4[2];
	u_int8_t	pll[2];		/* parameter list length */
	u_int8_t	reserved5;
	u_int8_t	control;
};

/*
 * Parameter format for SEND VOLUME TAG
 */

struct scsi_send_volume_tag_parameters {
	u_int8_t	vitf[32];	/* volume tag identification template */
	u_int8_t	reserved1[2];
	u_int8_t	minvsn[2];	/* minimum volume sequence number */
	u_int8_t	reserved2[2];
	u_int8_t	maxvsn[2];	/* maximum volume sequence number */
};

/*
 * Device capabilities page.
 *
 * This page defines characteristics of the elemenet types in the
 * medium changer device.
 *
 * Note in the definitions below, the following abbreviations are
 * used:
 *		MT	Medium transport element (picker)
 *		ST	Storage transport element (slot)
 *		IE	Import/export element (portal)
 *		DT	Data tranfer element (tape/disk drive)
 */
struct page_device_capabilities {
	u_int8_t	pg_code;	/* page code (0x1f) */
	u_int8_t	pg_length;	/* page length (0x12) */

	/*
	 * The STOR_xx bits indicate that an element of a given
	 * type may provide independent storage for a unit of
	 * media.  The top four bits of this value are reserved.
	 */
	u_int8_t	stor;
#define STOR_MT		0x01
#define STOR_ST		0x02
#define STOR_IE		0x04
#define STOR_DT		0x08

	u_int8_t	reserved0;

	/*
	 * The MOVE_TO_yy bits indicate the changer supports
	 * moving a unit of medium from an element of a given type to an
	 * element of type yy.  This is used to determine if a given
	 * MOVE MEDIUM command is legal.  The top four bits of each
	 * of these values are reserved.
	 */
	u_int8_t	move_from[CHET_MAX + 1];
#define MOVE_TO_MT	0x01
#define MOVE_TO_ST	0x02
#define MOVE_TO_IE	0x04
#define MOVE_TO_DT	0x08

	u_int8_t	reserved1[4];

	/*
	 * Similar to above, but for EXCHANGE MEDIUM.
	 */
	u_int8_t	exchange_with[CHET_MAX + 1];
#define EXCHANGE_WITH_MT	0x01
#define EXCHANGE_WITH_ST	0x02
#define EXCHANGE_WITH_IE	0x04
#define EXCHANGE_WITH_DT	0x08
};

/*
 * Medium changer elemement address assignment page.
 *
 * Some of these fields can be a little confusing, so an explanation
 * is in order.
 *
 * Each component within a a medium changer apparatus is called an
 * "element".
 *
 * The "medium transport element address" is the address of the first
 * picker (robotic arm).  "Number of medium transport elements" tells
 * us how many pickers exist in the changer.
 *
 * The "first storage element address" is the address of the first
 * slot in the tape or disk magazine.  "Number of storage elements" tells
 * us how many slots exist in the changer.
 *
 * The "first import/export element address" is the address of the first
 * medium portal accessible both by the medium changer and an outside
 * human operator.  This is where the changer might deposit tapes destined
 * for some vault.  The "number of import/export elements" tells us
 * not many of these portals exist in the changer.  NOTE: this number may
 * be 0.
 *
 * The "first data transfer element address" is the address of the first
 * tape or disk drive in the changer.  "Number of data transfer elements"
 * tells us how many drives exist in the changer.
 */
struct page_element_address_assignment {
	u_int8_t	pg_code;	/* page code (0x1d) */
	u_int8_t	pg_length;	/* page length (0x12) */

	/* Medium transport element address */
	u_int8_t	mtea[2];

	/* Number of medium transport elements */
	u_int8_t	nmte[2];

	/* First storage element address */
	u_int8_t	fsea[2];

	/* Number of storage elements */
	u_int8_t	nse[2];

	/* First import/export element address */
	u_int8_t	fieea[2];

	/* Number of import/export elements */
	u_int8_t	niee[2];

	/* First data transfer element address */
	u_int8_t	fdtea[2];

	/* Number of data trafer elements */
	u_int8_t	ndte[2];

	u_int8_t	reserved[2];
};

/*
 * Transport geometry parameters page.
 *
 * Defines whether each medium transport element is a member of a set of
 * elements that share a common robotics subsystem and whether the element
 * is capable of media rotation.  One transport geometry descriptor is
 * transferred for each medium transport element, beginning with the first
 * medium transport element (other than the default transport element address
 * of 0).
 */
struct page_transport_geometry_parameters {
	u_int8_t	pg_code;	/* page code (0x1e) */
	u_int8_t	pg_length;	/* page length; variable */

	/* Transport geometry descriptor(s) are here. */

	u_int8_t	misc;
#define CAN_ROTATE	0x01

	/* Member number in transport element set. */
	u_int8_t	member;
};

__BEGIN_DECLS
void scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries,
		      void (*cbfcnp)(struct cam_periph *, union ccb *),
		      u_int8_t tag_action, u_int32_t tea, u_int32_t src,
		      u_int32_t dst, int invert, u_int8_t sense_len,
		      u_int32_t timeout);

void scsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries,
			  void (*cbfcnp)(struct cam_periph *, union ccb *),
			  u_int8_t tag_action, u_int32_t tea, u_int32_t src,
			  u_int32_t dst1, u_int32_t dst2, int invert1,
			  int invert2, u_int8_t sense_len, u_int32_t timeout);

void scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries,
			      void (*cbfcnp)(struct cam_periph *, union ccb *),
			      u_int8_t tag_action, u_int32_t tea, u_int32_t dst,
			      int invert, u_int8_t sense_len,
			      u_int32_t timeout);

void scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries,
			      void (*cbfcnp)(struct cam_periph *, union ccb *),
			      u_int8_t tag_action, int voltag, u_int32_t sea,
			      u_int32_t count, u_int8_t *data_ptr,
			      u_int32_t dxfer_len, u_int8_t sense_len,
			      u_int32_t timeout);

void scsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries,
			       void (*cbfcnp)(struct cam_periph *, union ccb *),
			       u_int8_t tag_action, u_int8_t sense_len,
			       u_int32_t timeout);
void scsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries,
			  void (*cbfcnp)(struct cam_periph *, union ccb *),
			  u_int8_t tag_action,
			  u_int16_t element_address,
			  u_int8_t send_action_code,
			  struct scsi_send_volume_tag_parameters *parameters,
			  u_int8_t sense_len, u_int32_t timeout);
__END_DECLS

#endif /* _SCSI_SCSI_CH_H */

repo_name: veiledmerc/mira

license: mit


code:
/*
 * Structures and definitions for SCSI commands to Direct Access Devices
 */

/*-
 * Some lines of this file come from a file of the name "scsi.h"
 * distributed by OSF as part of mach2.5,
 *  so the following disclaimer has been kept.
 *
 * Copyright 1990 by Open Software Foundation,
 * Grenoble, FRANCE
 *
 * 		All Rights Reserved
 *
 *   Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appears in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation, and that the name of OSF or Open Software
 * Foundation not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior
 * permission.
 *
 *   OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*-
 * Largely written by Julian Elischer (julian@tfs.com)
 * for TRW Financial Systems.
 *
 * TRW Financial Systems, in accordance with their agreement with Carnegie
 * Mellon University, makes this software available to CMU to distribute
 * or use in any manner that they see fit as long as this message is kept with
 * the software. For this reason TFS also grants any other persons or
 * organisations permission to use or modify this software.
 *
 * TFS supplies this software to be publicly redistributed
 * on the understanding that TFS is not responsible for the correct
 * functioning of this software in any circumstances.
 *
 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
 *
 * $FreeBSD: release/9.0.0/sys/cam/scsi/scsi_da.h 139743 2005-01-05 22:34:37Z imp $
 */

#ifndef	_SCSI_SCSI_DA_H
#define _SCSI_SCSI_DA_H 1

#include <sys/cdefs.h>

struct scsi_rezero_unit
{
	u_int8_t opcode;
#define SRZU_LUN_MASK 0xE0
	u_int8_t byte2;
	u_int8_t reserved[3];
	u_int8_t control;
};

/*
 * NOTE:  The lower three bits of byte2 of the format CDB are the same as
 * the lower three bits of byte2 of the read defect data CDB, below.
 */
struct scsi_format_unit
{
	u_int8_t opcode;
	u_int8_t byte2;
#define FU_FORMAT_MASK	SRDD10_DLIST_FORMAT_MASK
#define FU_BLOCK_FORMAT	SRDD10_BLOCK_FORMAT
#define FU_BFI_FORMAT	SRDD10_BYTES_FROM_INDEX_FORMAT
#define FU_PHYS_FORMAT	SRDD10_PHYSICAL_SECTOR_FORMAT
#define FU_CMPLST	0x08
#define FU_FMT_DATA	0x10
	u_int8_t vendor_specific;
	u_int8_t interleave[2];
	u_int8_t control;
};

struct scsi_reassign_blocks
{
	u_int8_t opcode;
	u_int8_t byte2;
	u_int8_t unused[3];
	u_int8_t control;
};

struct scsi_read_defect_data_10
{
	u_int8_t opcode;

	/*
	 * The most significant 3 bits are the LUN, the other 5 are
	 * reserved.
	 */
#define SRDD10_LUN_MASK 0xE0
	u_int8_t byte2;
#define SRDD10_GLIST 0x08
#define SRDD10_PLIST 0x10
#define SRDD10_DLIST_FORMAT_MASK 0x07
#define SRDD10_BLOCK_FORMAT            0x00
#define SRDD10_BYTES_FROM_INDEX_FORMAT 0x04
#define SRDD10_PHYSICAL_SECTOR_FORMAT  0x05
	u_int8_t format;

	u_int8_t reserved[4];

	u_int8_t alloc_length[2];

	u_int8_t control;
};

struct scsi_read_defect_data_12
{
	u_int8_t opcode;

	/*
	 * The most significant 3 bits are the LUN, the other 5 are
	 * reserved.
	 */
#define SRDD12_LUN_MASK 0xE0
	u_int8_t byte2;

#define SRDD12_GLIST 0x08
#define SRDD12_PLIST 0x10
#define SRDD12_DLIST_FORMAT_MASK 0x07
#define SRDD12_BLOCK_FORMAT            0x00
#define SRDD12_BYTES_FROM_INDEX_FORMAT 0x04
#define SRDD12_PHYSICAL_SECTOR_FORMAT  0x05
	u_int8_t format;

	u_int8_t reserved[4];

	u_int8_t alloc_length[4];

	u_int8_t control;

};

/*
 * Opcodes
 */
#define REZERO_UNIT		0x01
#define FORMAT_UNIT		0x04
#define	REASSIGN_BLOCKS		0x07
#define MODE_SELECT		0x15
#define MODE_SENSE		0x1a
#define	READ_FORMAT_CAPACITIES	0x23
#define	WRITE_AND_VERIFY	0x2e
#define	VERIFY			0x2f
#define READ_DEFECT_DATA_10	0x37
#define READ_DEFECT_DATA_12	0xb7

struct format_defect_list_header
{
	u_int8_t reserved;
	u_int8_t byte2;
#define FU_DLH_VS	0x01
#define FU_DLH_IMMED	0x02
#define FU_DLH_DSP	0x04
#define FU_DLH_IP	0x08
#define FU_DLH_STPF	0x10
#define FU_DLH_DCRT	0x20
#define FU_DLH_DPRY	0x40
#define FU_DLH_FOV	0x80
	u_int8_t defect_list_length[2];
};

struct format_ipat_descriptor
{
	u_int8_t byte1;
#define	FU_INIT_NO_HDR		0x00
#define FU_INIT_LBA_MSB		0x40
#define FU_INIT_LBA_EACH	0x80
#define FU_INIT_SI		0x20
	u_int8_t pattern_type;
#define FU_INIT_PAT_DEFAULT	0x00
#define FU_INIT_PAT_REPEAT	0x01
	u_int8_t pat_length[2];
};

struct scsi_read_format_capacities
{
	uint8_t	opcode;		/* READ_FORMAT_CAPACITIES */
	uint8_t	byte2;
#define	SRFC_LUN_MASK	0xE0
	uint8_t	reserved0[5];
	uint8_t	alloc_length[2];
	uint8_t	reserved1[3];
};

struct scsi_verify
{
	uint8_t	opcode;		/* VERIFY */
	uint8_t	byte2;
#define	SVFY_LUN_MASK	0xE0
#define	SVFY_RELADR	0x01
#define	SVFY_BYTECHK	0x02
#define	SVFY_DPO	0x10
	uint8_t	addr[4];	/* LBA to begin verification at */
	uint8_t	reserved0[1];
	uint8_t	len[2];		/* number of blocks to verify */
	uint8_t	reserved1[3];
};

struct scsi_write_and_verify
{
	uint8_t	opcode;		/* WRITE_AND_VERIFY */
	uint8_t	byte2;
#define	SWVY_LUN_MASK	0xE0
#define	SWVY_RELADR	0x01
#define	SWVY_BYTECHK	0x02
#define	SWVY_DPO	0x10
	uint8_t	addr[4];	/* LBA to begin verification at */
	uint8_t	reserved0[1];
	uint8_t	len[2];		/* number of blocks to write and verify */
	uint8_t	reserved1[3];
};

/*
 * Replies to READ_FORMAT_CAPACITIES look like this:
 *
 * struct format_capacity_list_header
 * struct format_capacity_descriptor[1..n]
 *
 * These are similar, but not totally identical to, the
 * defect list used to format a rigid disk.
 *
 * The appropriate csio_decode() format string looks like this:
 * "{} *i3 {Len} i1 {Blocks} i4 {} *b6 {Code} b2 {Blocklen} i3"
 *
 * If the capacity_list_length is greater than
 * sizeof(struct format_capacity_descriptor), then there are
 * additional format capacity descriptors available which
 * denote which format(s) the drive can handle.
 *
 * (Source: USB Mass Storage UFI Specification)
 */

struct format_capacity_list_header {
	uint8_t	unused[3];
	uint8_t	capacity_list_length;
};

struct format_capacity_descriptor {
	uint8_t	nblocks[4];	/* total number of LBAs */
	uint8_t	byte4;		/* only present in max/cur descriptor */
#define FCD_CODE_MASK	0x03	/* mask for code field above */
#define FCD_UNFORMATTED	0x01	/* unformatted media present,
				 * maximum capacity returned */
#define FCD_FORMATTED	0x02	/* formatted media present,
				 * current capacity returned */
#define FCD_NOMEDIA	0x03	/* no media present,
				 * maximum device capacity returned */
	uint8_t	block_length[3];	/* length of an LBA in bytes */
};

struct scsi_reassign_blocks_data
{
	u_int8_t reserved[2];
	u_int8_t length[2];
	struct {
		u_int8_t dlbaddr[4];	/* defect logical block address */
	} defect_descriptor[1];
};

/*
 * This is the list header for the READ DEFECT DATA(10) command above.
 * It may be a bit wrong to append the 10 at the end of the data structure,
 * since it's only 4 bytes but it does tie it to the 10 byte command.
 */
struct scsi_read_defect_data_hdr_10
{
	u_int8_t reserved;
#define SRDDH10_GLIST 0x08
#define SRDDH10_PLIST 0x10
#define SRDDH10_DLIST_FORMAT_MASK 0x07
#define SRDDH10_BLOCK_FORMAT            0x00
#define SRDDH10_BYTES_FROM_INDEX_FORMAT 0x04
#define SRDDH10_PHYSICAL_SECTOR_FORMAT  0x05
	u_int8_t format;
	u_int8_t length[2];
};

struct scsi_defect_desc_block
{
	u_int8_t address[4];
};

struct scsi_defect_desc_bytes_from_index
{
	u_int8_t cylinder[3];
	u_int8_t head;
	u_int8_t bytes_from_index[4];
};

struct scsi_defect_desc_phys_sector
{
	u_int8_t cylinder[3];
	u_int8_t head;
	u_int8_t sector[4];
};

struct scsi_read_defect_data_hdr_12
{
	u_int8_t reserved;
#define SRDDH12_GLIST 0x08
#define SRDDH12_PLIST 0x10
#define SRDDH12_DLIST_FORMAT_MASK 0x07
#define SRDDH12_BLOCK_FORMAT            0x00
#define SRDDH12_BYTES_FROM_INDEX_FORMAT 0x04
#define SRDDH12_PHYSICAL_SECTOR_FORMAT  0x05
	u_int8_t format;
	u_int8_t length[4];
};

union	disk_pages /* this is the structure copied from osf */
{
	struct format_device_page {
		u_int8_t pg_code;	/* page code (should be 3)	      */
#define	SMS_FORMAT_DEVICE_PAGE	0x03	/* only 6 bits valid */
		u_int8_t pg_length;	/* page length (should be 0x16)	      */
#define	SMS_FORMAT_DEVICE_PLEN	0x16
		u_int8_t trk_z_1;	/* tracks per zone (MSB)	      */
		u_int8_t trk_z_0;	/* tracks per zone (LSB)	      */
		u_int8_t alt_sec_1;	/* alternate sectors per zone (MSB)   */
		u_int8_t alt_sec_0;	/* alternate sectors per zone (LSB)   */
		u_int8_t alt_trk_z_1;	/* alternate tracks per zone (MSB)    */
		u_int8_t alt_trk_z_0;	/* alternate tracks per zone (LSB)    */
		u_int8_t alt_trk_v_1;	/* alternate tracks per volume (MSB)  */
		u_int8_t alt_trk_v_0;	/* alternate tracks per volume (LSB)  */
		u_int8_t ph_sec_t_1;	/* physical sectors per track (MSB)   */
		u_int8_t ph_sec_t_0;	/* physical sectors per track (LSB)   */
		u_int8_t bytes_s_1;	/* bytes per sector (MSB)	      */
		u_int8_t bytes_s_0;	/* bytes per sector (LSB)	      */
		u_int8_t interleave_1;	/* interleave (MSB)		      */
		u_int8_t interleave_0;	/* interleave (LSB)		      */
		u_int8_t trk_skew_1;	/* track skew factor (MSB)	      */
		u_int8_t trk_skew_0;	/* track skew factor (LSB)	      */
		u_int8_t cyl_skew_1;	/* cylinder skew (MSB)		      */
		u_int8_t cyl_skew_0;	/* cylinder skew (LSB)		      */
		u_int8_t flags;		/* various */
#define			DISK_FMT_SURF	0x10
#define	       		DISK_FMT_RMB	0x20
#define			DISK_FMT_HSEC	0x40
#define			DISK_FMT_SSEC	0x80
		u_int8_t reserved21;
		u_int8_t reserved22;
		u_int8_t reserved23;
	} format_device;
	struct rigid_geometry_page {
		u_int8_t pg_code;	/* page code (should be 4)	      */
#define SMS_RIGID_GEOMETRY_PAGE 0x04
		u_int8_t pg_length;	/* page length (should be 0x16)	      */
#define SMS_RIGID_GEOMETRY_PLEN 0x16
		u_int8_t ncyl_2;	/* number of cylinders (MSB)	      */
		u_int8_t ncyl_1;	/* number of cylinders 		      */
		u_int8_t ncyl_0;	/* number of cylinders (LSB)	      */
		u_int8_t nheads;	/* number of heads 		      */
		u_int8_t st_cyl_wp_2;	/* starting cyl., write precomp (MSB) */
		u_int8_t st_cyl_wp_1;	/* starting cyl., write precomp	      */
		u_int8_t st_cyl_wp_0;	/* starting cyl., write precomp (LSB) */
		u_int8_t st_cyl_rwc_2;	/* starting cyl., red. write cur (MSB)*/
		u_int8_t st_cyl_rwc_1;	/* starting cyl., red. write cur      */
		u_int8_t st_cyl_rwc_0;	/* starting cyl., red. write cur (LSB)*/
		u_int8_t driv_step_1;	/* drive step rate (MSB)	      */
		u_int8_t driv_step_0;	/* drive step rate (LSB)	      */
		u_int8_t land_zone_2;	/* landing zone cylinder (MSB)	      */
		u_int8_t land_zone_1;	/* landing zone cylinder 	      */
		u_int8_t land_zone_0;	/* landing zone cylinder (LSB)	      */
		u_int8_t rpl;		/* rotational position locking (2 bits) */
		u_int8_t rot_offset;	/* rotational offset */
		u_int8_t reserved19;
		u_int8_t medium_rot_rate_1; /* medium rotation rate (RPM) (MSB) */
		u_int8_t medium_rot_rate_0; /* medium rotation rate (RPM) (LSB) */
		u_int8_t reserved22;
		u_int8_t reserved23;
    	} rigid_geometry;
	struct flexible_disk_page {
		u_int8_t pg_code;	/* page code (should be 5)	      */
#define SMS_FLEXIBLE_GEOMETRY_PAGE 0x05
		u_int8_t pg_length;	/* page length (should be 0x1E)	      */
#define SMS_FLEXIBLE_GEOMETRY_PLEN 0x1E
		u_int8_t xfr_rate_1;	/* transfer rate (MSB)		      */
		u_int8_t xfr_rate_0;	/* transfer rate (LSB)		      */
		u_int8_t nheads;	/* number of heads 		      */
		u_int8_t sec_per_track;	/* Sectors per track		      */
		u_int8_t bytes_s_1;	/* bytes per sector (MSB)	      */
		u_int8_t bytes_s_0;	/* bytes per sector (LSB)	      */
		u_int8_t ncyl_1;	/* number of cylinders (MSB)	      */
		u_int8_t ncyl_0;	/* number of cylinders (LSB)	      */
		u_int8_t st_cyl_wp_1;	/* starting cyl., write precomp (MSB) */
		u_int8_t st_cyl_wp_0;	/* starting cyl., write precomp (LSB) */
		u_int8_t st_cyl_rwc_1;	/* starting cyl., red. write cur (MSB)*/
		u_int8_t st_cyl_rwc_0;	/* starting cyl., red. write cur (LSB)*/
		u_int8_t driv_step_1;	/* drive step rate (MSB)	      */
		u_int8_t driv_step_0;	/* drive step rate (LSB)	      */
		u_int8_t driv_step_pw;	/* drive step pulse width	      */
		u_int8_t head_stl_del_1;/* Head settle delay (MSB)	      */
		u_int8_t head_stl_del_0;/* Head settle delay (LSB)	      */
		u_int8_t motor_on_del;	/* Motor on delay		      */
		u_int8_t motor_off_del;	/* Motor off delay		      */
		u_int8_t trdy_ssn_mo;	/* XXX ??? */
		u_int8_t spc;		/* XXX ??? */
		u_int8_t write_comp;	/* Write compensation */
		u_int8_t head_load_del; /* Head load delay */
		u_int8_t head_uload_del;/* Head un-load delay */
		u_int8_t pin32_pin2;
		u_int8_t pin4_pint1;
		u_int8_t medium_rot_rate_1; /* medium rotation rate (RPM) (MSB) */
		u_int8_t medium_rot_rate_0; /* medium rotation rate (RPM) (LSB) */
		u_int8_t reserved30;
		u_int8_t reserved31;
    	} flexible_disk;
};

struct scsi_da_rw_recovery_page {
	u_int8_t page_code;
#define SMS_RW_ERROR_RECOVERY_PAGE	0x01
	u_int8_t page_length;
	u_int8_t byte3;
#define SMS_RWER_AWRE			0x80
#define SMS_RWER_ARRE			0x40
#define SMS_RWER_TB			0x20
#define SMS_RWER_RC			0x10
#define SMS_RWER_EER			0x08
#define SMS_RWER_PER			0x04
#define SMS_RWER_DTE			0x02
#define SMS_RWER_DCR			0x01
	u_int8_t read_retry_count;
	u_int8_t correction_span;
	u_int8_t head_offset_count;
	u_int8_t data_strobe_offset_cnt;
	u_int8_t reserved;
	u_int8_t write_retry_count;
	u_int8_t reserved2;
	u_int8_t recovery_time_limit[2];
};

__BEGIN_DECLS
/*
 * XXX This is only left out of the kernel build to silence warnings.  If,
 * for some reason this function is used in the kernel, the ifdefs should
 * be moved so it is included both in the kernel and userland.
 */
#ifndef _KERNEL
void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries,
		      void (*cbfcnp)(struct cam_periph *, union ccb *),
		      u_int8_t tag_action, u_int8_t byte2, u_int16_t ileave,
		      u_int8_t *data_ptr, u_int32_t dxfer_len,
		      u_int8_t sense_len, u_int32_t timeout);

#endif /* !_KERNEL */
__END_DECLS

#endif /* _SCSI_SCSI_DA_H */


code:
/*	$FreeBSD: release/9.0.0/sys/cam/scsi/scsi_dvcfg.h 139743 2005-01-05 22:34:37Z imp $	*/
/*	$NecBSD: scsi_dvcfg.h,v 1.4 1998/03/14 07:05:06 kmatsuda Exp $	*/
/*	$NetBSD$	*/

/*-
 * [NetBSD for NEC PC-98 series]
 *  Copyright (c) 1994, 1995, 1996, 1997, 1998
 *	NetBSD/pc98 porting staff. All rights reserved.
 *  Copyright (c) 1994, 1995, 1996, 1997, 1998
 *	Naofumi HONDA. 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, 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.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
 */

#ifndef	_SCSI_DVCFG_H_
#define	_SCSI_DVCFG_H_

/* common dvcfg flags defitions for bs, ncv, stg */

#define	DVF_SCSI_SYNC		0x01
#define	DVF_SCSI_DISC		0x02
#define	DVF_SCSI_WAIT		0x04
#define	DVF_SCSI_LINK		0x08
#define	DVF_SCSI_QTAG		0x10
#define	DVF_SCSI_SP0		0x100
#define	DVF_SCSI_NOPARITY	0x200
#define	DVF_SCSI_SAVESP		0x400
#define	DVF_SCSI_SP1		0x800
#define	DVF_SCSI_PERIOD(XXX)	(((XXX) >> 24) & 0xff)
#define	DVF_SCSI_OFFSET(XXX)	(((XXX) >> 16) & 0xff)
#define DVF_SCSI_SYNCMASK	0xffff0000

#define	DVF_SCSI_DEFCFG	(DVF_SCSI_SYNC | DVF_SCSI_NOPARITY | DVF_SCSI_SYNCMASK)

#define	DVF_SCSI_BITS		"\020\13fssp\12noparity\11nosat\005qtag\004cmdlnk\003wait\002disc\001sync"

#endif	/* !_SCSI_DVCFG_H_ */


code:
/*-
 * This file is in the public domain.
 * $FreeBSD: release/9.0.0/sys/cam/scsi/scsi_iu.h 139743 2005-01-05 22:34:37Z imp $
 */
#ifndef	_SCSI_SCSI_IU_H
#define _SCSI_SCSI_IU_H 1

struct scsi_status_iu_header
{
	u_int8_t reserved[2];
	u_int8_t flags;
#define	SIU_SNSVALID 0x2
#define	SIU_RSPVALID 0x1
	u_int8_t status;
	u_int8_t sense_length[4];
	u_int8_t pkt_failures_length[4];
	u_int8_t pkt_failures[1];
};

#define SIU_PKTFAIL_OFFSET(siu) 12
#define SIU_PKTFAIL_CODE(siu) (scsi_4btoul((siu)->pkt_failures) & 0xFF)
#define		SIU_PFC_NONE			0
#define		SIU_PFC_CIU_FIELDS_INVALID	2
#define		SIU_PFC_TMF_NOT_SUPPORTED	4
#define		SIU_PFC_TMF_FAILED		5
#define		SIU_PFC_INVALID_TYPE_CODE	6
#define		SIU_PFC_ILLEGAL_REQUEST		7
#define SIU_SENSE_OFFSET(siu)				\
    (12 + (((siu)->flags & SIU_RSPVALID)		\
	? scsi_4btoul((siu)->pkt_failures_length)	\
	: 0))

#define	SIU_TASKMGMT_NONE		0x00
#define	SIU_TASKMGMT_ABORT_TASK		0x01
#define	SIU_TASKMGMT_ABORT_TASK_SET	0x02
#define	SIU_TASKMGMT_CLEAR_TASK_SET	0x04
#define	SIU_TASKMGMT_LUN_RESET		0x08
#define	SIU_TASKMGMT_TARGET_RESET	0x20
#define	SIU_TASKMGMT_CLEAR_ACA		0x40
#endif /*_SCSI_SCSI_IU_H*/


code:
/*	$FreeBSD: release/9.0.0/sys/cam/scsi/scsi_low.h 174898 2007-12-25 17:52:02Z rwatson $	*/
/*	$NecBSD: scsi_low.h,v 1.24.10.5 2001/06/26 07:31:46 honda Exp $	*/
/*	$NetBSD$	*/

#define	SCSI_LOW_DIAGNOSTIC
#define	SCSI_LOW_ALT_QTAG_ALLOCATE

/*-
 * [NetBSD for NEC PC-98 series]
 *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
 *	NetBSD/pc98 porting staff. All rights reserved.
 *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
 *	Naofumi HONDA. All rights reserved.
 *
 * [Ported for FreeBSD CAM]
 *  Copyright (c) 2000, 2001
 *      MITSUNAGA Noriaki, NOKUBI Hirotaka and TAKAHASHI Yoshihiro.
 *      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, 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.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
 */

#ifndef	_SCSI_LOW_H_
#define	_SCSI_LOW_H_

/*================================================
 * Scsi low OSDEP
 * (All os depend structures should be here!)
 ================================================*/
/******** interface ******************************/
#ifdef	__NetBSD__
#define	SCSI_LOW_INTERFACE_XS
#endif	/* __NetBSD__ */

#ifdef	__FreeBSD__
#define	SCSI_LOW_INTERFACE_CAM
#define	CAM
#endif	/* __FreeBSD__ */

/******** includes *******************************/
#ifdef	__NetBSD__
#include <i386/Cbus/dev/scsi_dvcfg.h>
#include <dev/isa/ccbque.h>
#endif	/* __NetBSD__ */

#ifdef	__FreeBSD__
#include <sys/device_port.h>
#include <sys/kdb.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_debug.h>

#include <cam/scsi/scsi_dvcfg.h>
#include <i386/isa/ccbque.h>
#endif	/* __FreeBSD__ */

/******** functions macro ************************/
#ifdef	__NetBSD__
#define	SCSI_LOW_DEBUGGER(dev)	Debugger()
#define	SCSI_LOW_DELAY(mu)	delay((mu))
#define	SCSI_LOW_SPLSCSI	splbio
#define	SCSI_LOW_BZERO(pt, size)	memset((pt), 0, (size))
#endif	/* __NetBSD__ */

#ifdef	__FreeBSD__
#undef	MSG_IDENTIFY
#define	SCSI_LOW_DEBUGGER(dev)	kdb_enter(KDB_WHY_CAM, dev)
#define	SCSI_LOW_DELAY(mu)	DELAY((mu))
#define	SCSI_LOW_SPLSCSI	splcam
#define	SCSI_LOW_BZERO(pt, size)	bzero((pt), (size))
#endif	/* __FreeBSD__ */

/******** os depend interface structures **********/
#ifdef	__NetBSD__
typedef	struct scsipi_sense_data scsi_low_osdep_sense_data_t;

struct scsi_low_osdep_interface {
	struct device si_dev;

	struct scsipi_link *si_splp;
};

struct scsi_low_osdep_targ_interface {
};

struct scsi_low_osdep_lun_interface {
	u_int sloi_quirks;
};
#endif	/* __NetBSD__ */

#ifdef	__FreeBSD__
typedef	struct scsi_sense_data scsi_low_osdep_sense_data_t;

struct scsi_low_osdep_interface {
	DEVPORT_DEVICE si_dev;

	struct cam_sim *sim;
	struct cam_path *path;

	int si_poll_count;

	struct callout_handle engage_ch;
	struct callout_handle timeout_ch;
#ifdef	SCSI_LOW_POWFUNC
	struct callout_handle recover_ch;
#endif
};

struct scsi_low_osdep_targ_interface {
};

struct scsi_low_osdep_lun_interface {
};
#endif	/* __FreeBSD__ */

/******** os depend interface functions *************/
struct slccb;
struct scsi_low_softc;
#define	SCSI_LOW_TIMEOUT_STOP		0
#define	SCSI_LOW_TIMEOUT_START		1
#define	SCSI_LOW_TIMEOUT_CH_IO		0
#define	SCSI_LOW_TIMEOUT_CH_ENGAGE	1
#define	SCSI_LOW_TIMEOUT_CH_RECOVER	2

struct scsi_low_osdep_funcs {
	int (*scsi_low_osdep_attach) \
			(struct scsi_low_softc *);
	int (*scsi_low_osdep_world_start) \
			(struct scsi_low_softc *);
	int (*scsi_low_osdep_dettach) \
			(struct scsi_low_softc *);
	int (*scsi_low_osdep_ccb_setup) \
			(struct scsi_low_softc *, struct slccb *);
	int (*scsi_low_osdep_done) \
			(struct scsi_low_softc *, struct slccb *);
	void (*scsi_low_osdep_timeout) \
			(struct scsi_low_softc *, int, int);
};

/*================================================
 * Generic Scsi Low header file
 * (All os depend structures should be above!)
 ================================================*/
/*************************************************
 * Scsi low definitions
 *************************************************/
#define	SCSI_LOW_SYNC		DVF_SCSI_SYNC
#define	SCSI_LOW_DISC		DVF_SCSI_DISC
#define	SCSI_LOW_WAIT		DVF_SCSI_WAIT
#define	SCSI_LOW_LINK		DVF_SCSI_LINK
#define	SCSI_LOW_QTAG		DVF_SCSI_QTAG
#define	SCSI_LOW_NOPARITY	DVF_SCSI_NOPARITY
#define	SCSI_LOW_SAVESP		DVF_SCSI_SAVESP
#define	SCSI_LOW_DEFCFG		DVF_SCSI_DEFCFG
#define	SCSI_LOW_BITS		DVF_SCSI_BITS

#define	SCSI_LOW_PERIOD(n)	DVF_SCSI_PERIOD(n)
#define	SCSI_LOW_OFFSET(n)	DVF_SCSI_OFFSET(n)

/* host scsi id and targets macro */
#ifndef	SCSI_LOW_NTARGETS
#define	SCSI_LOW_NTARGETS			8
#endif	/* SCSI_LOW_NTARGETS */
#define	SCSI_LOW_NCCB				128

#define	SCSI_LOW_MAX_RETRY			3
#define	SCSI_LOW_MAX_SELECTION_RETRY		10

/* timeout control macro */
#define	SCSI_LOW_TIMEOUT_HZ			10
#define SCSI_LOW_MIN_TOUT			12
#define SCSI_LOW_TIMEOUT_CHECK_INTERVAL 	1
#define	SCSI_LOW_POWDOWN_TC			15
#define	SCSI_LOW_MAX_PHCHANGES			256
#define	SCSI2_RESET_DELAY			5000000

/* msg */
#define	SCSI_LOW_MAX_MSGLEN			32
#define	SCSI_LOW_MSG_LOG_DATALEN  		8

/*************************************************
 * Scsi Data Pointer
 *************************************************/
/* scsi pointer */
struct sc_p {
	u_int8_t *scp_data;
	int scp_datalen;

	u_int8_t *scp_cmd;
	int scp_cmdlen;

	u_int8_t scp_direction;
#define	SCSI_LOW_RWUNK	(-1)
#define	SCSI_LOW_WRITE	0
#define	SCSI_LOW_READ	1
	u_int8_t scp_status;
	u_int8_t scp_spare[2];
};

/*************************************************
 * Command Control Block Structure
 *************************************************/
typedef int scsi_low_tag_t;
struct targ_info;

#define	SCSI_LOW_UNKLUN	((u_int) -1)
#define	SCSI_LOW_UNKTAG	((scsi_low_tag_t) -1)

struct slccb {
	TAILQ_ENTRY(slccb) ccb_chain;

	void *osdep;			/* os depend structure */

	struct targ_info *ti;		/* targ_info */
	struct lun_info *li;		/* lun info */
	struct buf *bp;			/* io bufs */

	scsi_low_tag_t ccb_tag;		/* effective qtag */
	scsi_low_tag_t ccb_otag;	/* allocated qtag */

	/*****************************************
	 * Scsi data pointers (original and saved)
	 *****************************************/
	struct sc_p ccb_scp;		/* given */
	struct sc_p ccb_sscp;		/* saved scsi data pointer */
	int ccb_datalen;		/* transfered data counter */

	/*****************************************
	 * Msgout
	 *****************************************/
	u_int ccb_msgoutflag;
	u_int ccb_omsgoutflag;

	/*****************************************
	 * Error or Timeout counters
	 *****************************************/
	u_int ccb_flags;
#define	CCB_INTERNAL	0x0001
#define	CCB_SENSE	0x0002
#define	CCB_CLEARQ	0x0004
#define	CCB_DISCQ	0x0008
#define	CCB_STARTQ	0x0010
#define	CCB_POLLED	0x0100	/* polling ccb */
#define	CCB_NORETRY	0x0200	/* do NOT retry */
#define	CCB_AUTOSENSE	0x0400	/* do a sence after CA */
#define	CCB_URGENT	0x0800	/* an urgent ccb */
#define	CCB_NOSDONE	0x1000	/* do not call an os done routine */
#define	CCB_SCSIIO	0x2000	/* a normal scsi io coming from upper layer */
#define	CCB_SILENT	0x4000	/* no terminate messages */

	u_int ccb_error;

	int ccb_rcnt;			/* retry counter */
	int ccb_selrcnt;		/* selection retry counter */
	int ccb_tc;			/* timer counter */
	int ccb_tcmax;			/* max timeout */

	/*****************************************
	 * Sense data buffer
	 *****************************************/
	u_int8_t ccb_scsi_cmd[12];
	scsi_low_osdep_sense_data_t ccb_sense;
};

/*************************************************
 * Slccb functions
 *************************************************/
GENERIC_CCB_ASSERT(scsi_low, slccb)

/*************************************************
 * Target and Lun structures
 *************************************************/
struct scsi_low_softc;
LIST_HEAD(scsi_low_softc_tab, scsi_low_softc);
TAILQ_HEAD(targ_info_tab, targ_info);
LIST_HEAD(lun_info_tab, lun_info);

struct lun_info {
	struct scsi_low_osdep_lun_interface li_sloi;

	int li_lun;
	struct targ_info *li_ti;		/* my target */

	LIST_ENTRY(lun_info) lun_chain;		/* targ_info link */

	struct slccbtab li_discq;			/* disconnect queue */

	/*
	 * qtag control
	 */
	int li_maxnexus;
	int li_maxnqio;
	int li_nqio;
	int li_disc;

#define	SCSI_LOW_MAXNEXUS (sizeof(u_int) * NBBY)
	u_int li_qtagbits;

#ifdef	SCSI_LOW_ALT_QTAG_ALLOCATE
	u_int8_t li_qtagarray[SCSI_LOW_MAXNEXUS];
	u_int li_qd;
#endif	/* SCSI_LOW_ALT_QTAG_ALLOCATE */

#define	SCSI_LOW_QFLAG_CA_QCLEAR	0x01
	u_int li_qflags;

	/*
	 * lun state
	 */
#define	SCSI_LOW_LUN_SLEEP	0x00
#define	SCSI_LOW_LUN_START	0x01
#define	SCSI_LOW_LUN_INQ	0x02
#define	SCSI_LOW_LUN_MODEQ	0x03
#define	SCSI_LOW_LUN_OK		0x04
	u_int li_state;				/* target lun state */

	/*
	 * lun control flags
 	 */
	u_int li_flags_valid;	/* valid flags */
#define	SCSI_LOW_LUN_FLAGS_USER_VALID	0x0001
#define	SCSI_LOW_LUN_FLAGS_DISK_VALID	0x0002
#define	SCSI_LOW_LUN_FLAGS_QUIRKS_VALID	0x0004
#define	SCSI_LOW_LUN_FLAGS_ALL_VALID \
	(SCSI_LOW_LUN_FLAGS_USER_VALID | \
	 SCSI_LOW_LUN_FLAGS_DISK_VALID | SCSI_LOW_LUN_FLAGS_QUIRKS_VALID)

	u_int li_flags;		/* real lun control flags */
	u_int li_cfgflags;	/* lun control flags given by user */
	u_int li_diskflags;	/* lun control flags given by hardware info */
	u_int li_quirks;	/* lun control flags given by upper layer */

	/* inq buffer */
	struct scsi_low_inq_data {
		u_int8_t sd_type;
		u_int8_t sd_sp1;
		u_int8_t sd_version;
		u_int8_t sd_resp;
		u_int8_t sd_len;
		u_int8_t sd_sp2[2];
		u_int8_t sd_support;
	} __packed li_inq;

	/* modeq buffer */
	struct scsi_low_mode_sense_data {
		u_int8_t sms_header[4];
		struct {
			u_int8_t cmp_page;
			u_int8_t cmp_length;
			u_int8_t cmp_rlec;
			u_int8_t cmp_qc;
			u_int8_t cmp_eca;
			u_int8_t cmp_spare[3];
		} __packed sms_cmp;

	} li_sms;
};

struct scsi_low_msg_log {
	int slml_ptr;
	struct {
		u_int8_t msg[2];
	} slml_msg[SCSI_LOW_MSG_LOG_DATALEN];
};

struct targ_info {
	struct scsi_low_osdep_targ_interface ti_slti;

	TAILQ_ENTRY(targ_info) ti_chain;	/* targ_info link */

	struct scsi_low_softc *ti_sc;		/* our softc */
	u_int ti_id;				/* scsi id */

	/*
	 * Lun chain
	 */
	struct lun_info_tab ti_litab;		/* lun chain */

	/*
	 * total disconnected nexus
	 */
	int ti_disc;

	/*
	 * Scsi phase control
 	 */

#define	PH_NULL		0x00
#define	PH_ARBSTART	0x01
#define	PH_SELSTART	0x02
#define	PH_SELECTED	0x03
#define	PH_CMD		0x04
#define	PH_DATA		0x05
#define	PH_MSGIN	0x06
#define	PH_MSGOUT	0x07
#define	PH_STAT		0x08
#define	PH_DISC		0x09
#define	PH_RESEL	0x0a
	u_int ti_phase;				/* scsi phase */
	u_int ti_ophase;			/* old scsi phase */

	/*
	 * Msg in
 	 */
	u_int ti_msginptr;			/* msgin ptr */
	u_int ti_msginlen;			/* expected msg length */
	int ti_msgin_parity_error;		/* parity error detected */
	u_int8_t ti_msgin[SCSI_LOW_MAX_MSGLEN];	/* msgin buffer */

	/*
	 * Msg out
 	 */
	u_int ti_msgflags;			/* msgs to be asserted */
	u_int ti_omsgflags;			/* msgs asserted */
	u_int ti_emsgflags;			/* a msg currently asserted */
#define	SCSI_LOW_MSG_RESET	0x00000001
#define	SCSI_LOW_MSG_REJECT	0x00000002
#define	SCSI_LOW_MSG_PARITY	0x00000004
#define	SCSI_LOW_MSG_ERROR	0x00000008
#define	SCSI_LOW_MSG_IDENTIFY	0x00000010
#define	SCSI_LOW_MSG_ABORT	0x00000020
#define	SCSI_LOW_MSG_TERMIO	0x00000040
#define	SCSI_LOW_MSG_SIMPLE_QTAG	0x00000080
#define	SCSI_LOW_MSG_ORDERED_QTAG	0x00000100
#define	SCSI_LOW_MSG_HEAD_QTAG		0x00000200
#define	SCSI_LOW_MSG_ABORT_QTAG 0x00000400
#define	SCSI_LOW_MSG_CLEAR_QTAG 0x00000800
#define	SCSI_LOW_MSG_WIDE	0x00001000
#define	SCSI_LOW_MSG_SYNCH	0x00002000
#define	SCSI_LOW_MSG_NOOP	0x00004000
#define	SCSI_LOW_MSG_LAST	0x00008000
#define	SCSI_LOW_MSG_ALL	0xffffffff

	/* msgout buffer */
	u_int8_t ti_msgoutstr[SCSI_LOW_MAX_MSGLEN];	/* scsi msgout */
	u_int ti_msgoutlen;			/* msgout strlen */

	/*
	 * target initialize msgout
 	 */
	u_int ti_setup_msg;		/* setup msgout requests */
	u_int ti_setup_msg_done;

	/*
	 * synch and wide data info
 	 */
	u_int ti_flags_valid;	/* valid flags */
#define	SCSI_LOW_TARG_FLAGS_USER_VALID		0x0001
#define	SCSI_LOW_TARG_FLAGS_DISK_VALID		0x0002
#define	SCSI_LOW_TARG_FLAGS_QUIRKS_VALID	0x0004
#define	SCSI_LOW_TARG_FLAGS_ALL_VALID \
	(SCSI_LOW_TARG_FLAGS_USER_VALID | \
	 SCSI_LOW_TARG_FLAGS_DISK_VALID | SCSI_LOW_TARG_FLAGS_QUIRKS_VALID)

	u_int ti_diskflags;	/* given target disk flags */
	u_int ti_quirks;	/* given target quirk */

	struct synch {
		u_int8_t offset;
		u_int8_t period;
	} ti_osynch, ti_maxsynch;		/* synch data */

#define	SCSI_LOW_BUS_WIDTH_8	0
#define	SCSI_LOW_BUS_WIDTH_16	1
#define	SCSI_LOW_BUS_WIDTH_32	2
	u_int ti_owidth, ti_width;

	/*
	 * lun info size.
 	 */
	int ti_lunsize;

#ifdef	SCSI_LOW_DIAGNOSTIC
	struct scsi_low_msg_log ti_log_msgout;
	struct scsi_low_msg_log ti_log_msgin;
#endif	/* SCSI_LOW_DIAGNOSTIC */
};

/*************************************************
 * COMMON HEADER STRUCTURE
 *************************************************/
struct scsi_low_softc;
struct proc;
typedef struct scsi_low_softc *sc_low_t;

#define	SCSI_LOW_START_OK	0
#define	SCSI_LOW_START_FAIL	1
#define	SCSI_LOW_INFO_ALLOC	0
#define	SCSI_LOW_INFO_REVOKE	1
#define	SCSI_LOW_INFO_DEALLOC	2
#define	SCSI_LOW_POWDOWN	1
#define	SCSI_LOW_ENGAGE		2

#define	SC_LOW_INIT_T (int (*)(sc_low_t, int))
#define	SC_LOW_BUSRST_T (void (*)(sc_low_t))
#define	SC_LOW_TARG_INIT_T (int (*)(sc_low_t, struct targ_info *, int))
#define	SC_LOW_LUN_INIT_T (int (*)(sc_low_t, struct targ_info *, struct lun_info *, int))
#define	SC_LOW_SELECT_T (int (*)(sc_low_t, struct slccb *))
#define	SC_LOW_ATTEN_T (void (*)(sc_low_t))
#define	SC_LOW_NEXUS_T (int (*)(sc_low_t))
#define	SC_LOW_MSG_T (int (*)(sc_low_t, struct targ_info *, u_int))
#define	SC_LOW_POLL_T (int (*)(void *))
#define	SC_LOW_POWER_T (int (*)(sc_low_t, u_int))
#define	SC_LOW_TIMEOUT_T (int (*)(sc_low_t))

struct scsi_low_funcs {
	int (*scsi_low_init)(sc_low_t, int);
	void (*scsi_low_bus_reset)(sc_low_t);
	int (*scsi_low_targ_init)(sc_low_t, struct targ_info *, int);
	int (*scsi_low_lun_init)(sc_low_t, struct targ_info *, struct lun_info *, int);
	int (*scsi_low_start_bus)(sc_low_t, struct slccb *);
	int (*scsi_low_establish_lun_nexus)(sc_low_t);
	int (*scsi_low_establish_ccb_nexus)(sc_low_t);
	void (*scsi_low_attention)(sc_low_t);
	int (*scsi_low_msg)(sc_low_t, struct targ_info *, u_int);
	int (*scsi_low_timeout)(sc_low_t);
	int (*scsi_low_poll)(void *);
	int (*scsi_low_power)(sc_low_t, u_int);
	int (*scsi_low_ioctl)(sc_low_t, u_long, caddr_t, int, struct proc *);
};

struct scsi_low_softc {
	/* os depend structure */
	struct scsi_low_osdep_interface sl_si;
#define	sl_dev	sl_si.si_dev
	struct scsi_low_osdep_funcs *sl_osdep_fp;
	u_char sl_xname[16];

	/* our chain */
	LIST_ENTRY(scsi_low_softc) sl_chain;

	/* my targets */
	struct targ_info *sl_ti[SCSI_LOW_NTARGETS];
	struct targ_info_tab sl_titab;

	/* current active T_L_Q nexus */
	struct targ_info *sl_Tnexus;		/* Target nexus */
	struct lun_info *sl_Lnexus;		/* Lun nexus */
	struct slccb *sl_Qnexus;			/* Qtag nexus */
	int sl_nexus_call;

	/* ccb start queue */
	struct slccbtab sl_start;

	/* retry limit and phase change counter */
	int sl_max_retry;
	int sl_ph_count;
	int sl_timeout_count;

	/* selection & total num disconnect targets */
	int sl_nio;
	int sl_disc;
	int sl_retry_sel;
	struct slccb *sl_selid;

	/* attention */
	int sl_atten;			/* ATN asserted */
	int sl_clear_atten;		/* negate ATN required */

	/* scsi phase suggested by scsi msg */
	u_int sl_msgphase;
#define	MSGPH_NULL	0x00		/* no msg */
#define	MSGPH_DISC	0x01		/* disconnect msg */
#define	MSGPH_CMDC	0x02		/* cmd complete msg */
#define	MSGPH_ABORT	0x03		/* abort seq */
#define	MSGPH_TERM	0x04		/* current io terminate */
#define	MSGPH_LCTERM	0x05		/* cmd link terminated */
#define	MSGPH_RESET	0x06		/* reset target */

	/* error */
	u_int sl_error;			/* error flags */
#define	FATALIO		0x0001		/* generic io error & retry io */
#define	ABORTIO		0x0002		/* generic io error & terminate io */
#define	TIMEOUTIO	0x0004		/* watch dog timeout */
#define	SELTIMEOUTIO	0x0008		/* selection timeout */
#define	PDMAERR		0x0010		/* dma xfer error */
#define	MSGERR		0x0020		/* msgsys error */
#define	PARITYERR	0x0040		/* parity error */
#define	BUSYERR		0x0080		/* target busy error */
#define	STATERR		0x0100		/* status error */
#define	UACAERR		0x0200		/* target CA state, no sense check */
#define	SENSEIO		0x1000		/* cmd not excuted but sense data ok */
#define	SENSEERR	0x2000		/* cmd not excuted and sense data bad */
#define	UBFERR		0x4000		/* unexpected bus free */
#define	PENDINGIO	0x8000		/* ccb start not yet */
#define	SCSI_LOW_ERRORBITS "\020\017ubferr\016senseerr\015senseio\012uacaerr\011staterr\010busy\007parity\006msgerr\005pdmaerr\004seltimeout\003timeout\002abort\001fatal"

	/* current scsi data pointer */
	struct sc_p sl_scp;

	/* power control */
	u_int sl_active;		/* host is busy state */
	int sl_powc;			/* power down timer counter */
	u_int sl_rstep;			/* resume step */

	/* configuration flags */
	u_int sl_flags;
#define	HW_POWDOWN	0x0001
#define	HW_RESUME	0x0002
#define	HW_PDMASTART	0x0004
#define	HW_INACTIVE	0x0008
#define	HW_POWERCTRL	0x0010
#define	HW_INITIALIZING 0x0020
#define	HW_READ_PADDING		0x1000
#define	HW_WRITE_PADDING	0x2000

	u_int sl_cfgflags;
#define	CFG_NODISC		0x0001
#define	CFG_NOPARITY		0x0002
#define	CFG_NOATTEN		0x0004
#define	CFG_ASYNC		0x0008
#define	CFG_NOQTAG		0x0010

	int sl_show_result;
#define	SHOW_SYNCH_NEG	0x0001
#define	SHOW_WIDE_NEG	0x0002
#define	SHOW_CALCF_RES	0x0010
#define	SHOW_PROBE_RES	0x0020
#define	SHOW_ALL_NEG	-1

	/* host informations */
	u_int sl_hostid;
	int sl_nluns;
	int sl_ntargs;
	int sl_openings;

	/* interface functions */
	struct scsi_low_funcs *sl_funcs;

	/* targinfo size */
	int sl_targsize;

#if	defined(i386) || defined(__i386__)
	u_int sl_irq;		/* XXX */
#endif	/* i386 */
};

/*************************************************
 * SCSI LOW service functions
 *************************************************/
/*
 * Scsi low attachment function.
 */
int scsi_low_attach(struct scsi_low_softc *, int, int, int, int, int);
int scsi_low_dettach(struct scsi_low_softc *);

/*
 * Scsi low interface activate or deactivate functions
 */
int scsi_low_is_busy(struct scsi_low_softc *);
int scsi_low_activate(struct scsi_low_softc *);
int scsi_low_deactivate(struct scsi_low_softc *);

/*
 * Scsi phase "bus service" functions.
 * These functions are corresponding to each scsi bus phaeses.
 */
/* bus idle phase (other initiators or targets release bus) */
void scsi_low_bus_idle(struct scsi_low_softc *);

/* arbitration and selection phase */
void scsi_low_arbit_fail(struct scsi_low_softc *, struct slccb *);
static __inline void scsi_low_arbit_win(struct scsi_low_softc *);

/* msgout phase */
#define	SCSI_LOW_MSGOUT_INIT		0x00000001
#define	SCSI_LOW_MSGOUT_UNIFY		0x00000002
int scsi_low_msgout(struct scsi_low_softc *, struct targ_info *, u_int);

/* msgin phase */
#define SCSI_LOW_DATA_PE	0x80000000
int scsi_low_msgin(struct scsi_low_softc *, struct targ_info *, u_int);

/* statusin phase */
static __inline int scsi_low_statusin(struct scsi_low_softc *, struct targ_info *, u_int);

/* data phase */
int scsi_low_data(struct scsi_low_softc *, struct targ_info *, struct buf **, int);
static __inline void scsi_low_data_finish(struct scsi_low_softc *);

/* cmd phase */
int scsi_low_cmd(struct scsi_low_softc *, struct targ_info *);

/* reselection phase */
struct targ_info *scsi_low_reselected(struct scsi_low_softc *, u_int);

/* disconnection phase */
int scsi_low_disconnected(struct scsi_low_softc *, struct targ_info *);

/*
 * Scsi bus restart function.
 * Canncel all established nexuses => scsi system initialized => restart jobs.
 */
#define	SCSI_LOW_RESTART_HARD	1
#define	SCSI_LOW_RESTART_SOFT	0
int scsi_low_restart(struct scsi_low_softc *, int, u_char *);

/*
 * Scsi utility fucntions
 */
/* print current status */
void scsi_low_print(struct scsi_low_softc *, struct targ_info *);

/* bus reset utility */
void scsi_low_bus_reset(struct scsi_low_softc *);

/*************************************************
 * Message macro defs
 *************************************************/
#define	SCSI_LOW_SETUP_PHASE(ti, phase)			\
{							\
	(ti)->ti_ophase = ti->ti_phase;			\
	(ti)->ti_phase = (phase);			\
}

#define	SCSI_LOW_SETUP_MSGPHASE(slp, PHASE)		\
{							\
	(slp)->sl_msgphase = (PHASE);			\
}

#define	SCSI_LOW_ASSERT_ATN(slp)			\
{							\
	(slp)->sl_atten = 1;				\
}

#define	SCSI_LOW_DEASSERT_ATN(slp)			\
{							\
	(slp)->sl_atten = 0;				\
}

/*************************************************
 * Inline functions
 *************************************************/
static __inline void scsi_low_attention(struct scsi_low_softc *);
static __inline int scsi_low_is_msgout_continue(struct targ_info *, u_int);
static __inline int scsi_low_assert_msg(struct scsi_low_softc *, struct targ_info *, u_int, int);
static __inline int scsi_low_is_disconnect_ok(struct slccb *);

static __inline int
scsi_low_is_msgout_continue(ti, mask)
	struct targ_info *ti;
	u_int mask;
{

	return ((ti->ti_msgflags & (~mask)) != 0);
}

static __inline int
scsi_low_is_disconnect_ok(cb)
	struct slccb *cb;
{

	return ((cb->li->li_flags & SCSI_LOW_DISC) != 0 &&
		    (cb->ccb_flags & (CCB_SENSE | CCB_CLEARQ)) == 0);
}

static __inline void
scsi_low_attention(slp)
	struct scsi_low_softc *slp;
{

	if (slp->sl_atten != 0)
		return;

	(*slp->sl_funcs->scsi_low_attention) (slp);
	SCSI_LOW_ASSERT_ATN(slp);
}

static __inline int
scsi_low_assert_msg(slp, ti, msg, now)
	struct scsi_low_softc *slp;
	struct targ_info *ti;
	u_int msg;
	int now;
{

	ti->ti_msgflags |= msg;
	if (now != 0)
		scsi_low_attention(slp);
	return 0;
}

static __inline void
scsi_low_arbit_win(slp)
	struct scsi_low_softc *slp;
{

	slp->sl_selid = NULL;
}

static __inline void
scsi_low_data_finish(slp)
	struct scsi_low_softc *slp;
{

	if (slp->sl_Qnexus != NULL)
	{
		slp->sl_Qnexus->ccb_datalen = slp->sl_scp.scp_datalen;
	}
}

static __inline int
scsi_low_statusin(slp, ti, c)
	struct scsi_low_softc *slp;
	struct targ_info *ti;
	u_int c;
{

	slp->sl_ph_count ++;
	if ((c & SCSI_LOW_DATA_PE) != 0)
	{
		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 0);
		return EIO;
	}
	slp->sl_scp.scp_status = (u_int8_t) c;
	return 0;
}

/*************************************************
 * Message out defs
 *************************************************/
/* XXX: use scsi_message.h */
#define	ST_GOOD		0x00
#define	ST_CHKCOND	0x02
#define	ST_MET		0x04
#define	ST_BUSY		0x08
#define	ST_INTERGOOD	0x10
#define	ST_INTERMET	0x14
#define	ST_CONFLICT	0x18
#define	ST_CMDTERM	0x22
#define	ST_QUEFULL	0x28
#define	ST_UNKNOWN	0xff

#define	MSG_COMP	0x00
#define	MSG_EXTEND	0x01

#define	MKMSG_EXTEND(XLEN, XCODE) ((((u_int)(XLEN)) << NBBY) | ((u_int)(XCODE)))
#define	MSG_EXTEND_MDPCODE	0x00
#define	MSG_EXTEND_MDPLEN	0x05
#define	MSG_EXTEND_SYNCHCODE	0x01
#define	MSG_EXTEND_SYNCHLEN	0x03
#define	MSG_EXTEND_WIDECODE	0x03
#define	MSG_EXTEND_WIDELEN	0x02

#define	MSG_SAVESP	0x02
#define	MSG_RESTORESP	0x03
#define	MSG_DISCON	0x04
#define	MSG_I_ERROR	0x05
#define	MSG_ABORT	0x06
#define	MSG_REJECT	0x07
#define	MSG_NOOP	0x08
#define	MSG_PARITY	0x09
#define	MSG_LCOMP	0x0a
#define	MSG_LCOMP_F	0x0b
#define	MSG_RESET	0x0c
#define	MSG_ABORT_QTAG	0x0d
#define	MSG_CLEAR_QTAG	0x0e
#define	MSG_TERM_IO	0x11
#define	MSG_SIMPLE_QTAG	0x20
#define	MSG_HEAD_QTAG	0x21
#define	MSG_ORDERED_QTAG	0x22
#define	MSG_IDENTIFY	  	0x80
#define	MSG_IDENTIFY_DISCPRIV	0x40
#endif	/* !_SCSI_LOW_H_ */


code:
/*	$FreeBSD: release/9.0.0/sys/cam/scsi/scsi_low_pisa.h 139743 2005-01-05 22:34:37Z imp $	*/
/*	$NecBSD: scsi_low_pisa.h,v 1.3.14.1 2001/06/08 06:27:49 honda Exp $	*/
/*	$NetBSD$	*/

/*-
 * [NetBSD for NEC PC-98 series]
 *  Copyright (c) 1998
 *	NetBSD/pc98 porting staff. 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, 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.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
 */

#ifndef	_SCSI_LOW_PISA_H_
#define	_SCSI_LOW_PISA_H_

#ifdef	__NetBSD__
int scsi_low_activate_pisa(pisa_device_handle_t);
int scsi_low_deactivate_pisa(pisa_device_handle_t);
int scsi_low_notify_pisa(pisa_device_handle_t, pisa_event_t);
#endif	/* __NetBSD__ */

#ifdef	__FreeBSD__
int scsi_low_activate_pisa(struct scsi_low_softc *, int);
int scsi_low_deactivate_pisa(struct scsi_low_softc *);
#endif	/* __FreeBSD__ */
#endif	/* !_SCSI_LOW_PISA_H_ */


code:
/*-
 * This file is in the public domain.
 * $FreeBSD: release/9.0.0/sys/cam/scsi/scsi_message.h 139743 2005-01-05 22:34:37Z imp $
 */

/* Messages (1 byte) */		     /* I/T (M)andatory or (O)ptional */
#define MSG_CMDCOMPLETE		0x00 /* M/M */
#define MSG_TASK_COMPLETE	0x00 /* M/M */ /* SPI3 Terminology */
#define MSG_EXTENDED		0x01 /* O/O */
#define MSG_SAVEDATAPOINTER	0x02 /* O/O */
#define MSG_RESTOREPOINTERS	0x03 /* O/O */
#define MSG_DISCONNECT		0x04 /* O/O */
#define MSG_INITIATOR_DET_ERR	0x05 /* M/M */
#define MSG_ABORT		0x06 /* O/M */
#define MSG_ABORT_TASK_SET	0x06 /* O/M */ /* SPI3 Terminology */
#define MSG_MESSAGE_REJECT	0x07 /* M/M */
#define MSG_NOOP		0x08 /* M/M */
#define MSG_PARITY_ERROR	0x09 /* M/M */
#define MSG_LINK_CMD_COMPLETE	0x0a /* O/O */
#define MSG_LINK_CMD_COMPLETEF	0x0b /* O/O */ /* Obsolete */
#define MSG_BUS_DEV_RESET	0x0c /* O/M */
#define MSG_TARGET_RESET	0x0c /* O/M */ /* SPI3 Terminology */
#define MSG_ABORT_TAG		0x0d /* O/O */
#define MSG_ABORT_TASK		0x0d /* O/O */ /* SPI3 Terminology */
#define MSG_CLEAR_QUEUE		0x0e /* O/O */
#define MSG_CLEAR_TASK_SET	0x0e /* O/O */ /* SPI3 Terminology */
#define MSG_INIT_RECOVERY	0x0f /* O/O */ /* Deprecated in SPI3 */
#define MSG_REL_RECOVERY	0x10 /* O/O */ /* Deprecated in SPI3 */
#define MSG_TERM_IO_PROC	0x11 /* O/O */ /* Deprecated in SPI3 */
#define MSG_CLEAR_ACA		0x16 /* O/O */ /* SPI3 */
#define MSG_LOGICAL_UNIT_RESET	0x17 /* O/O */ /* SPI3 */
#define MSG_QAS_REQUEST		0x55 /* O/O */ /* SPI3 */

/* Messages (2 byte) */
#define MSG_SIMPLE_Q_TAG	0x20 /* O/O */
#define MSG_SIMPLE_TASK		0x20 /* O/O */ /* SPI3 Terminology */
#define MSG_HEAD_OF_Q_TAG	0x21 /* O/O */
#define MSG_HEAD_OF_QUEUE_TASK	0x21 /* O/O */ /* SPI3 Terminology */
#define MSG_ORDERED_Q_TAG	0x22 /* O/O */
#define MSG_ORDERED_TASK	0x22 /* O/O */ /* SPI3 Terminology */
#define MSG_IGN_WIDE_RESIDUE	0x23 /* O/O */
#define MSG_ACA_TASK		0x24 /* 0/0 */ /* SPI3 */

/* Identify message */		     /* M/M */
#define MSG_IDENTIFYFLAG	0x80
#define MSG_IDENTIFY_DISCFLAG	0x40
#define MSG_IDENTIFY(lun, disc)	(((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
#define MSG_ISIDENTIFY(m)	((m) & MSG_IDENTIFYFLAG)
#define MSG_IDENTIFY_LUNMASK	0x3F

/* Extended messages (opcode and length) */
#define MSG_EXT_SDTR		0x01
#define MSG_EXT_SDTR_LEN	0x03

#define MSG_EXT_WDTR		0x03
#define MSG_EXT_WDTR_LEN	0x02
#define MSG_EXT_WDTR_BUS_8_BIT	0x00
#define MSG_EXT_WDTR_BUS_16_BIT	0x01
#define MSG_EXT_WDTR_BUS_32_BIT	0x02 /* Deprecated in SPI3 */

#define	MSG_EXT_PPR		0x04 /* SPI3/SPI4 */
#define	MSG_EXT_PPR_LEN		0x06
#define	MSG_EXT_PPR_PCOMP_EN	0x80
#define	MSG_EXT_PPR_RTI		0x40
#define	MSG_EXT_PPR_RD_STRM	0x20
#define	MSG_EXT_PPR_WR_FLOW	0x10
#define	MSG_EXT_PPR_HOLD_MCS	0x08
#define	MSG_EXT_PPR_QAS_REQ	0x04
#define	MSG_EXT_PPR_DT_REQ	0x02
#define	MSG_EXT_PPR_IU_REQ	0x01


code:
/*-
 * Copyright (c) 1997, 1999 Kenneth D. Merry.
 * 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, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 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.
 *
 * $FreeBSD: release/9.0.0/sys/cam/scsi/scsi_pass.h 139743 2005-01-05 22:34:37Z imp $
 */

#ifndef _SCSI_PASS_H
#define _SCSI_PASS_H 1

#include <sys/ioccom.h>

#include <cam/cam_ccb.h>

/*
 * Convert to using a pointer to a ccb in the next major version.
 * This should allow us to avoid an extra copy of the CCB data.
 */
#define CAMIOCOMMAND	_IOWR(CAM_VERSION, 2, union ccb)
#define CAMGETPASSTHRU	_IOWR(CAM_VERSION, 3, union ccb)

#endif


code:
/*-
 * Structure and function declarations for Processor type devices.
 *
 * Copyright (c) 1998 Justin T. Gibbs
 * 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, this list of conditions, and the following disclaimer,
 *    without modification, immediately at the beginning of the file.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 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.
 *
 * $FreeBSD: release/9.0.0/sys/cam/scsi/scsi_pt.h 139743 2005-01-05 22:34:37Z imp $
 */

#ifndef	_SCSI_SCSI_PT_H
#define _SCSI_SCSI_PT_H 1

struct scsi_send_receive
{
	u_int8_t opcode;
	u_int8_t byte2;
	u_int8_t xfer_len[3];
	u_int8_t control;
};

/*
 * Opcodes
 */
#define RECEIVE			0x08
#define SEND			0x0A

#endif /* _SCSI_SCSI_PT_H */


code:
/*-
 * Structure and function declarations for the
 * SCSI Sequential Access Peripheral driver for CAM.
 *
 * Copyright (c) 1999, 2000 Matthew Jacob
 * 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, this list of conditions, and the following disclaimer,
 *    without modification, immediately at the beginning of the file.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 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.
 *
 * $FreeBSD: release/9.0.0/sys/cam/scsi/scsi_sa.h 139743 2005-01-05 22:34:37Z imp $
 */

#ifndef	_SCSI_SCSI_SA_H
#define _SCSI_SCSI_SA_H 1

#include <sys/cdefs.h>

struct scsi_read_block_limits
{
	u_int8_t opcode;
	u_int8_t byte2;
	u_int8_t unused[3];
	u_int8_t control;
};

struct scsi_read_block_limits_data
{
	u_int8_t gran;
#define	RBL_GRAN_MASK	0x1F
#define RBL_GRAN(rblim) ((rblim)->gran & RBL_GRAN_MASK)
	u_int8_t maximum[3];
	u_int8_t minimum[2];
};

struct scsi_sa_rw
{
	u_int8_t opcode;
        u_int8_t sli_fixed;
#define SAR_SLI		0x02
#define SARW_FIXED	0x01
	u_int8_t length[3];
        u_int8_t control;
};

struct scsi_load_unload
{
	u_int8_t opcode;
        u_int8_t immediate;
#define SLU_IMMED	0x01
	u_int8_t reserved[2];
	u_int8_t eot_reten_load;
#define SLU_EOT		0x04
#define SLU_RETEN	0x02
#define SLU_LOAD	0x01
        u_int8_t control;
};

struct scsi_rewind
{
	u_int8_t opcode;
        u_int8_t immediate;
#define SREW_IMMED	0x01
	u_int8_t reserved[3];
        u_int8_t control;
};

typedef enum {
	SS_BLOCKS,
	SS_FILEMARKS,
	SS_SEQFILEMARKS,
	SS_EOD,
	SS_SETMARKS,
	SS_SEQSETMARKS
} scsi_space_code;

struct scsi_space
{
	u_int8_t opcode;
        u_int8_t code;
#define SREW_IMMED	0x01
	u_int8_t count[3];
        u_int8_t control;
};

struct scsi_write_filemarks
{
	u_int8_t opcode;
        u_int8_t byte2;
#define SWFMRK_IMMED	0x01
#define SWFMRK_WSMK	0x02
	u_int8_t num_marks[3];
        u_int8_t control;
};

/*
 * Reserve and release unit have the same exact cdb format, but different
 * opcodes.
 */
struct scsi_reserve_release_unit
{
	u_int8_t opcode;
	u_int8_t lun_thirdparty;
#define SRRU_LUN_MASK	0xE0
#define SRRU_3RD_PARTY	0x10
#define SRRU_3RD_SHAMT	1
#define SRRU_3RD_MASK	0xE
	u_int8_t reserved[3];
	u_int8_t control;
};

/*
 * Erase a tape
 */
struct scsi_erase
{
	u_int8_t opcode;
	u_int8_t lun_imm_long;
#define SE_LUN_MASK	0xE0
#define SE_LONG		0x1
#define SE_IMMED	0x2
	u_int8_t reserved[3];
	u_int8_t control;
};

/*
 * Dev specific mode page masks.
 */
#define SMH_SA_WP		0x80
#define	SMH_SA_BUF_MODE_MASK	0x70
#define SMH_SA_BUF_MODE_NOBUF	0x00
#define SMH_SA_BUF_MODE_SIBUF	0x10	/* Single-Initiator buffering */
#define SMH_SA_BUF_MODE_MIBUF	0x20	/* Multi-Initiator buffering */
#define SMH_SA_SPEED_MASK	0x0F
#define SMH_SA_SPEED_DEFAULT	0x00

/*
 * Sequential-access specific mode page numbers.
 */
#define SA_DEVICE_CONFIGURATION_PAGE	0x10
#define SA_MEDIUM_PARTITION_PAGE_1	0x11
#define SA_MEDIUM_PARTITION_PAGE_2	0x12
#define SA_MEDIUM_PARTITION_PAGE_3	0x13
#define SA_MEDIUM_PARTITION_PAGE_4	0x14
#define SA_DATA_COMPRESSION_PAGE	0x0f	/* SCSI-3 */

/*
 * Mode page definitions.
 */

/* See SCSI-II spec 9.3.3.1 */
struct scsi_dev_conf_page {
	u_int8_t pagecode;	/* 0x10 */
	u_int8_t pagelength;	/* 0x0e */
	u_int8_t byte2;		/* CAP, CAF, Active Format */
	u_int8_t active_partition;
	u_int8_t wb_full_ratio;
	u_int8_t rb_empty_ratio;
	u_int8_t wrdelay_time[2];
	u_int8_t byte8;
#define	SA_DBR			0x80	/* data buffer recovery */
#define	SA_BIS			0x40	/* block identifiers supported */
#define	SA_RSMK			0x20	/* report setmarks */
#define	SA_AVC			0x10	/* automatic velocity control */
#define	SA_SOCF_MASK		0xc0	/* stop on consecutive formats */
#define	SA_RBO			0x20	/* recover buffer order */
#define	SA_REW			0x10	/* report early warning */
	u_int8_t gap_size;
	u_int8_t byte10;
	u_int8_t ew_bufsize[3];
	u_int8_t sel_comp_alg;
#define	SA_COMP_NONE		0x00
#define	SA_COMP_DEFAULT		0x01
	/* the following is 'reserved' in SCSI-2 but is defined in SSC-r22 */
	u_int8_t extra_wp;
#define	SA_ASOC_WP		0x04	/* Associated Write Protect */
#define	SA_PERS_WP		0x02	/* Persistent Write Protect */
#define	SA_PERM_WP		0x01	/* Permanent Write Protect */
};

/* from SCSI-3: SSC-Rev10 (6/97) */
struct scsi_data_compression_page {
	u_int8_t page_code;	/* 0x0f */
	u_int8_t page_length;	/* 0x0e */
	u_int8_t dce_and_dcc;
#define SA_DCP_DCE		0x80 	/* Data compression enable */
#define SA_DCP_DCC		0x40	/* Data compression capable */
	u_int8_t dde_and_red;
#define SA_DCP_DDE		0x80	/* Data decompression enable */
#define SA_DCP_RED_MASK		0x60	/* Report Exception on Decomp. */
#define SA_DCP_RED_SHAMT	5
#define SA_DCP_RED_0		0x00
#define SA_DCP_RED_1		0x20
#define SA_DCP_RED_2		0x40
	u_int8_t comp_algorithm[4];
	u_int8_t decomp_algorithm[4];
	u_int8_t reserved[4];
};

typedef union {
	struct { u_int8_t pagecode, pagelength; } hdr;
	struct scsi_dev_conf_page dconf;
	struct scsi_data_compression_page dcomp;
} sa_comp_t;

struct scsi_tape_read_position {
	u_int8_t opcode;		/* READ_POSITION */
	u_int8_t byte1;			/* set LSB to read hardware block pos */
	u_int8_t reserved[8];
};

struct scsi_tape_position_data	{	/* Short Form */
	u_int8_t flags;
#define	SA_RPOS_BOP		0x80	/* Beginning of Partition */
#define	SA_RPOS_EOP		0x40	/* End of Partition */
#define	SA_RPOS_BCU		0x20	/* Block Count Unknown (SCSI3) */
#define	SA_RPOS_BYCU		0x10	/* Byte Count Unknown (SCSI3) */
#define	SA_RPOS_BPU		0x04	/* Block Position Unknown */
#define	SA_RPOS_PERR		0x02	/* Position Error (SCSI3) */
#define	SA_RPOS_UNCERTAIN	SA_RPOS_BPU
	u_int8_t partition;
	u_int8_t reserved[2];
	u_int8_t firstblk[4];
	u_int8_t lastblk[4];
	u_int8_t reserved2;
	u_int8_t nbufblk[3];
	u_int8_t nbufbyte[4];
};

struct scsi_tape_locate {
	u_int8_t opcode;
	u_int8_t byte1;
#define	SA_SPOS_IMMED		0x01
#define	SA_SPOS_CP		0x02
#define	SA_SPOS_BT		0x04
	u_int8_t reserved1;
	u_int8_t blkaddr[4];
	u_int8_t reserved2;
	u_int8_t partition;
	u_int8_t control;
};

/*
 * Opcodes
 */
#define REWIND			0x01
#define READ_BLOCK_LIMITS	0x05
#define SA_READ			0x08
#define SA_WRITE		0x0A
#define WRITE_FILEMARKS		0x10
#define SPACE			0x11
#define RESERVE_UNIT		0x16
#define RELEASE_UNIT		0x17
#define ERASE			0x19
#define LOAD_UNLOAD		0x1B
#define	LOCATE			0x2B
#define	READ_POSITION		0x34

/*
 * Tape specific density codes- only enough of them here to recognize
 * some specific older units so we can choose 2FM@EOD or FIXED blocksize
 * quirks.
 */
#define SCSI_DENSITY_HALFINCH_800	0x01
#define SCSI_DENSITY_HALFINCH_1600	0x02
#define SCSI_DENSITY_HALFINCH_6250	0x03
#define SCSI_DENSITY_HALFINCH_6250C	0xC3	/* HP Compressed 6250 */
#define SCSI_DENSITY_QIC_11_4TRK	0x04
#define SCSI_DENSITY_QIC_11_9TRK	0x84	/* Vendor Unique Emulex */
#define SCSI_DENSITY_QIC_24		0x05
#define SCSI_DENSITY_HALFINCH_PE	0x06
#define SCSI_DENSITY_QIC_120		0x0f
#define SCSI_DENSITY_QIC_150		0x10
#define	SCSI_DENSITY_QIC_525_320	0x11
#define	SCSI_DENSITY_QIC_1320		0x12
#define	SCSI_DENSITY_QIC_2GB		0x22
#define	SCSI_DENSITY_QIC_4GB		0x26
#define	SCSI_DENSITY_QIC_3080		0x29

__BEGIN_DECLS
void	scsi_read_block_limits(struct ccb_scsiio *, u_int32_t,
			       void (*cbfcnp)(struct cam_periph *, union ccb *),
			       u_int8_t, struct scsi_read_block_limits_data *,
			       u_int8_t , u_int32_t);

void	scsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries,
			   void (*cbfcnp)(struct cam_periph *, union ccb *),
			   u_int8_t tag_action, int readop, int sli,
			   int fixed, u_int32_t length, u_int8_t *data_ptr,
			   u_int32_t dxfer_len, u_int8_t sense_len,
			   u_int32_t timeout);

void	scsi_rewind(struct ccb_scsiio *csio, u_int32_t retries,
		    void (*cbfcnp)(struct cam_periph *, union ccb *),
		    u_int8_t tag_action, int immediate, u_int8_t sense_len,
		    u_int32_t timeout);

void	scsi_space(struct ccb_scsiio *csio, u_int32_t retries,
		   void (*cbfcnp)(struct cam_periph *, union ccb *),
		   u_int8_t tag_action, scsi_space_code code,
		   u_int32_t count, u_int8_t sense_len, u_int32_t timeout);

void	scsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries,
			 void (*cbfcnp)(struct cam_periph *, union ccb *),
			 u_int8_t tag_action, int immediate,   int eot,
			 int reten, int load, u_int8_t sense_len,
			 u_int32_t timeout);

void	scsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries,
			     void (*cbfcnp)(struct cam_periph *, union ccb *),
			     u_int8_t tag_action, int immediate, int setmark,
			     u_int32_t num_marks, u_int8_t sense_len,
			     u_int32_t timeout);

void	scsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries,
				  void (*cbfcnp)(struct cam_periph *,
				  union ccb *), u_int8_t tag_action,
				  int third_party, int third_party_id,
				  u_int8_t sense_len, u_int32_t timeout,
				  int reserve);

void	scsi_erase(struct ccb_scsiio *csio, u_int32_t retries,
		   void (*cbfcnp)(struct cam_periph *, union ccb *),
		   u_int8_t tag_action, int immediate, int long_erase,
		   u_int8_t sense_len, u_int32_t timeout);

void	scsi_data_comp_page(struct scsi_data_compression_page *page,
			    u_int8_t dce, u_int8_t dde, u_int8_t red,
			    u_int32_t comp_algorithm,
			    u_int32_t decomp_algorithm);

void	scsi_read_position(struct ccb_scsiio *csio, u_int32_t retries,
                           void (*cbfcnp)(struct cam_periph *, union ccb *),
                           u_int8_t tag_action, int hardsoft,
                           struct scsi_tape_position_data *sbp,
                           u_int8_t sense_len, u_int32_t timeout);

void	scsi_set_position(struct ccb_scsiio *csio, u_int32_t retries,
                         void (*cbfcnp)(struct cam_periph *, union ccb *),
                         u_int8_t tag_action, int hardsoft, u_int32_t blkno,
                         u_int8_t sense_len, u_int32_t timeout);
__END_DECLS

#endif /* _SCSI_SCSI_SA_H */