Home | History | Annotate | Download | only in dda
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  *
     21  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     22  * Use is subject to license terms.
     23  */
     24 
     25 
     26 /*
     27  * Driver for Disk Archiving (dda)
     28  *
     29  * DDA emulates the st tape driver BSD mode for MMS disk archiving.
     30  *
     31  * A limited number of MTIO operations are implemented by DDA.
     32  *
     33  * USCSI commands are not implemented by DDA.
     34  *
     35  * Tape drive operations such as load, capacity and read block limits
     36  * are DDA ioctl commands.
     37  *
     38  * DDA media is implemented as a cartridge directory containing three
     39  * files: metadata, index and data.
     40  *
     41  * The metadata file contains cartridge information such as version,
     42  * capacity, stripe alignment, direct I/O alignment, and the write
     43  * protect tab. The user application sets the alignments when the dda
     44  * media is created.
     45  *
     46  * The index file contains index records which describes the data file.
     47  * An index record contains the data file offset, number of consecutive
     48  * same size records and filemarks. An new index record is generated
     49  * when a write changes record sizes or data follows a filemark. A on
     50  * disk binary search is used for locate or space filemarks operations.
     51  * An advisory file lock is held on the index file to prevent multiple
     52  * loads for the same piece of dda media and to prevent a load when
     53  * the user is changing the cartridge write protect tab. The data file
     54  * offset is adjusted for alignment at bot, when data follows a filemark,
     55  * or the record size changes. Stripe alignment occurs at bot or after a
     56  * filemark. Direct I/O alignment occurs for every read or write operation
     57  * and is applied after the stripe alignment.
     58  *
     59  * The data file contains user data along with holes for stripe and
     60  * direct I/O alignment.
     61  *
     62  * The metadata and index file records are used in native endian format
     63  * in memory and are stored on disk in big endian format. The data file
     64  * is in the host's native endian format.
     65  */
     66 
     67 #include <sys/devops.h>			/* used by dev_ops */
     68 #include <sys/conf.h>			/* used by dev_ops and cb_ops */
     69 #include <sys/modctl.h> 		/* used by modlinkage, modldrv, */
     70 					/* _init, _info, and _fini */
     71 #include <sys/types.h>  		/* used by open, close, read, write, */
     72 					/* prop_op, and ddi_prop_op */
     73 #include <sys/file.h>			/* used by open, close */
     74 #include <sys/errno.h>  		/* used by open, close, read, write */
     75 #include <sys/open.h>			/* used by open, close, read, write */
     76 #include <sys/cred.h>			/* used by open, close, read */
     77 #include <sys/uio.h>			/* used by read */
     78 #include <sys/stat.h>			/* defines S_IFCHR used by */
     79 					/* ddi_create_minor_node */
     80 #include <sys/cmn_err.h>		/* used by all entry points for */
     81 					/* this driver */
     82 #include <sys/ddi.h>			/* used by all entry points for */
     83 					/* this driver also used by cb_ops, */
     84 					/* ddi_get_instance, and ddi_prop_op */
     85 #include <sys/sunddi.h> 		/* used by all entry points for */
     86 					/* this driver also used by cb_ops, */
     87 					/* ddi_create_minor_node, */
     88 					/* ddi_get_instance, and ddi_prop_op */
     89 #include <sys/scsi/impl/uscsi.h>	/* uscsi commands */
     90 #include <sys/ioctl.h>
     91 #include <sys/mtio.h>			/* tape io */
     92 #include <sys/systeminfo.h>		/* for hostid access */
     93 #include <sys/scsi/targets/stdef.h>
     94 #include <sys/vfs.h>
     95 #include <limits.h>
     96 #include <sys/sdt.h>			/* d-trace */
     97 #include <sys/flock.h>			/* advisory non-blocking file lock */
     98 #include "dda.h"
     99 
    100 /* vnode mode is read, write, large files, allow symlinks */
    101 #define	DDA_VNODE_MODE FREAD|FWRITE|FOFFMAX
    102 
    103 /* maximum block size */
    104 #define	DDA_MAX_REC_SIZE	262144	/* maximum media block size */
    105 
    106 /* early warning capacity - space */
    107 #define	DDA_EARLY_WARN		98	/* media early warning percentage */
    108 
    109 /* block number unknown */
    110 #define	DDA_BLKNO_UNKNOWN	1000000000
    111 
    112 /* file name unknown */
    113 #define	DDA_UNKNOWN_FNAME	"?"
    114 
    115 /* operation flags and macros */
    116 #define	DDA_FLAG_TRUNC		0x1	/* write truncate */
    117 #define	DDA_FLAG_FM_FWD_PEND	0x2	/* file mark forward pending */
    118 #define	DDA_FLAG_FM_NOSKIP	0x4	/* fsr set fm forward pending */
    119 #define	DDA_FLAG_FM_NEEDED	0x8	/* file mark needed */
    120 #define	DDA_FLAG_EOT_EIO	0x10	/* read return code for eot */
    121 #define	DDA_FLAG_EW		0x20	/* alternating ew write failure */
    122 #define	DDA_FLAG_INDEX		0x40	/* index record needs file write */
    123 
    124 #define	DDA_GET_TRUNC(x)	(x->dda_flags & DDA_FLAG_TRUNC)
    125 #define	DDA_GET_FM_FWD_PEND(x)	(x->dda_flags & DDA_FLAG_FM_FWD_PEND)
    126 #define	DDA_GET_FM_NOSKIP(x)	(x->dda_flags & DDA_FLAG_FM_NOSKIP)
    127 #define	DDA_GET_FM_NEEDED(x)	(x->dda_flags & DDA_FLAG_FM_NEEDED)
    128 #define	DDA_GET_EOT_EIO(x)	(x->dda_flags & DDA_FLAG_EOT_EIO)
    129 #define	DDA_GET_EW(x)		(x->dda_flags & DDA_FLAG_EW)
    130 #define	DDA_GET_INDEX(x)	(x->dda_flags & DDA_FLAG_INDEX)
    131 
    132 #define	DDA_SET_TRUNC(x)	(x->dda_flags |= DDA_FLAG_TRUNC)
    133 #define	DDA_SET_FM_FWD_PEND(x)	(x->dda_flags |= DDA_FLAG_FM_FWD_PEND)
    134 #define	DDA_SET_FM_NOSKIP(x)	(x->dda_flags |= DDA_FLAG_FM_NOSKIP)
    135 #define	DDA_SET_FM_NEEDED(x)	(x->dda_flags |= DDA_FLAG_FM_NEEDED)
    136 #define	DDA_SET_EOT_EIO(x)	(x->dda_flags |= DDA_FLAG_EOT_EIO)
    137 #define	DDA_SET_EW(x)		(x->dda_flags |= DDA_FLAG_EW)
    138 #define	DDA_SET_INDEX(x)	(x->dda_flags |= DDA_FLAG_INDEX)
    139 
    140 #define	DDA_CLR_TRUNC(x)	(x->dda_flags &= ~DDA_FLAG_TRUNC)
    141 #define	DDA_CLR_FM_FWD_PEND(x)	(x->dda_flags &= ~(DDA_FLAG_FM_FWD_PEND | \
    142 						    DDA_FLAG_FM_NOSKIP))
    143 #define	DDA_CLR_FM_NOSKIP(x)	(x->dda_flags &= ~DDA_FLAG_FM_NOSKIP)
    144 #define	DDA_CLR_FM_NEEDED(x)	(x->dda_flags &= ~DDA_FLAG_FM_NEEDED)
    145 #define	DDA_CLR_EOT_EIO(x)	(x->dda_flags &= ~DDA_FLAG_EOT_EIO)
    146 #define	DDA_CLR_EW(x)		(x->dda_flags &= ~DDA_FLAG_EW)
    147 #define	DDA_CLR_INDEX(x)	(x->dda_flags &= ~DDA_FLAG_INDEX)
    148 
    149 /* metadata flag */
    150 #define	DDA_GET_WPROTECT(x)	(x->dda_metadata.dda_flags & DDA_FLAG_WPROTECT)
    151 
    152 /* read only tape */
    153 #define	DDA_GET_READ_ONLY(x)	((x->dda_read_only || \
    154 				    DDA_GET_WPROTECT(x)) ? 1 : 0)
    155 
    156 /* alignment macros */
    157 #define	DDA_OFF_ALIGNED(off, sz)	(off & (int64_t)(sz - 1))
    158 #define	DDA_LEN_ALIGNED(len, sz)	((size_t)len & (sz - 1))
    159 
    160 /* index record calculations */
    161 #define	DDA_IS_BOT(x)		(x->dda_index_offset == 0 && \
    162 				    x->dda_pos == 0 ? 1 : 0)
    163 #define	DDA_IS_BLANK(x)		(x->dda_index_offset == 0 && \
    164 				    DDA_INDEX_COUNT(x) == 0 ? 1 : 0)
    165 #define	DDA_IS_FM(x)		(DDA_IS_BLANK(x) ? 0 : \
    166 				    x->dda_index.dda_fmcount && \
    167 				    x->dda_pos >= x->dda_index. \
    168 				    dda_blkcount && \
    169 				    x->dda_pos <= DDA_INDEX_COUNT(x) ? 1 : 0)
    170 #define	DDA_LBA(x)		(x->dda_index.dda_lba + x->dda_pos)
    171 #define	DDA_INDEX_COUNT(x)	(x->dda_index.dda_blkcount + \
    172 				    x->dda_index.dda_fmcount)
    173 
    174 #ifdef	DEBUG
    175 #define	DDA_DEBUG(y) y
    176 #else
    177 #define	DDA_DEBUG(y)
    178 #endif
    179 
    180 #define	DDA_DEBUG1(x) DDA_DEBUG(DTRACE_PROBE1 x)
    181 #define	DDA_DEBUG2(x) DDA_DEBUG(DTRACE_PROBE2 x)
    182 #define	DDA_DEBUG3(x) DDA_DEBUG(DTRACE_PROBE3 x)
    183 #define	DDA_DEBUG4(x) DDA_DEBUG(DTRACE_PROBE4 x)
    184 
    185 /* index record state */
    186 typedef struct dda_istate {
    187 	dda_index_t	dda_index;
    188 	off64_t		dda_index_offset;
    189 	int64_t		dda_pos;
    190 	uint32_t	dda_flags;
    191 } dda_istate_t;
    192 
    193 /* driver operations */
    194 static int dda_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
    195 static int dda_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
    196 static int dda_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
    197     void **resultp);
    198 static int dda_open(dev_t *devp, int flag, int otyp, cred_t *credp);
    199 static int dda_close(dev_t dev, int flag, int otyp, cred_t *credp);
    200 static int dda_read(dev_t dev, struct uio *uio, cred_t *credp);
    201 static int dda_write(dev_t dev, struct uio *uio, cred_t *credp);
    202 static int dda_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
    203     int *rvalp);
    204 
    205 /* tape operations */
    206 static int dda_tape_op(dda_t *dda, struct mtlop *mtop);
    207 static int dda_tape_load(dda_t *dda, char *path);
    208 static int dda_tape_unload(dda_t *dda);
    209 static int dda_tape_rewind(dda_t *dda);
    210 static int dda_tape_write(dda_t *dda, struct uio *uio);
    211 static int dda_tape_read(dda_t *dda, struct uio *uio);
    212 static int dda_tape_wfm(dda_t *dda, int count);
    213 static int dda_tape_eom(dda_t *dda);
    214 static int dda_tape_fsf(dda_t *dda, int count);
    215 static int dda_tape_bsf(dda_t *dda, int count);
    216 static int dda_tape_fsr(dda_t *dda, int count);
    217 static int dda_tape_bsr(dda_t *dda, int count);
    218 static int dda_tape_locate(dda_t *dda, int64_t position);
    219 static int dda_tape_erase(dda_t *dda);
    220 
    221 /* support routines */
    222 static void dda_set_unloaded(dda_t *dda);
    223 static int64_t dda_get_fileno(dda_t *dda);
    224 static int dda_get_blkno(dda_t *dda, int64_t *blkno);
    225 static int dda_write_truncate(dda_t *dda);
    226 
    227 /* index record write, read, generate, save and restore */
    228 static int dda_write_index(dda_t *dda);
    229 static int dda_read_index(dda_t *dda);
    230 static void dda_gen_next_index(dda_t *dda, int32_t blksize);
    231 static void dda_save_istate(dda_t *dda, dda_istate_t *istate);
    232 static void dda_restore_istate(dda_t *dda, dda_istate_t *istate);
    233 
    234 /* data file offset */
    235 static off64_t dda_stripe_align(dda_t *dda);
    236 static off64_t dda_data_offset(dda_t *dda);
    237 
    238 /* space */
    239 static int dda_tape_capacity(dda_t *dda, int64_t *space);
    240 static int dda_ew_eom(dda_t *dda, int32_t count, int64_t *avail, int *ew);
    241 
    242 /* search */
    243 static int dda_locate_compare(dda_t *dda, int64_t lba);
    244 static int dda_fsf_compare(dda_t *dda, int64_t fileno);
    245 static int dda_bsf_compare(dda_t *dda, int64_t fileno);
    246 static int dda_bsearch(dda_t *dda,
    247     int64_t key,
    248     int (*compare)(dda_t *, int64_t),
    249     int *found);
    250 
    251 /* vnode operations */
    252 static int dda_vn_open(dda_t *dda, struct vnode **vpp, char *fname);
    253 static int dda_vn_close(dda_t *dda, struct vnode **vpp);
    254 static int dda_vn_lock(dda_t *dda, struct vnode *vp, short lock);
    255 static int dda_vn_read(dda_t *dda, struct vnode *vp, void *buf, int len,
    256     off64_t offset);
    257 static int dda_vn_write(dda_t *dda, struct vnode *vp, void *buf, int len,
    258     off64_t offset);
    259 static int dda_vn_truncate(dda_t *dda, struct vnode *vp, off64_t offset);
    260 static int dda_vn_sync(dda_t *dda, struct vnode *vp);
    261 static int dda_vn_size(dda_t *dda, struct vnode *vp, off64_t *fsize);
    262 static char *dda_vn_get_fname(dda_t *dda, struct vnode *vp);
    263 static void dda_vn_error_skey(dda_t *dda, int err);
    264 
    265 /* cb_ops structure */
    266 static struct cb_ops dda_cb_ops = {
    267 	dda_open,
    268 	dda_close,
    269 	nodev,			/* no strategy - nodev returns ENXIO */
    270 	nodev,			/* no print */
    271 	nodev,			/* no dump */
    272 	dda_read,
    273 	dda_write,
    274 	dda_ioctl,
    275 	nodev,			/* no devmap */
    276 	nodev,			/* no mmap */
    277 	nodev,			/* no segmap */
    278 	nochpoll,		/* returns ENXIO for non-pollable devices */
    279 	ddi_prop_op,
    280 	NULL,			/* streamtab struct; if not NULL, all above */
    281 	/* fields are ignored */
    282 	D_NEW | D_MP,		/* compatibility flags: see conf.h */
    283 	CB_REV,			/* cb_ops revision number */
    284 	nodev,			/* no aread */
    285 	nodev			/* no awrite */
    286 };
    287 
    288 /* dev_ops structure */
    289 static struct dev_ops dda_dev_ops = {
    290 	DEVO_REV,
    291 	0,			/* reference count */
    292 	dda_getinfo,
    293 	nulldev,		/* no identify - nulldev returns 0 */
    294 	nulldev,		/* no probe */
    295 	dda_attach,
    296 	dda_detach,
    297 	nodev,			/* no reset - nodev returns ENXIO */
    298 	&dda_cb_ops,
    299 	(struct bus_ops *)NULL,
    300 	nodev			/* no power */
    301 };
    302 
    303 /* modldrv structure */
    304 #define	DDA_LINKINFO "driver for disk archiving"
    305 static char dda_linkinfo[100];
    306 static struct modldrv dda_md = {
    307 	&mod_driverops,
    308 	dda_linkinfo,
    309 	&dda_dev_ops
    310 };
    311 
    312 /* modlinkage structure */
    313 static struct modlinkage dda_ml = {
    314 	MODREV_1,
    315 	&dda_md,
    316 	NULL
    317 };
    318 
    319 /* dev_info structure, one instance per dda device */
    320 static void *dda_state;
    321 
    322 /* Loadable module configuration entry points */
    323 
    324 /*
    325  * _init
    326  *
    327  * Parameters:
    328  *	None
    329  *
    330  * Globals:
    331  *	- dda_state:	Uninitialized list of DDA drives.
    332  *	- dda_linkinfo:	DDA description string.
    333  *	- dda_ml:	DDA module linkage structure.
    334  *
    335  * Initialize list of emulated tape drives.
    336  * Create driver description reported to user.
    337  * Export driver specification to the kernel.
    338  *
    339  * Return Values:
    340  *	0 : success
    341  *	non-zero : failure
    342  *
    343  */
    344 int
    345 _init(void)
    346 {
    347 	int	rc;
    348 
    349 	if ((rc = ddi_soft_state_init(&dda_state, sizeof (dda_t), 0)) != 0) {
    350 		cmn_err(CE_WARN, "_init: soft state init error %d", rc);
    351 		return (rc);
    352 	}
    353 	(void) snprintf(dda_linkinfo, sizeof (dda_linkinfo), "%s %d.%d",
    354 	    DDA_LINKINFO, DDA_MAJOR_VERSION, DDA_MINOR_VERSION);
    355 	if ((rc = mod_install(&dda_ml)) != 0) {
    356 		cmn_err(CE_WARN, "_init: mod install error %d", rc);
    357 		ddi_soft_state_fini(&dda_state);
    358 	}
    359 	return (rc);
    360 }
    361 
    362 /*
    363  * _info
    364  *
    365  * Parameters:
    366  *	- modinfop:	Opaque module information structure.
    367  *
    368  * Globals:
    369  *	- dda_ml:       DDA module linkage structure.
    370  *
    371  * Report DDA module information.
    372  *
    373  * Return Values:
    374  *      non-zero : success
    375  *      0 : failure
    376  *
    377  */
    378 int
    379 _info(struct modinfo *modinfop)
    380 {
    381 	int	rc;
    382 
    383 	if ((rc = mod_info(&dda_ml, modinfop)) == 0) {
    384 		cmn_err(CE_WARN, "_info: mod info error %d", rc);
    385 	}
    386 	return (rc);
    387 }
    388 
    389 /*
    390  * _fini
    391  *
    392  * Parameters:
    393  *	- none
    394  *
    395  * Globals:
    396  *	- dda_ml:       DDA module linkage structure.
    397  *	- dda_state:	DDA drive list.
    398  *
    399  * Prepare to unload the DDA driver from the kernel.
    400  * Release DDA drive list to the system.
    401  *
    402  * Return Values:
    403  *      0 : success
    404  *      non-zero : failure
    405  *
    406  */
    407 int
    408 _fini(void)
    409 {
    410 	int	rc;
    411 
    412 	if ((rc = mod_remove(&dda_ml)) != 0) {
    413 		return (rc);
    414 	}
    415 	ddi_soft_state_fini(&dda_state);
    416 	return (rc);
    417 }
    418 
    419 /* Device configuration entry points */
    420 
    421 /*
    422  * dda_attach
    423  *
    424  * Parameters:
    425  *	- dip:		Device information structure.
    426  *	- cmd:		Attach command.
    427  *
    428  * Globals:
    429  *	- dda_state:	Pointer to list of DDA drives.
    430  *
    431  * Create and initialize one DDA tape drive for each dda.conf instance.
    432  * Create BSD no-rewind tape drive minor node.
    433  * Assign generated serial number to the drive.
    434  * Initialize exclusive drive access mutex.
    435  * Set drive state to unload.
    436  *
    437  * Return Values:
    438  *      DDI_SUCCESS : success
    439  *      DDI_FAILURE : failure
    440  *
    441  */
    442 static int
    443 dda_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    444 {
    445 	int		instance = ddi_get_instance(dip);
    446 	dda_t		*dda;
    447 
    448 	switch (cmd) {
    449 	case DDI_ATTACH:
    450 		if (ddi_soft_state_zalloc(dda_state, instance) != DDI_SUCCESS) {
    451 			cmn_err(CE_WARN, "%d attach soft state alloc failed",
    452 			    instance);
    453 			return (DDI_FAILURE);
    454 		}
    455 
    456 		if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) {
    457 			ddi_soft_state_free(dda_state, instance);
    458 			cmn_err(CE_WARN, "%d attach get soft state failed",
    459 			    instance);
    460 			return (DDI_FAILURE);
    461 		}
    462 		dda->dda_inst = -1;
    463 
    464 		if (ddi_create_minor_node(dip, "bn", S_IFCHR,
    465 		    instance, DDI_PSEUDO, 0) != DDI_SUCCESS) {
    466 			ddi_soft_state_free(dda_state, instance);
    467 			cmn_err(CE_WARN, "%d attach create minor node failed",
    468 			    instance);
    469 			return (DDI_FAILURE);
    470 		}
    471 
    472 		dda->dda_dip = dip;
    473 		dda->dda_inst = instance;
    474 		mutex_init(&dda->dda_mutex, NULL, MUTEX_DRIVER, NULL);
    475 		dda_set_unloaded(dda);
    476 		return (DDI_SUCCESS);
    477 	default:
    478 		return (DDI_FAILURE);
    479 	}
    480 }
    481 
    482 /*
    483  * dda_detach
    484  *
    485  * Parameters:
    486  *	- dip:		Device information structure.
    487  *	- cmd:		Detach command.
    488  *
    489  * Globals:
    490  *	- dda_state:	Pointer to list of DDA drives.
    491  *
    492  * Get drive instance from the list of drives.
    493  * If media is loaded in the drive then unload the media.
    494  * Remove minor device node.
    495  * Release exclusive access mutex.
    496  * Release memory.
    497  *
    498  * Return Values:
    499  *      DDI_SUCCESS : success
    500  *      DDI_FAILURE : failure
    501  *
    502  */
    503 static int
    504 dda_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    505 {
    506 	int	instance = ddi_get_instance(dip);
    507 	dda_t	*dda;
    508 
    509 	switch (cmd) {
    510 	case DDI_DETACH:
    511 		if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) {
    512 			cmn_err(CE_WARN, "%d detach get soft state failed",
    513 			    instance);
    514 			return (DDI_FAILURE);
    515 		}
    516 		if (dda->dda_loaded) {
    517 			dda->dda_cred = kcred;
    518 			(void) dda_tape_unload(dda);
    519 		}
    520 		ddi_remove_minor_node(dip, "bn");
    521 		mutex_destroy(&dda->dda_mutex);
    522 		ddi_soft_state_free(dda_state, instance);
    523 		return (DDI_SUCCESS);
    524 	default:
    525 		return (DDI_FAILURE);
    526 	}
    527 }
    528 
    529 /*
    530  * dda_getinfo
    531  *
    532  * Parameters:
    533  *	- dip:		Device information structure.
    534  *	- cmd:		Information command.
    535  *	- arg:		Device structure.
    536  *	- resultp:	Pointer for information requested.
    537  *
    538  * Globals:
    539  *	- dda_state:	List of DDA emulated tape drives.
    540  *
    541  * Return drive instance information to the kernel.
    542  *
    543  * Return Values:
    544  *      DDI_SUCCESS : success
    545  *      DDI_FAILURE : failure
    546  *
    547  */
    548 /*ARGSUSED*/
    549 static int
    550 dda_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
    551 {
    552 	int	instance = getminor((dev_t)arg);
    553 	dda_t	*dda;
    554 
    555 	switch (cmd) {
    556 	case DDI_INFO_DEVT2DEVINFO:
    557 		if ((dda = ddi_get_soft_state(dda_state,
    558 		    instance)) == NULL) {
    559 			cmn_err(CE_WARN, "%d getinfo get soft state failed",
    560 			    instance);
    561 			*resultp = NULL;
    562 			return (DDI_FAILURE);
    563 		}
    564 		*resultp = dda->dda_dip;
    565 		return (DDI_SUCCESS);
    566 	case DDI_INFO_DEVT2INSTANCE:
    567 		*resultp = (void *)(uintptr_t)instance;
    568 		return (DDI_SUCCESS);
    569 	default:
    570 		*resultp = NULL;
    571 		return (DDI_FAILURE);
    572 	}
    573 }
    574 
    575 /* Main entry points */
    576 
    577 /*
    578  * dda_open
    579  *
    580  * Parameters:
    581  *	- devp:		Device structure.
    582  *	- flag:		Device open mode.
    583  *	- otyp:		Character or block device open.
    584  *	- credp:	User credentials.
    585  *
    586  * Globals:
    587  *	- dda_state:	List of DDA emulated tape drives.
    588  *
    589  * Verify character device open.
    590  * Get drive structure.
    591  * Lock drive to ensure sequential access.
    592  * If drive is already in-use then unlock drive and return busy.
    593  * If drive is not loaded then prevent read only or write non-blocking
    594  * access to the drive.
    595  * Save open process pid as the test for drive in-use.
    596  * Set read only mode.
    597  * Unlock drive.
    598  *
    599  * Return Values:
    600  *      DDI_SUCCESS : success
    601  *      DDI_FAILURE : failure
    602  *
    603  */
    604 static int
    605 dda_open(dev_t *devp, int flag, int otyp, cred_t *credp)
    606 {
    607 	int	instance = getminor(*devp);
    608 	dda_t	*dda;
    609 
    610 	if (otyp != OTYP_CHR) {
    611 		return (EINVAL);
    612 	}
    613 	if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) {
    614 		return (ENXIO);
    615 	}
    616 	mutex_enter(&dda->dda_mutex);
    617 	if (dda->dda_pid) {
    618 		/*
    619 		 * The real tape driver does not allow a drive to be
    620 		 * opened multiple times.
    621 		 */
    622 		mutex_exit(&dda->dda_mutex);
    623 		return (EBUSY);
    624 	}
    625 	if (!dda->dda_loaded) {
    626 		/*
    627 		 * The real tape driver does not allow an unloaded tape
    628 		 * drive to be opened in read only or blocking mode.
    629 		 */
    630 		if ((flag & FWRITE) == 0 ||
    631 		    ((flag & FWRITE) == FWRITE &&
    632 		    (flag & (FNDELAY | FNONBLOCK)) == 0)) {
    633 			mutex_exit(&dda->dda_mutex);
    634 			return (EIO);
    635 		}
    636 	}
    637 
    638 	/* user credentials */
    639 	dda->dda_cred = credp;
    640 
    641 	/* set open flag */
    642 	dda->dda_pid = ddi_get_pid();
    643 
    644 	/* get read only mode */
    645 	dda->dda_read_only = (flag & FWRITE) ? 0 : 1;
    646 	DDA_DEBUG2((dda_pid,
    647 	    int, dda->dda_inst,
    648 	    pid_t, dda->dda_pid));
    649 	mutex_exit(&dda->dda_mutex);
    650 	return (0);
    651 }
    652 
    653 /*
    654  * dda_open
    655  *
    656  * Parameters:
    657  *	- devp:		Device structure.
    658  *	- flag:		Device open mode.
    659  *	- otyp:		Character or block device open.
    660  *	- credp:	User credentials.
    661  *
    662  * Globals:
    663  *	- dda_state:	List of DDA emulated tape drives.
    664  *
    665  * Verify character device close.
    666  * Get drive structure.
    667  * Lock drive to ensure sequential access.
    668  * Append filemark if loaded and needed.
    669  * Unlock drive.
    670  *
    671  * Return Values:
    672  *      0 : success
    673  *      errno : failure
    674  *
    675  */
    676 static int
    677 dda_close(dev_t dev, int flag, int otyp, cred_t *credp)
    678 {
    679 	int	instance = getminor(dev);
    680 	dda_t	*dda;
    681 	int	err = 0;
    682 
    683 	if (otyp != OTYP_CHR) {
    684 		return (EINVAL);
    685 	}
    686 	if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) {
    687 		return (ENXIO);
    688 	}
    689 	mutex_enter(&dda->dda_mutex);
    690 	dda->dda_cred = credp;
    691 	DDA_DEBUG2((dda_pid,
    692 	    int, dda->dda_inst,
    693 	    pid_t, dda->dda_pid));
    694 	if (DDA_GET_FM_FWD_PEND(dda)) {
    695 		DDA_CLR_FM_FWD_PEND(dda);
    696 		DDA_CLR_FM_NEEDED(dda);
    697 	}
    698 	if ((flag & FWRITE) &&
    699 	    DDA_GET_FM_NEEDED(dda) &&
    700 	    DDA_GET_READ_ONLY(dda) == 0) {
    701 		err = dda_tape_wfm(dda, 1);
    702 	} else {
    703 		dda->dda_resid = 0;
    704 	}
    705 	dda->dda_pid = 0;
    706 	/* only reset record size at bot for bsb no rewind */
    707 	if (DDA_IS_BOT(dda)) {
    708 		dda->dda_rec_size = 0;
    709 		dda->dda_ili = 0;
    710 	}
    711 	mutex_exit(&dda->dda_mutex);
    712 	return (err);
    713 }
    714 
    715 /*
    716  * dda_read
    717  *
    718  * Parameters:
    719  *	- dev:		Device structure.
    720  *	- uio:		Vector I/O operations.
    721  *	- credp:	User credentials.
    722  *
    723  * Globals:
    724  *	- dda_state:	List of DDA emulated tape drives.
    725  *
    726  * Get drive structure.
    727  * Lock drive to ensure sequential access.
    728  * Call tape read function.
    729  * Unlock drive.
    730  *
    731  * Return Values:
    732  *      0 : success
    733  *      errno : failure
    734  *
    735  */
    736 static int
    737 dda_read(dev_t dev, struct uio *uio, cred_t *credp)
    738 {
    739 	int	instance = getminor(dev);
    740 	dda_t	*dda;
    741 	int	err;
    742 
    743 	if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) {
    744 		return (ENXIO);
    745 	}
    746 	mutex_enter(&dda->dda_mutex);
    747 	dda->dda_cred = credp;
    748 	err = dda_tape_read(dda, uio);
    749 	mutex_exit(&dda->dda_mutex);
    750 	return (err);
    751 }
    752 
    753 /*
    754  * dda_write
    755  *
    756  * Parameters:
    757  *	- dev:		Device structure.
    758  *	- uio:		Vector I/O operations.
    759  *	- credp:	User credentials.
    760  *
    761  * Globals:
    762  *	- dda_state:	List of DDA emulated tape drives.
    763  *
    764  * Get drive structure.
    765  * Lock drive to ensure sequential access.
    766  * Call tape write function.
    767  * Unlock drive.
    768  *
    769  * Return Values:
    770  *      0 : success
    771  *      errno : failure
    772  *
    773  */
    774 static int
    775 dda_write(dev_t dev, struct uio *uio, cred_t *credp)
    776 {
    777 	int	instance = getminor(dev);
    778 	dda_t	*dda;
    779 	int	err;
    780 
    781 	if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) {
    782 		return (ENXIO);
    783 	}
    784 	mutex_enter(&dda->dda_mutex);
    785 	dda->dda_cred = credp;
    786 	err = dda_tape_write(dda, uio);
    787 	mutex_exit(&dda->dda_mutex);
    788 	return (err);
    789 }
    790 
    791 /*
    792  * dda_ioctl
    793  *
    794  * Parameters:
    795  *	- dev:		Device structure.
    796  *	- cmd:		DDA or MTIO command.
    797  *	- flag:		User data model.
    798  *	- credp:	User credentials.
    799  *	- rvalp:	Return error number.
    800  *
    801  * Globals:
    802  *	- dda_state:	List of DDA emulated tape drives.
    803  *
    804  * Interface to execute DDA commands and selected MTIO commands.
    805  *
    806  * The DDA commands perform operations normally handled by a real tape
    807  * drive such as load, capacity, write protect tab, read block limits,
    808  * loaded cartridge pcl.
    809  *
    810  * MTIO commands support unload, motion, write filemark, erase, drive status,
    811  * drive type, record size, and setting incorrect length indicator.
    812  *
    813  * Get drive structure.
    814  * Determine command to execute.
    815  * Lock drive to ensure sequential access.
    816  * Call function to emulate MTIO functionality.
    817  * Unlock drive.
    818  *
    819  * Return Values:
    820  *	Cartridge write protect command:
    821  *	0 : read only
    822  *	-1 : read write
    823  *
    824  *	All other commands:
    825  *      0 : success
    826  *      errno : failure
    827  *
    828  * Note:
    829  *	DDA emulates BSD no-rewind behavior.
    830  *
    831  */
    832 /*ARGSUSED5*/
    833 static int
    834 dda_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
    835 {
    836 	int	instance = getminor(dev);
    837 	dda_t	*dda;
    838 	int	tmp;
    839 	char	*path;
    840 	int	err = 0;
    841 
    842 
    843 	if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) {
    844 		return (ENXIO);
    845 	}
    846 
    847 	switch (cmd) {
    848 	case DDA_CMD_LOAD: {
    849 		path = kmem_alloc(PATH_MAX, KM_SLEEP);
    850 		if (ddi_copyin((void *)arg, path, PATH_MAX, flag)) {
    851 			err = EFAULT;
    852 		} else {
    853 			mutex_enter(&dda->dda_mutex);
    854 			dda->dda_cred = credp;
    855 			err = dda_tape_load(dda, path);
    856 			mutex_exit(&dda->dda_mutex);
    857 		}
    858 		kmem_free(path, PATH_MAX);
    859 		return (err);
    860 	}
    861 	case DDA_CMD_NAME: {
    862 		mutex_enter(&dda->dda_mutex);
    863 		if (!dda->dda_loaded) {
    864 			mutex_exit(&dda->dda_mutex);
    865 			return (EIO);
    866 		}
    867 		path = kmem_alloc(PATH_MAX, KM_SLEEP);
    868 		(void) snprintf(path, PATH_MAX, "%s", dda->dda_path);
    869 		mutex_exit(&dda->dda_mutex);
    870 		if (ddi_copyout(path, (void *)arg, PATH_MAX, flag)) {
    871 			err = EFAULT;
    872 		}
    873 		kmem_free(path, PATH_MAX);
    874 		return (err);
    875 	}
    876 	case DDA_CMD_CAPACITY: {
    877 		dda_capacity_t		capacity;
    878 
    879 		mutex_enter(&dda->dda_mutex);
    880 		dda->dda_cred = credp;
    881 		if (!dda->dda_loaded) {
    882 			mutex_exit(&dda->dda_mutex);
    883 			return (EIO);
    884 		}
    885 		dda->dda_resid = 0;
    886 		capacity.dda_capacity = dda->dda_metadata.dda_capacity;
    887 		if (err = dda_tape_capacity(dda, &capacity.dda_space)) {
    888 			mutex_exit(&dda->dda_mutex);
    889 			return (err);
    890 		}
    891 		mutex_exit(&dda->dda_mutex);
    892 		if (ddi_copyout(&capacity, (void *)arg,
    893 		    sizeof (dda_capacity_t), flag)) {
    894 			return (EFAULT);
    895 		}
    896 		return (0);
    897 	}
    898 	case DDA_CMD_WPROTECT: {
    899 		mutex_enter(&dda->dda_mutex);
    900 		if (!dda->dda_loaded) {
    901 			mutex_exit(&dda->dda_mutex);
    902 			return (EIO);
    903 		}
    904 		dda->dda_resid = 0;
    905 		if (DDA_GET_WPROTECT(dda) != 0) {
    906 			mutex_exit(&dda->dda_mutex);
    907 			/* write protect tab on */
    908 			return (0);
    909 		}
    910 		mutex_exit(&dda->dda_mutex);
    911 		/* write protect tab off */
    912 		return (-1);
    913 	}
    914 	case DDA_CMD_BLKLMT: {
    915 		dda_blklmt_t	blklmt;
    916 
    917 		blklmt.dda_blkmax = DDA_MAX_REC_SIZE;
    918 		blklmt.dda_blkmin = 1;
    919 
    920 		mutex_enter(&dda->dda_mutex);
    921 		dda->dda_resid = 0;
    922 		mutex_exit(&dda->dda_mutex);
    923 
    924 		if (ddi_copyout(&blklmt, (void *)arg,
    925 		    sizeof (dda_blklmt_t), flag)) {
    926 			return (EFAULT);
    927 		}
    928 		return (0);
    929 	}
    930 	case USCSICMD: {
    931 		return (ENOTTY);
    932 	}
    933 	case MTIOCGETPOS: {
    934 		tapepos_t	pos;
    935 		int64_t		blkno;
    936 
    937 		mutex_enter(&dda->dda_mutex);
    938 		dda->dda_cred = credp;
    939 		if (!dda->dda_loaded) {
    940 			mutex_exit(&dda->dda_mutex);
    941 			return (EIO);
    942 		}
    943 		dda->dda_resid = 0;
    944 
    945 		bzero(&pos, sizeof (tapepos_t));
    946 		pos.lgclblkno = DDA_LBA(dda);
    947 		pos.fileno = dda_get_fileno(dda);
    948 		(void) dda_get_blkno(dda, &blkno);
    949 		pos.blkno = (UINT32_MAX & blkno);
    950 		pos.pmode = logical;
    951 
    952 		mutex_exit(&dda->dda_mutex);
    953 		if (ddi_copyout(&pos, (void *)arg,
    954 		    sizeof (tapepos_t), flag)) {
    955 			return (EFAULT);
    956 		}
    957 		return (0);
    958 	}
    959 	case MTIOCRESTPOS: {
    960 		tapepos_t	pos;
    961 
    962 		if (ddi_copyin((void *)arg, &pos,
    963 		    sizeof (tapepos_t), flag)) {
    964 			return (EFAULT);
    965 		}
    966 		mutex_enter(&dda->dda_mutex);
    967 		dda->dda_cred = credp;
    968 		if (!dda->dda_loaded) {
    969 			mutex_exit(&dda->dda_mutex);
    970 			return (EIO);
    971 		}
    972 		if (pos.pmode != logical) {
    973 			mutex_exit(&dda->dda_mutex);
    974 			return (EINVAL);
    975 		}
    976 		err = dda_tape_locate(dda, pos.lgclblkno);
    977 		mutex_exit(&dda->dda_mutex);
    978 		return (err);
    979 	}
    980 	case MTIOCLTOP: {
    981 		struct	mtlop	local;
    982 		int	rval;
    983 
    984 		if (ddi_copyin((void *)arg, &local, sizeof (local), flag)) {
    985 			return (EFAULT);
    986 		}
    987 
    988 		mutex_enter(&dda->dda_mutex);
    989 		dda->dda_cred = credp;
    990 		rval = dda_tape_op(dda, &local);
    991 		mutex_exit(&dda->dda_mutex);
    992 
    993 		if (ddi_copyout(&local, (void *)arg, sizeof (local), flag)) {
    994 			rval = EFAULT;
    995 		}
    996 		return (rval);
    997 	}
    998 	case MTIOCTOP: {
    999 #ifdef _MULTI_DATAMODEL
   1000 		/*
   1001 		 * For use when a 32 bit app makes a call into a
   1002 		 * 64 bit ioctl
   1003 		 */
   1004 		struct mtop32   mtop_32_for_64;
   1005 #endif /* _MULTI_DATAMODEL */
   1006 		struct mtop passed;
   1007 		struct mtlop local;
   1008 		int rval = 0;
   1009 
   1010 #ifdef _MULTI_DATAMODEL
   1011 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1012 		case DDI_MODEL_ILP32:
   1013 			if (ddi_copyin((void *)arg, &mtop_32_for_64,
   1014 			    sizeof (struct mtop32), flag)) {
   1015 				return (EFAULT);
   1016 			}
   1017 			local.mt_op = mtop_32_for_64.mt_op;
   1018 			local.mt_count =  (int64_t)mtop_32_for_64.mt_count;
   1019 			break;
   1020 
   1021 		case DDI_MODEL_NONE:
   1022 			if (ddi_copyin((void *)arg, &passed,
   1023 			    sizeof (passed), flag)) {
   1024 				return (EFAULT);
   1025 			}
   1026 			local.mt_op = passed.mt_op;
   1027 			/* prevent sign extension */
   1028 			local.mt_count = (UINT32_MAX & passed.mt_count);
   1029 			break;
   1030 		}
   1031 
   1032 #else /* ! _MULTI_DATAMODEL */
   1033 		if (ddi_copyin((void *)arg, &passed, sizeof (passed), flag)) {
   1034 			return (EFAULT);
   1035 		}
   1036 		local.mt_op = passed.mt_op;
   1037 		/* prevent sign extension */
   1038 		local.mt_count = (UINT32_MAX & passed.mt_count);
   1039 #endif /* _MULTI_DATAMODEL */
   1040 
   1041 		mutex_enter(&dda->dda_mutex);
   1042 		dda->dda_cred = credp;
   1043 		rval = dda_tape_op(dda, &local);
   1044 		mutex_exit(&dda->dda_mutex);
   1045 
   1046 #ifdef _MULTI_DATAMODEL
   1047 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1048 		case DDI_MODEL_ILP32:
   1049 			if (((uint64_t)local.mt_count) > UINT32_MAX) {
   1050 				rval = ERANGE;
   1051 				break;
   1052 			}
   1053 			/*
   1054 			 * Convert 64 bit back to 32 bit before doing
   1055 			 * copyout. This is what the ILP32 app expects.
   1056 			 */
   1057 			mtop_32_for_64.mt_op = local.mt_op;
   1058 			mtop_32_for_64.mt_count = (daddr32_t)local.mt_count;
   1059 
   1060 			if (ddi_copyout(&mtop_32_for_64, (void *)arg,
   1061 			    sizeof (struct mtop32), flag)) {
   1062 				rval = EFAULT;
   1063 			}
   1064 			break;
   1065 
   1066 		case DDI_MODEL_NONE:
   1067 			passed.mt_count = local.mt_count;
   1068 			passed.mt_op = local.mt_op;
   1069 			if (ddi_copyout(&passed, (void *)arg,
   1070 			    sizeof (passed), flag)) {
   1071 				rval = EFAULT;
   1072 			}
   1073 			break;
   1074 		}
   1075 #else /* ! _MULTI_DATAMODE */
   1076 		if (((uint64_t)local.mt_count) > UINT32_MAX) {
   1077 			rval = ERANGE;
   1078 		} else {
   1079 			passed.mt_op = local.mt_op;
   1080 			passed.mt_count = (daddr32_t)local.mt_count;
   1081 			if (ddi_copyout(&passed, (void *)arg,
   1082 			    sizeof (passed), flag)) {
   1083 				rval = EFAULT;
   1084 			}
   1085 		}
   1086 #endif /* _MULTI_DATAMODE */
   1087 		return (rval);
   1088 	}
   1089 	case MTIOCGET: {
   1090 #ifdef	_MULTI_DATAMODEL
   1091 		struct mtget32	mtg_local32;
   1092 		struct mtget32	*mtget_32 = &mtg_local32;
   1093 #endif	/* _MULTI_DATAMODEL */
   1094 		struct mtget mtg_local;
   1095 		struct mtget *mtget = &mtg_local;
   1096 
   1097 		bzero(mtget, sizeof (struct mtget));
   1098 		mutex_enter(&dda->dda_mutex);
   1099 		dda->dda_cred = credp;
   1100 		if (!dda->dda_loaded) {
   1101 			mtget->mt_erreg = KEY_NOT_READY;
   1102 			mtget->mt_resid = 0;
   1103 			mtget->mt_fileno = -1;
   1104 			mtget->mt_blkno = 0;
   1105 		} else {
   1106 			mtget->mt_erreg = dda->dda_status;
   1107 			mtget->mt_resid = dda->dda_resid;
   1108 			mtget->mt_fileno = dda_get_fileno(dda);
   1109 			mtget->mt_blkno = dda->dda_blkno;
   1110 		}
   1111 		mtget->mt_type = MT_ISOTHER;
   1112 		mtget->mt_flags = MTF_SCSI /* | MTF_ASF */;
   1113 		mtget->mt_bf = 1;
   1114 
   1115 		dda->dda_status = 0;
   1116 		dda->dda_resid = 0;
   1117 		tmp = sizeof (struct mtget);
   1118 
   1119 		DDA_CLR_FM_NEEDED(dda);
   1120 		DDA_DEBUG3((dda_cmd_status,
   1121 		    int, dda->dda_inst,
   1122 		    short, mtget->mt_erreg,
   1123 		    int32_t, mtget->mt_resid));
   1124 		mutex_exit(&dda->dda_mutex);
   1125 
   1126 #ifdef	_MULTI_DATAMODEL
   1127 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1128 		case DDI_MODEL_ILP32:
   1129 			mtget_32->mt_erreg =	mtget->mt_erreg;
   1130 			mtget_32->mt_resid =	mtget->mt_resid;
   1131 			mtget_32->mt_dsreg =	mtget->mt_dsreg;
   1132 			mtget_32->mt_fileno =	(daddr32_t)mtget->mt_fileno;
   1133 			mtget_32->mt_blkno =	(daddr32_t)mtget->mt_blkno;
   1134 			mtget_32->mt_type =	mtget->mt_type;
   1135 			mtget_32->mt_flags =	mtget->mt_flags;
   1136 			mtget_32->mt_bf =	mtget->mt_bf;
   1137 
   1138 			if (ddi_copyout(mtget_32, (void *)arg,
   1139 			    sizeof (struct mtget32), flag)) {
   1140 				return (EFAULT);
   1141 			}
   1142 			break;
   1143 		case DDI_MODEL_NONE:
   1144 			if (ddi_copyout(mtget, (void *)arg, tmp, flag)) {
   1145 				return (EFAULT);
   1146 			}
   1147 			break;
   1148 		}
   1149 #else	/* ! _MULTI_DATAMODE */
   1150 		if (ddi_copyout(mtget, (void *)arg, tmp, flag)) {
   1151 			return (EFAULT);
   1152 		}
   1153 #endif	/* _MULTI_DATAMODE */
   1154 
   1155 		return (0);
   1156 	}
   1157 	case MTIOCGETDRIVETYPE: {
   1158 #ifdef	_MULTI_DATAMODEL
   1159 		struct mtdrivetype_request32	mtdtrq32;
   1160 #endif	/* _MULTI_DATAMODEL */
   1161 		struct mtdrivetype_request mtdtrq;
   1162 		struct mtdrivetype mtdrtyp;
   1163 		struct mtdrivetype *mtdt = &mtdrtyp;
   1164 
   1165 #ifdef	_MULTI_DATAMODEL
   1166 		switch (ddi_model_convert_from(flag & FMODELS)) {
   1167 		case DDI_MODEL_ILP32:
   1168 		{
   1169 			if (ddi_copyin((void *)arg, &mtdtrq32,
   1170 			    sizeof (struct mtdrivetype_request32), flag)) {
   1171 				return (EFAULT);
   1172 			}
   1173 			mtdtrq.size = mtdtrq32.size;
   1174 			mtdtrq.mtdtp =
   1175 			    (struct  mtdrivetype *)(uintptr_t)mtdtrq32.mtdtp;
   1176 			break;
   1177 		}
   1178 		case DDI_MODEL_NONE:
   1179 			if (ddi_copyin((void *)arg, &mtdtrq,
   1180 			    sizeof (struct mtdrivetype_request), flag)) {
   1181 				return (EFAULT);
   1182 			}
   1183 			break;
   1184 		}
   1185 #else	/* ! _MULTI_DATAMODEL */
   1186 		if (ddi_copyin((void *)arg, &mtdtrq,
   1187 		    sizeof (struct mtdrivetype_request), flag)) {
   1188 			return (EFAULT);
   1189 		}
   1190 #endif	/* _MULTI_DATAMODEL */
   1191 
   1192 		if (mtdtrq.size < 0) {
   1193 			return (EINVAL);
   1194 		}
   1195 		bzero(mtdt, sizeof (struct mtdrivetype));
   1196 		(void) strncpy(mtdt->name, DDA_ST_NAME, ST_NAMESIZE);
   1197 		(void) strncpy(mtdt->vid, DDA_VID, VIDPIDLEN);
   1198 		mtdt->type = MT_ISOTHER;
   1199 		mtdt->bsize = 0;
   1200 		mtdt->options = ST_VARIABLE |
   1201 		    ST_READ_IGNORE_ILI |
   1202 		    ST_BSF |
   1203 		    ST_BSR |
   1204 		    ST_KNOWS_EOD |
   1205 		    ST_UNLOADABLE |
   1206 		    ST_NO_RESERVE_RELEASE;
   1207 		tmp = sizeof (struct mtdrivetype);
   1208 		if (mtdtrq.size < tmp)
   1209 			tmp = mtdtrq.size;
   1210 		if (ddi_copyout(mtdt, mtdtrq.mtdtp, tmp, flag)) {
   1211 			return (EFAULT);
   1212 		}
   1213 		mutex_enter(&dda->dda_mutex);
   1214 		DDA_CLR_FM_NEEDED(dda);
   1215 		mutex_exit(&dda->dda_mutex);
   1216 		return (0);
   1217 	}
   1218 	case MTIOCREADIGNOREILI: {
   1219 		int	set_ili;
   1220 
   1221 		if (ddi_copyin((void *)arg, &set_ili,
   1222 		    sizeof (set_ili), flag)) {
   1223 			return (EFAULT);
   1224 		}
   1225 
   1226 		mutex_enter(&dda->dda_mutex);
   1227 		if (!dda->dda_loaded) {
   1228 			mutex_exit(&dda->dda_mutex);
   1229 			return (EIO);
   1230 		}
   1231 		if (dda->dda_rec_size) {
   1232 			mutex_exit(&dda->dda_mutex);
   1233 			return (ENOTTY);
   1234 		}
   1235 		if (set_ili != 0 && set_ili != 1) {
   1236 			mutex_exit(&dda->dda_mutex);
   1237 			return (EINVAL);
   1238 		}
   1239 		dda->dda_ili = set_ili;
   1240 		DDA_DEBUG2((dda_cmd_ili,
   1241 		    int, dda->dda_inst,
   1242 		    int, dda->dda_ili));
   1243 		DDA_CLR_FM_NEEDED(dda);
   1244 		mutex_exit(&dda->dda_mutex);
   1245 		return (0);
   1246 	}
   1247 
   1248 	} /* switch end */
   1249 
   1250 	return (ENOTTY);
   1251 }
   1252 
   1253 /* tape operations */
   1254 
   1255 /*
   1256  * dda_tape_op
   1257  *
   1258  * Parameters:
   1259  *	- dda:		DDA tape drive.
   1260  *	- mtop:		Magnetic tape operation structure.
   1261  *
   1262  * Perform the MTIO command by calling the appropriate DDA function.
   1263  *
   1264  * Return Values:
   1265  *      0 : success
   1266  *      errno : failure
   1267  *
   1268  */
   1269 static int
   1270 dda_tape_op(dda_t *dda, struct mtlop *mtop)
   1271 {
   1272 	int	err;
   1273 
   1274 	switch (mtop->mt_op) {
   1275 	case MTTELL:
   1276 		if (!dda->dda_loaded) {
   1277 			return (EIO);
   1278 		}
   1279 		mtop->mt_count = DDA_LBA(dda);
   1280 		return (0);
   1281 	case MTSEEK: {
   1282 		int64_t	lba;
   1283 
   1284 		if (!dda->dda_loaded) {
   1285 			return (EIO);
   1286 		}
   1287 		if (err = dda_tape_locate(dda, mtop->mt_count)) {
   1288 			lba = DDA_LBA(dda);
   1289 		}
   1290 		if (err && mtop->mt_count != lba) {
   1291 			/* turn seek into tell command */
   1292 			mtop->mt_op = MTTELL;
   1293 			mtop->mt_count = lba;
   1294 		}
   1295 		return (err);
   1296 	}
   1297 	case MTWEOF:
   1298 		if (mtop->mt_count < 0) {
   1299 			return (EINVAL);
   1300 		}
   1301 		err = dda_tape_wfm(dda, mtop->mt_count);
   1302 		return (err);
   1303 	case MTFSF:
   1304 		err = dda_tape_fsf(dda, mtop->mt_count);
   1305 		return (err);
   1306 	case MTBSF:
   1307 		err = dda_tape_bsf(dda, mtop->mt_count);
   1308 		return (err);
   1309 	case MTFSR:
   1310 		err = dda_tape_fsr(dda, mtop->mt_count);
   1311 		return (err);
   1312 	case MTBSR:
   1313 		err = dda_tape_bsr(dda, mtop->mt_count);
   1314 		return (err);
   1315 	case MTRETEN:
   1316 	case MTREW:
   1317 		err = dda_tape_rewind(dda);
   1318 		return (err);
   1319 	case MTNOP:
   1320 		DDA_DEBUG3((dda_cmd_nop,
   1321 		    int, dda->dda_inst,
   1322 		    int64_t, DDA_LBA(dda),
   1323 		    int64_t, dda_get_fileno(dda)));
   1324 		return (0);
   1325 	case MTERASE:
   1326 		err = dda_tape_erase(dda);
   1327 		return (err);
   1328 	case MTEOM:
   1329 		err = dda_tape_eom(dda);
   1330 		return (err);
   1331 	case MTOFFL:
   1332 		err = dda_tape_unload(dda);
   1333 		return (err);
   1334 	case MTSRSZ:
   1335 		if (mtop->mt_count < 0) {
   1336 			return (EINVAL);
   1337 		}
   1338 		if (mtop->mt_count > DDA_MAX_REC_SIZE) {
   1339 			return (EINVAL);
   1340 		}
   1341 		if (!dda->dda_loaded) {
   1342 			return (EIO);
   1343 		}
   1344 		dda->dda_rec_size = mtop->mt_count;
   1345 
   1346 		if (dda->dda_rec_size) {
   1347 			dda->dda_ili = 0;
   1348 		}
   1349 
   1350 		DDA_DEBUG3((dda_cmd_srsz,
   1351 		    int, dda->dda_inst,
   1352 		    int32_t, dda->dda_rec_size,
   1353 		    int, dda->dda_ili));
   1354 		DDA_CLR_FM_NEEDED(dda);
   1355 		return (0);
   1356 	case MTGRSZ:
   1357 		if (!dda->dda_loaded) {
   1358 			return (EIO);
   1359 		}
   1360 		mtop->mt_count = dda->dda_rec_size;
   1361 		DDA_DEBUG3((dda_cmd_grsz,
   1362 		    int, dda->dda_inst,
   1363 		    int32_t, dda->dda_rec_size,
   1364 		    int, dda->dda_ili));
   1365 		return (0);
   1366 	}
   1367 	return (ENOTTY);
   1368 }
   1369 
   1370 /*
   1371  * dda_tape_load
   1372  *
   1373  * Parameters:
   1374  *	- dda:		DDA tape drive.
   1375  *	- path:		DDA media directory.
   1376  *
   1377  * If the drive is already loaded and the path is different then
   1378  * reject the load command and return.
   1379  * If the drive is already loaded and the path is the same then
   1380  * accept the load command and return.
   1381  * If not loaded open the DDA media files.
   1382  * If write protect tab is set read only.
   1383  * Calculate data file offset to early warning.
   1384  * Set unit attention status.
   1385  * Set truncate need flag since the media is at BOT.
   1386  * DDA media is now loaded and ready for access.
   1387  *
   1388  * Return Values:
   1389  *      0 : success
   1390  *      errno : failure
   1391  *
   1392  */
   1393 static int
   1394 dda_tape_load(dda_t *dda, char *path)
   1395 {
   1396 	char		*fname;
   1397 	int		err;
   1398 	short		status;
   1399 
   1400 
   1401 	dda->dda_status = 0;
   1402 	dda->dda_resid = 0;
   1403 	if (dda->dda_loaded) {
   1404 		if (strcmp(dda->dda_path, path) != 0) {
   1405 			cmn_err(CE_CONT,
   1406 			    "%d loaded already %s",
   1407 			    dda->dda_inst, dda->dda_path);
   1408 
   1409 			DDA_DEBUG2((dda_cmd_loaded_already,
   1410 			    int, dda->dda_inst,
   1411 			    char *, dda->dda_path));
   1412 
   1413 			dda->dda_status = KEY_ILLEGAL_REQUEST;
   1414 			return (EIO);
   1415 		}
   1416 		cmn_err(CE_CONT,
   1417 		    "%d load resume %s",
   1418 		    dda->dda_inst, dda->dda_path);
   1419 
   1420 		DDA_DEBUG2((dda_cmd_load_resume,
   1421 		    int, dda->dda_inst,
   1422 		    char *, dda->dda_path));
   1423 
   1424 		return (0);
   1425 	}
   1426 
   1427 	fname = kmem_alloc(PATH_MAX, KM_SLEEP);
   1428 
   1429 	/* reset media data, the drive data is not reset */
   1430 	bzero(dda, offsetof(dda_t, dda_inst));
   1431 	(void) snprintf(dda->dda_path, PATH_MAX, "%s", path);
   1432 
   1433 	(void) snprintf(fname, PATH_MAX, "%s/%s", dda->dda_path,
   1434 	    DDA_METADATA_FNAME);
   1435 	if (err = dda_vn_open(dda, &dda->dda_metadata_vp, fname)) {
   1436 		goto load_error;
   1437 	}
   1438 	if (err = dda_vn_lock(dda, dda->dda_metadata_vp, F_WRLCK)) {
   1439 		goto load_error;
   1440 	}
   1441 	if (err = dda_vn_read(dda, dda->dda_metadata_vp, &dda->dda_metadata,
   1442 	    sizeof (dda_metadata_t), 0)) {
   1443 		goto load_error;
   1444 	}
   1445 	DDA_BE_METADATA(dda->dda_metadata, dda->dda_metadata);
   1446 
   1447 	(void) snprintf(fname, PATH_MAX, "%s/%s", dda->dda_path,
   1448 	    DDA_INDEX_FNAME);
   1449 	if (err = dda_vn_open(dda, &dda->dda_index_vp, fname)) {
   1450 		goto load_error;
   1451 	}
   1452 	if (err = dda_vn_size(dda, dda->dda_index_vp, &dda->dda_index_fsize)) {
   1453 		goto load_error;
   1454 	}
   1455 	if (err = dda_read_index(dda)) {
   1456 		goto load_error;
   1457 	}
   1458 
   1459 	(void) snprintf(fname, PATH_MAX, "%s/%s", dda->dda_path,
   1460 	    DDA_DATA_FNAME);
   1461 	if (err = dda_vn_open(dda, &dda->dda_data_vp, fname)) {
   1462 		goto load_error;
   1463 	}
   1464 	if (err = dda_vn_size(dda, dda->dda_data_vp, &dda->dda_data_fsize)) {
   1465 		goto load_error;
   1466 	}
   1467 
   1468 	/* non-floating point early warning to eom percentage calculation */
   1469 	dda->dda_early_warn =
   1470 	    (dda->dda_metadata.dda_capacity / 100) * DDA_EARLY_WARN;
   1471 	if (dda->dda_early_warn < DDA_MAX_REC_SIZE) {
   1472 		dda->dda_early_warn = DDA_MAX_REC_SIZE;
   1473 		if (dda->dda_early_warn > dda->dda_metadata.dda_capacity) {
   1474 			dda->dda_early_warn = dda->dda_metadata.dda_capacity;
   1475 		}
   1476 	}
   1477 
   1478 	/* set media loaded */
   1479 	dda->dda_status = KEY_UNIT_ATTENTION;
   1480 	dda->dda_loaded = 1;
   1481 	DDA_SET_TRUNC(dda);
   1482 
   1483 	cmn_err(CE_CONT, "%d loaded %s",
   1484 	    dda->dda_inst, dda->dda_path);
   1485 
   1486 	DDA_DEBUG2((dda_cmd_load,
   1487 	    int, dda->dda_inst,
   1488 	    char *, path));
   1489 
   1490 	kmem_free(fname, PATH_MAX);
   1491 	return (0);
   1492 
   1493 load_error:
   1494 	cmn_err(CE_WARN, "%d load %s error %d",
   1495 	    dda->dda_inst, dda->dda_path, err);
   1496 
   1497 	DDA_DEBUG3((dda_cmd_load_err,
   1498 	    int, dda->dda_inst,
   1499 	    char *, path,
   1500 	    int, err));
   1501 
   1502 	/* cleanup */
   1503 	status = dda->dda_status;
   1504 	if (dda->dda_index_vp) {
   1505 		(void) dda_vn_close(dda, &dda->dda_index_vp);
   1506 	}
   1507 	if (dda->dda_data_vp) {
   1508 		(void) dda_vn_close(dda, &dda->dda_data_vp);
   1509 	}
   1510 	if (dda->dda_metadata_vp) {
   1511 		(void) dda_vn_lock(dda, dda->dda_metadata_vp, F_UNLCK);
   1512 		(void) dda_vn_close(dda, &dda->dda_metadata_vp);
   1513 	}
   1514 	dda_set_unloaded(dda);
   1515 	dda->dda_status = status;
   1516 	kmem_free(fname, PATH_MAX);
   1517 	return (err);
   1518 }
   1519 
   1520 /*
   1521  * dda_tape_unload
   1522  *
   1523  * Parameters:
   1524  *	- dda:		DDA tape drive.
   1525  *
   1526  * Write filemark if needed to emulate st bsd mode.
   1527  * Unload media from the drive.
   1528  * Report first error encounter.
   1529  *
   1530  * Return Values:
   1531  *      0 : success
   1532  *      errno : failure
   1533  *
   1534  */
   1535 static int
   1536 dda_tape_unload(dda_t *dda)
   1537 {
   1538 	int	rc;
   1539 	int	err = 0;
   1540 	short	status;
   1541 
   1542 
   1543 	/*
   1544 	 * Close all files, report first error
   1545 	 */
   1546 
   1547 	if (!dda->dda_loaded) {
   1548 		return (EIO);
   1549 	}
   1550 
   1551 	dda->dda_status = 0;
   1552 	dda->dda_resid = 0;
   1553 
   1554 	if (err = dda_write_index(dda)) {
   1555 		status = dda->dda_status;
   1556 	}
   1557 
   1558 	if (DDA_GET_FM_NEEDED(dda)) {
   1559 		if (rc = dda_tape_wfm(dda, 1)) {
   1560 			if (err == 0) {
   1561 				err = rc;
   1562 				status = dda->dda_status;
   1563 			}
   1564 		}
   1565 	}
   1566 
   1567 	if (rc = dda_vn_close(dda, &dda->dda_index_vp)) {
   1568 		if (err == 0) {
   1569 			err = rc;
   1570 			status = dda->dda_status;
   1571 		}
   1572 	}
   1573 
   1574 	if (rc = dda_vn_close(dda, &dda->dda_data_vp)) {
   1575 		if (err == 0) {
   1576 			err = rc;
   1577 			status = dda->dda_status;
   1578 		}
   1579 	}
   1580 
   1581 	(void) dda_vn_lock(dda, dda->dda_metadata_vp, F_UNLCK);
   1582 	if (rc = dda_vn_close(dda, &dda->dda_metadata_vp)) {
   1583 		if (err == 0) {
   1584 			err = rc;
   1585 			status = dda->dda_status;
   1586 		}
   1587 	}
   1588 
   1589 	dda->dda_status = status;
   1590 
   1591 	if (err == 0) {
   1592 		cmn_err(CE_CONT, "%d unloaded %s",
   1593 		    dda->dda_inst, dda->dda_path);
   1594 
   1595 		DDA_DEBUG2((dda_cmd_unload,
   1596 		    int, dda->dda_inst,
   1597 		    char *, dda->dda_path));
   1598 	} else {
   1599 		cmn_err(CE_WARN, "%d unloaded %s with error %d",
   1600 		    dda->dda_inst, dda->dda_path, err);
   1601 
   1602 		DDA_DEBUG3((dda_cmd_unload_err,
   1603 		    int, dda->dda_inst,
   1604 		    char *, dda->dda_path,
   1605 		    int, err));
   1606 	}
   1607 
   1608 	dda_set_unloaded(dda);
   1609 	return (err);
   1610 }
   1611 
   1612 /* support routines */
   1613 
   1614 /*
   1615  * dda_set_unloaded
   1616  *
   1617  * Parameters:
   1618  *	- dda:		DDA tape drive.
   1619  *
   1620  * Set DDA drive unloaded.
   1621  * Zero DDA media structure members.
   1622  * Set fileno to -1 for status.
   1623  *
   1624  * Return Values:
   1625  *      None
   1626  *
   1627  */
   1628 static void
   1629 dda_set_unloaded(dda_t *dda)
   1630 {
   1631 	bzero(dda, offsetof(dda_t, dda_inst));
   1632 	dda->dda_index.dda_fileno = -1;
   1633 	dda->dda_loaded = 0;
   1634 }
   1635 
   1636 /*
   1637  * dda_get_fileno
   1638  *
   1639  * Parameters:
   1640  *	- dda:		DDA tape drive.
   1641  *
   1642  * Get DDA media fileno based on st bsd behavior.
   1643  *
   1644  * Return Values:
   1645  *	fileno : filemark number
   1646  *
   1647  */
   1648 static int64_t
   1649 dda_get_fileno(dda_t *dda)
   1650 {
   1651 	int64_t	fileno;
   1652 
   1653 	fileno = dda->dda_index.dda_fileno;
   1654 	if (dda->dda_pos > dda->dda_index.dda_blkcount) {
   1655 		fileno += (dda->dda_pos - dda->dda_index.dda_blkcount);
   1656 	}
   1657 
   1658 	if (DDA_GET_FM_FWD_PEND(dda)) {
   1659 		if (DDA_GET_FM_NOSKIP(dda)) {
   1660 			fileno--;
   1661 		}
   1662 	}
   1663 
   1664 	return (fileno);
   1665 }
   1666 
   1667 /*
   1668  * dda_get_blkno
   1669  *
   1670  * Parameters:
   1671  *	- dda:		DDA tape drive.
   1672  *
   1673  * Get DDA media blkno.
   1674  * If positioned at filemark then the blkno is 0.
   1675  * Otherwise backup until bot or filemark is encountered.
   1676  *
   1677  * Return Values:
   1678  *	fileno : filemark number
   1679  *
   1680  */
   1681 static int
   1682 dda_get_blkno(dda_t *dda, int64_t *blkno)
   1683 {
   1684 	dda_istate_t	istate;
   1685 	int		err = 0;
   1686 
   1687 	if (dda->dda_pos > dda->dda_index.dda_blkcount) {
   1688 		*blkno = 0;
   1689 		return (0);
   1690 	}
   1691 	dda_save_istate(dda, &istate);
   1692 	*blkno = dda->dda_pos;
   1693 	dda->dda_index_offset -= sizeof (dda_index_t);
   1694 	while (dda->dda_index_offset >= 0) {
   1695 		if (err = dda_read_index(dda)) {
   1696 			break;
   1697 		}
   1698 		if (dda->dda_index.dda_fmcount) {
   1699 			break;
   1700 		}
   1701 		*blkno += dda->dda_index.dda_blkcount;
   1702 		dda->dda_index_offset -= sizeof (dda_index_t);
   1703 	}
   1704 	dda_restore_istate(dda, &istate);
   1705 	return (err);
   1706 }
   1707 
   1708 /*
   1709  * dda_write_truncate
   1710  *
   1711  * Parameters:
   1712  *	- dda:		DDA tape drive.
   1713  *
   1714  * Truncate DDA media at the current position.
   1715  * If at bot then stripe align the data file offset.
   1716  *
   1717  * Return Values:
   1718  *	0 : success
   1719  *	errno : failure
   1720  *
   1721  */
   1722 static int
   1723 dda_write_truncate(dda_t *dda)
   1724 {
   1725 	int	err;
   1726 
   1727 	dda->dda_flags = 0;
   1728 
   1729 	if (DDA_IS_BOT(dda)) {
   1730 		bzero(&dda->dda_index, sizeof (dda_index_t));
   1731 		DDA_SET_INDEX(dda);
   1732 	}
   1733 
   1734 	if (dda->dda_pos != DDA_INDEX_COUNT(dda)) {
   1735 		DDA_SET_INDEX(dda);
   1736 		if (dda->dda_pos <= dda->dda_index.dda_blkcount) {
   1737 			dda->dda_index.dda_fmcount = 0;
   1738 			dda->dda_index.dda_blkcount = dda->dda_pos;
   1739 		} else {
   1740 			dda->dda_index.dda_fmcount =
   1741 			    dda->dda_pos - dda->dda_index.dda_blkcount;
   1742 		}
   1743 
   1744 		if (DDA_INDEX_COUNT(dda) == 0) {
   1745 			dda->dda_index_offset -= sizeof (dda_index_t);
   1746 			if (dda->dda_index_offset < 0) {
   1747 				bzero(&dda->dda_index, sizeof (dda_index_t));
   1748 				dda->dda_index_offset = 0;
   1749 				dda->dda_pos = 0;
   1750 			} else {
   1751 				if (err = dda_read_index(dda)) {
   1752 					return (err);
   1753 				}
   1754 				dda->dda_pos = DDA_INDEX_COUNT(dda);
   1755 			}
   1756 		}
   1757 	}
   1758 
   1759 	if (err = dda_write_index(dda)) {
   1760 		dda->dda_status = KEY_MEDIUM_ERROR;
   1761 		return (err);
   1762 	}
   1763 
   1764 	dda->dda_index_fsize = dda->dda_index_offset + sizeof (dda_index_t);
   1765 	if (err = dda_vn_truncate(dda, dda->dda_index_vp,
   1766 	    dda->dda_index_fsize)) {
   1767 		return (err);
   1768 	}
   1769 
   1770 	dda->dda_data_fsize = dda_data_offset(dda);
   1771 	if (err = dda_vn_truncate(dda, dda->dda_data_vp,
   1772 	    dda->dda_data_fsize)) {
   1773 		return (err);
   1774 	}
   1775 
   1776 	if (DDA_IS_BOT(dda)) {
   1777 		dda->dda_index.dda_offset += dda_stripe_align(dda);
   1778 	}
   1779 
   1780 	return (0);
   1781 }
   1782 
   1783 /*
   1784  * dda_tape_erase
   1785  *
   1786  * Parameters:
   1787  *	- dda:		DDA tape drive.
   1788  *
   1789  * Erase DDA media from the current position.
   1790  *
   1791  * Return Values:
   1792  *	0 : success
   1793  *	errno : failure
   1794  *
   1795  */
   1796 static int
   1797 dda_tape_erase(dda_t *dda)
   1798 {
   1799 	int	err;
   1800 
   1801 
   1802 	if (!dda->dda_loaded) {
   1803 		return (EIO);
   1804 	}
   1805 
   1806 	dda->dda_status = 0;
   1807 	dda->dda_resid = 0;
   1808 
   1809 	if (DDA_GET_READ_ONLY(dda)) {
   1810 		dda->dda_status = KEY_WRITE_PROTECT;
   1811 		return (EACCES);
   1812 	}
   1813 
   1814 	/*
   1815 	 * Erase from current logical position
   1816 	 */
   1817 	DDA_DEBUG2((dda_cmd_erase,
   1818 	    int, dda->dda_inst,
   1819 	    int64_t, DDA_LBA(dda)));
   1820 
   1821 	if (err = dda_write_truncate(dda)) {
   1822 		DDA_DEBUG2((dda_cmd_erase_err,
   1823 		    int, dda->dda_inst,
   1824 		    int, err));
   1825 	}
   1826 	return (err);
   1827 }
   1828 
   1829 /*
   1830  * dda_sync
   1831  *
   1832  * Parameters:
   1833  *	- dda:		DDA tape drive.
   1834  *
   1835  * Flush DDA media files to disk.
   1836  *
   1837  * Return Values:
   1838  *	0 : success
   1839  *	errno : failure
   1840  *
   1841  */
   1842 static int
   1843 dda_sync(dda_t *dda)
   1844 {
   1845 	int	err;
   1846 	int	rc;
   1847 	short	status;
   1848 
   1849 	/*
   1850 	 * Sync index and data files, report first error
   1851 	 */
   1852 
   1853 	err = dda_vn_sync(dda, dda->dda_index_vp);
   1854 	status = dda->dda_status;
   1855 
   1856 	if (rc = dda_vn_sync(dda, dda->dda_data_vp)) {
   1857 		if (err == 0) {
   1858 			status = dda->dda_status;
   1859 			err = rc;
   1860 		}
   1861 	}
   1862 
   1863 	dda->dda_status = status;
   1864 	return (err);
   1865 }
   1866 
   1867 /*
   1868  * dda_tape_wfm
   1869  *
   1870  * Parameters:
   1871  *	- dda:		DDA tape drive.
   1872  *	- count:	Number of filemarks to write.
   1873  *
   1874  * If zero filemarks then flush media to disk and return.
   1875  * Truncate DDA media if needed.
   1876  * If at physical end of media and no filemarks can be
   1877  * written then set status and return.
   1878  * Write the number of filemarks requested.
   1879  * Update position on media.
   1880  * Set residual for the number of filemarks not written.
   1881  * Flush DDA media to disk.
   1882  *
   1883  * Return Values:
   1884  *	0 : success
   1885  *	errno : failure
   1886  *
   1887  * Note:
   1888  *	A filemark is counted as 1 byte of used tape space.
   1889  */
   1890 static int
   1891 dda_tape_wfm(dda_t *dda, int count)
   1892 {
   1893 	int	err;
   1894 	int64_t	avail;
   1895 	int	ew;
   1896 
   1897 	if (!dda->dda_loaded) {
   1898 		return (EIO);
   1899 	}
   1900 	dda->dda_status = 0;
   1901 	dda->dda_resid = count;
   1902 
   1903 	if (DDA_GET_READ_ONLY(dda)) {
   1904 		dda->dda_status = KEY_WRITE_PROTECT;
   1905 		return (EACCES);
   1906 	}
   1907 
   1908 	DDA_DEBUG3((dda_cmd_wfm,
   1909 	    int, dda->dda_inst,
   1910 	    int64_t, DDA_LBA(dda),
   1911 	    int, count));
   1912 
   1913 	if (count == 0) {
   1914 		if (err = dda_write_index(dda)) {
   1915 			return (err);
   1916 		}
   1917 		err = dda_sync(dda);
   1918 		return (err);
   1919 	}
   1920 
   1921 	if (DDA_GET_TRUNC(dda) && (err = dda_write_truncate(dda))) {
   1922 		return (err);
   1923 	}
   1924 
   1925 	if (err = dda_ew_eom(dda, count, &avail, &ew)) {
   1926 		return (err);
   1927 	}
   1928 
   1929 	if (avail == 0) {
   1930 		/*
   1931 		 * Physical end of media.
   1932 		 */
   1933 		DDA_DEBUG2((dda_cmd_wfm_eom,
   1934 		    int, dda->dda_inst,
   1935 		    int64_t, DDA_LBA(dda)));
   1936 		dda->dda_status = SUN_KEY_EOT;
   1937 		return (EIO);
   1938 	}
   1939 
   1940 	DDA_SET_INDEX(dda);
   1941 	dda->dda_index.dda_fmcount += avail;
   1942 	if (err = dda_write_index(dda)) {
   1943 		dda->dda_index.dda_fmcount -= avail;
   1944 		return (err);
   1945 	}
   1946 
   1947 	dda->dda_resid -= avail;
   1948 	dda->dda_pos += avail;
   1949 	dda->dda_blkno = 0;
   1950 
   1951 	if (err = dda_sync(dda)) {
   1952 		return (err);
   1953 	}
   1954 
   1955 	DDA_CLR_FM_NEEDED(dda);
   1956 
   1957 	return (0);
   1958 }
   1959 
   1960 /*
   1961  * dda_tape_write
   1962  *
   1963  * Parameters:
   1964  *	- dda:		DDA tape drive.
   1965  *	- uio:		Vector I/O operations.
   1966  *
   1967  * DDA write supports all write lengths allowed by the kernel.
   1968  *
   1969  * A variable length write may span two index records when the
   1970  * length is not modulus max record size.
   1971  *
   1972  * A fixed length write requires the data length to be a multiple
   1973  * the record size.
   1974  *
   1975  * If read only media then set write protect status and return.
   1976  * If zero length write then return.
   1977  * Calculate number of blocks to write based on the record size.
   1978  * Truncate media if needed.
   1979  * Get early warning and physical end of media.
   1980  * Adjust length to write in blocks based on tape space remaining.
   1981  * If positioned past early warning then alternating write failures
   1982  * occur.
   1983  * Get data file offset.
   1984  * Write the data to the data file.
   1985  * If write error then set status and return errno.
   1986  * If write returns residual then adjust counts and truncate
   1987  * incomplete blocks.
   1988  * Update index record with new media position.
   1989  * If write crosses into early warning then set status.
   1990  * Write complete.
   1991  *
   1992  *
   1993  * Return Values:
   1994  *	0 : success
   1995  *	errno : failure
   1996  *
   1997  */
   1998 static int
   1999 dda_tape_write(dda_t *dda, struct uio *uio)
   2000 {
   2001 	int		err;
   2002 	int32_t		len;
   2003 	int32_t		total;
   2004 	int32_t		blksize;
   2005 	int32_t		blkcount;
   2006 	int64_t		avail;
   2007 	int		ew;
   2008 	int		rc;
   2009 	off64_t		data_offset;
   2010 	int32_t		blks;
   2011 	int64_t		offset;
   2012 	dda_istate_t	istate;
   2013 	int32_t		partial = 0;
   2014 
   2015 	if (!dda->dda_loaded) {
   2016 		return (EIO);
   2017 	}
   2018 	dda->dda_status = 0;
   2019 	dda->dda_resid = 0;
   2020 
   2021 	if (DDA_GET_READ_ONLY(dda)) {
   2022 		dda->dda_status = KEY_WRITE_PROTECT;
   2023 		dda->dda_resid = uio->uio_resid;
   2024 		return (EACCES);
   2025 	}
   2026 
   2027 	if ((total = uio->uio_resid) == 0) {
   2028 		if (err = dda_write_index(dda)) {
   2029 			return (err);
   2030 		}
   2031 		return (0);
   2032 	}
   2033 	len = total;
   2034 
   2035 	dda_save_istate(dda, &istate);
   2036 
   2037 	if (dda->dda_rec_size == 0) {
   2038 		/* variable block(s) */
   2039 		if (len > DDA_MAX_REC_SIZE) {
   2040 			/* write may span this index record and next */
   2041 			blksize = DDA_MAX_REC_SIZE;
   2042 			blkcount = len / DDA_MAX_REC_SIZE;
   2043 			partial = len - (blksize * blkcount);
   2044 		} else {
   2045 			/* single block write */
   2046 			blksize = len;
   2047 			blkcount = 1;
   2048 		}
   2049 		dda->dda_resid = len;
   2050 	} else {
   2051 		/* fixed block(s) */
   2052 		if ((len % dda->dda_rec_size) != 0) {
   2053 			return (EINVAL);
   2054 		}
   2055 		blksize = dda->dda_rec_size;
   2056 		blkcount = (len / dda->dda_rec_size);
   2057 		dda->dda_resid = blkcount;
   2058 	}
   2059 
   2060 	DDA_DEBUG4((dda_cmd_write,
   2061 	    int, dda->dda_inst,
   2062 	    int64_t, DDA_LBA(dda),
   2063 	    int32_t, uio->uio_resid,
   2064 	    int32_t, blkcount));
   2065 
   2066 	if (DDA_GET_TRUNC(dda) && (err = dda_write_truncate(dda))) {
   2067 		return (err);
   2068 	}
   2069 
   2070 	if (err = dda_ew_eom(dda, len, &avail, &ew)) {
   2071 		return (err);
   2072 	}
   2073 
   2074 	if (ew) {
   2075 		/*
   2076 		 * Logical end of media, alternating
   2077 		 * zero byte writes after early warning.
   2078 		 */
   2079 		DDA_DEBUG2((dda_cmd_write_ew,
   2080 		    int, dda->dda_inst,
   2081 		    int, DDA_GET_EW(dda)));
   2082 		if (DDA_GET_EW(dda)) {
   2083 			DDA_CLR_EW(dda);
   2084 			dda->dda_status = SUN_KEY_EOT;
   2085 			if (avail < blksize) {
   2086 				/*
   2087 				 * Physical end of media hit.
   2088 				 */
   2089 				return (EIO);
   2090 			}
   2091 			return (0);
   2092 		}
   2093 
   2094 		/*
   2095 		 * Next early warning write is zero bytes.
   2096 		 */
   2097 		DDA_SET_EW(dda);
   2098 	}
   2099 
   2100 	if (avail < len) {
   2101 		/* at least one block */
   2102 		if (avail < blksize) {
   2103 			/*
   2104 			 * Physical end of media hit.
   2105 			 */
   2106 			DDA_DEBUG2((dda_cmd_write_eom,
   2107 			    int, dda->dda_inst,
   2108 			    int64_t, DDA_LBA(dda)));
   2109 			dda->dda_status = SUN_KEY_EOT;
   2110 			return (EIO);
   2111 		}
   2112 
   2113 		/* adjust counts */
   2114 		blkcount = avail / blksize;
   2115 		len = blkcount * blksize;
   2116 		if (dda->dda_rec_size == 0) {
   2117 			partial = 0;
   2118 			dda->dda_resid = (total - len);
   2119 		} else {
   2120 			dda->dda_resid = (total - len) / blksize;
   2121 		}
   2122 	}
   2123 
   2124 	if (dda->dda_pos > dda->dda_index.dda_blkcount &&
   2125 	    dda->dda_index.dda_fmcount) {
   2126 		dda_gen_next_index(dda, blksize);
   2127 		dda->dda_index.dda_offset += dda_stripe_align(dda);
   2128 	}
   2129 
   2130 	if (blksize != dda->dda_index.dda_blksize) {
   2131 		if (DDA_IS_BOT(dda)) {
   2132 			dda->dda_index.dda_blksize = blksize;
   2133 		} else {
   2134 			if (err = dda_write_index(dda)) {
   2135 				goto write_error;
   2136 			}
   2137 			dda_gen_next_index(dda, blksize);
   2138 		}
   2139 	}
   2140 
   2141 	/* write data */
   2142 	data_offset = dda_data_offset(dda);
   2143 	uio->uio_loffset = data_offset;
   2144 	uio->uio_resid = len;
   2145 	(void) VOP_RWLOCK(dda->dda_data_vp, V_WRITELOCK_TRUE, NULL);
   2146 	err = VOP_WRITE(dda->dda_data_vp, uio, 0, dda->dda_cred, NULL);
   2147 	VOP_RWUNLOCK(dda->dda_data_vp, V_WRITELOCK_TRUE, NULL);
   2148 
   2149 	if (err) {
   2150 		DDA_DEBUG4((dda_cmd_write_vn_err,
   2151 		    int, dda->dda_inst,
   2152 		    int64_t, DDA_LBA(dda),
   2153 		    off64_t, data_offset,
   2154 		    int, err));
   2155 		dda_vn_error_skey(dda, err);
   2156 		goto write_error;
   2157 	}
   2158 
   2159 	if (uio->uio_resid) {
   2160 		if (dda->dda_rec_size == 0) {
   2161 			partial = 0;
   2162 		}
   2163 
   2164 		/* remove blocks from data */
   2165 
   2166 		blks = uio->uio_resid / blksize;
   2167 		if (uio->uio_resid - (blks * blksize)) {
   2168 			blks++;
   2169 		}
   2170 		blkcount -= blks;
   2171 		if (blkcount == 0) {
   2172 			goto write_error;
   2173 		}
   2174 
   2175 		len = blkcount * blksize;
   2176 		offset = data_offset + len;
   2177 
   2178 		if (err = dda_vn_truncate(dda, dda->dda_data_vp, offset)) {
   2179 			goto write_error;
   2180 		}
   2181 	}
   2182 
   2183 	/* update index record block count */
   2184 	DDA_SET_INDEX(dda);
   2185 	dda->dda_index.dda_blkcount += blkcount;
   2186 	dda->dda_pos += blkcount;
   2187 	dda->dda_blkno += blkcount;
   2188 
   2189 	if (partial) {
   2190 		if (err = dda_write_index(dda)) {
   2191 			goto write_error;
   2192 		}
   2193 		dda_save_istate(dda, &istate);
   2194 		dda_gen_next_index(dda, partial);
   2195 
   2196 		/* update new index record with block */
   2197 		DDA_SET_INDEX(dda);
   2198 		dda->dda_index.dda_blkcount = 1;
   2199 		dda->dda_pos++;
   2200 		dda->dda_blkno++;
   2201 	}
   2202 
   2203 	if (total == len) {
   2204 		dda->dda_resid = 0;
   2205 	} else {
   2206 		uio->uio_resid = total - len;
   2207 		if (dda->dda_rec_size == 0) {
   2208 			dda->dda_resid = (total - len);
   2209 		} else {
   2210 			dda->dda_resid = (total - len) / blksize;
   2211 		}
   2212 
   2213 		DDA_DEBUG4((dda_cmd_write_done,
   2214 		    int, dda->dda_inst,
   2215 		    int64_t, DDA_LBA(dda),
   2216 		    int32_t, blkcount,
   2217 		    int32_t, uio->uio_resid));
   2218 	}
   2219 
   2220 	if (ew) {
   2221 		DDA_DEBUG2((dda_cmd_write_ew,
   2222 		    int, dda->dda_inst,
   2223 		    int64_t, DDA_LBA(dda)));
   2224 		dda->dda_status = SUN_KEY_EOT;
   2225 	}
   2226 
   2227 	DDA_SET_FM_NEEDED(dda);
   2228 
   2229 	dda->dda_data_fsize += total - uio->uio_resid;
   2230 
   2231 	return (err);
   2232 
   2233 write_error:
   2234 	/* no blocks written */
   2235 	uio->uio_resid = total;
   2236 	if (dda->dda_rec_size == 0) {
   2237 		dda->dda_resid = total;
   2238 	} else {
   2239 		dda->dda_resid = total / blksize;
   2240 	}
   2241 	dda_restore_istate(dda, &istate);
   2242 	if (DDA_IS_BOT(dda)) {
   2243 		dda->dda_index.dda_blksize = 0;
   2244 	}
   2245 	DDA_SET_TRUNC(dda);
   2246 	if (rc = dda_write_truncate(dda)) {
   2247 		if (err == 0) {
   2248 			err = rc;
   2249 		}
   2250 	}
   2251 	DDA_DEBUG3((dda_cmd_write_err,
   2252 	    int, dda->dda_inst,
   2253 	    int64_t, DDA_LBA(dda),
   2254 	    int, err));
   2255 	if (err) {
   2256 		/* original error */
   2257 		return (err);
   2258 	}
   2259 	return (EIO);
   2260 }
   2261 
   2262 /*
   2263  * dda_tape_read
   2264  *
   2265  * Parameters:
   2266  *	- dda:		DDA tape drive.
   2267  *	- uio:		Vector I/O operations.
   2268  *
   2269  * DDA read supports all read lengths allowed by the kernel.
   2270  *
   2271  * A variable length read may span two index records.
   2272  *
   2273  * The DDA variable length read supports the ILI (incorrect length
   2274  * indicator).
   2275  *
   2276  * A fixed length read requires the data length to be a multiple of
   2277  * the record size.
   2278  *
   2279  * If zero length read then return success.
   2280  * Calculate the number of blocks to read based on the record size.
   2281  * Get early warning and physical end of media.
   2282  * Adjust length (blocks) to read based on tape space remaining.
   2283  * Read the data from the data file.
   2284  * If a read error occurred or residual from dda's adjusted read length
   2285  * then set status and return.
   2286  * Update the index record with new media position.
   2287  * Read complete.
   2288  *
   2289  *
   2290  * Return Values:
   2291  *	0 : success
   2292  *	errno : failure
   2293  *
   2294  */
   2295 int
   2296 dda_tape_read(dda_t *dda, struct uio *uio)
   2297 {
   2298 	int32_t		len;
   2299 	int32_t		total;
   2300 	int32_t		blksize;
   2301 	int32_t		blkcount;
   2302 	int		err;
   2303 	off64_t		fsize;
   2304 	dda_istate_t	istate;
   2305 	off64_t		data_offset;
   2306 	int		overflow = 0;
   2307 	int		noskip;
   2308 	int		partial = 0;
   2309 	off64_t		offset;
   2310 	dda_index_t	index;
   2311 
   2312 	if (!dda->dda_loaded) {
   2313 		return (EIO);
   2314 	}
   2315 	dda->dda_status = 0;
   2316 	dda->dda_resid = 0;
   2317 	DDA_SET_TRUNC(dda);
   2318 	DDA_CLR_FM_NEEDED(dda);
   2319 	DDA_CLR_EW(dda);
   2320 
   2321 	if ((total = uio->uio_resid) == 0) {
   2322 		if (err = dda_write_index(dda)) {
   2323 			return (err);
   2324 		}
   2325 		return (0);
   2326 	}
   2327 	len = total;
   2328 
   2329 	dda_save_istate(dda, &istate);
   2330 
   2331 	if (dda->dda_rec_size == 0) {
   2332 		/* variable */
   2333 		if (len > DDA_MAX_REC_SIZE) {
   2334 			/* read may span this index record and next */
   2335 			blksize = DDA_MAX_REC_SIZE;
   2336 			blkcount = len / DDA_MAX_REC_SIZE;
   2337 			if (len - (blksize * blkcount)) {
   2338 				/* actual partial blksize determined below */
   2339 				partial = 1;
   2340 			}
   2341 		} else {
   2342 			/* single block read */
   2343 			blksize = len;
   2344 			blkcount = 1;
   2345 		}
   2346 		dda->dda_resid = len;
   2347 	} else {
   2348 		/* fixed */
   2349 		if (dda->dda_ili) {
   2350 			cmn_err(CE_WARN, "%d Incorrect Length Indicator Set",
   2351 			    dda->dda_inst);
   2352 			return (EINVAL);
   2353 		}
   2354 		if ((len % dda->dda_rec_size) != 0) {
   2355 			cmn_err(CE_WARN, "%d read: not modulo %d block size",
   2356 			    dda->dda_inst, dda->dda_rec_size);
   2357 			return (EINVAL);
   2358 		}
   2359 		blksize = dda->dda_rec_size;
   2360 		blkcount = (len / dda->dda_rec_size);
   2361 		dda->dda_resid = blkcount;
   2362 	}
   2363 
   2364 	if (err = dda_write_index(dda)) {
   2365 		return (err);
   2366 	}
   2367 
   2368 	DDA_DEBUG4((dda_cmd_read,
   2369 	    int, dda->dda_inst,
   2370 	    int64_t, DDA_LBA(dda),
   2371 	    int32_t, uio->uio_resid,
   2372 	    int32_t, blkcount));
   2373 
   2374 	if (DDA_GET_FM_FWD_PEND(dda)) {
   2375 		noskip = DDA_GET_FM_NOSKIP(dda);
   2376 		DDA_CLR_FM_FWD_PEND(dda);
   2377 		if (noskip) {
   2378 			DDA_DEBUG1((dda_cmd_read_ffpns,
   2379 			    int, dda->dda_inst));
   2380 
   2381 			dda->dda_status = SUN_KEY_EOF;
   2382 			dda->dda_blkno = 0;
   2383 			return (0);
   2384 		}
   2385 
   2386 		DDA_DEBUG1((dda_cmd_read_ffpc,
   2387 		    int, dda->dda_inst));
   2388 	}
   2389 
   2390 	fsize = dda->dda_index_fsize - sizeof (dda_index_t);
   2391 
   2392 	if (dda->dda_pos >= DDA_INDEX_COUNT(dda)) {
   2393 		dda->dda_index_offset += sizeof (dda_index_t);
   2394 		if (dda->dda_index_offset > fsize) {
   2395 
   2396 			DDA_DEBUG3((dda_cmd_read_eot,
   2397 			    int, dda->dda_inst,
   2398 			    int64_t, DDA_LBA(dda),
   2399 			    int, DDA_GET_EOT_EIO(dda)));
   2400 
   2401 			dda->dda_index_offset -= sizeof (dda_index_t);
   2402 			dda->dda_status = SUN_KEY_EOT;
   2403 			if (DDA_GET_EOT_EIO(dda) == 0) {
   2404 				DDA_SET_EOT_EIO(dda);
   2405 				dda->dda_resid = len;
   2406 				return (EIO);
   2407 			}
   2408 			return (0);
   2409 		}
   2410 		if (err = dda_read_index(dda)) {
   2411 			dda_restore_istate(dda, &istate);
   2412 			return (err);
   2413 		}
   2414 	}
   2415 
   2416 	DDA_CLR_EOT_EIO(dda);
   2417 
   2418 	if (DDA_IS_FM(dda)) {
   2419 		DDA_DEBUG2((dda_cmd_read_fm,
   2420 		    int, dda->dda_inst,
   2421 		    int64_t, DDA_LBA(dda)));
   2422 
   2423 		DDA_SET_FM_FWD_PEND(dda);
   2424 		dda->dda_pos++;
   2425 		dda->dda_status = SUN_KEY_EOF;
   2426 		dda->dda_blkno = 0;
   2427 		return (0);
   2428 	}
   2429 
   2430 	if (blksize != dda->dda_index.dda_blksize) {
   2431 		if (blksize < dda->dda_index.dda_blksize) {
   2432 			len = blksize;
   2433 			if (dda->dda_ili == 0) {
   2434 				overflow = 1;
   2435 			}
   2436 		} else {
   2437 			len = dda->dda_index.dda_blksize;
   2438 		}
   2439 		blkcount = 1;
   2440 		blksize = len;
   2441 		partial = 0;
   2442 
   2443 		DDA_DEBUG4((dda_cmd_read_blksz,
   2444 		    int, dda->dda_inst,
   2445 		    int64_t, blksize,
   2446 		    int64_t, blkcount,
   2447 		    int, overflow));
   2448 	}
   2449 
   2450 	if (dda->dda_pos + blkcount + partial > dda->dda_index.dda_blkcount) {
   2451 		if (partial) {
   2452 			/* get partial from next index record */
   2453 			offset = dda->dda_index_offset + sizeof (dda_index_t);
   2454 			if (offset > fsize) {
   2455 				partial = 0;
   2456 			} else if (dda_vn_read(dda, dda->dda_index_vp,
   2457 			    &index, sizeof (dda_index_t), offset)) {
   2458 				partial = 0;
   2459 			} else {
   2460 				DDA_BE_INDEX(index, index);
   2461 				if (index.dda_blkcount == 0) {
   2462 					partial = 0;
   2463 				}
   2464 			}
   2465 		}
   2466 
   2467 		blkcount = dda->dda_index.dda_blkcount - dda->dda_pos;
   2468 		if (blkcount == 0) {
   2469 			if (dda->dda_rec_size == 0) {
   2470 				dda->dda_resid = total;
   2471 			} else {
   2472 				dda->dda_resid = total / blksize;
   2473 			}
   2474 			DDA_DEBUG1((dda_cmd_read_noblks,
   2475 			    int, dda->dda_inst));
   2476 			return (0);
   2477 		}
   2478 
   2479 		len = blkcount * blksize;
   2480 
   2481 		if (partial) {
   2482 			len += index.dda_blksize;
   2483 		}
   2484 
   2485 		DDA_DEBUG4((dda_cmd_read_numblks,
   2486 		    int, dda->dda_inst,
   2487 		    int32_t, len,
   2488 		    int32_t, blksize,
   2489 		    int32_t, blkcount));
   2490 
   2491 	} else if (partial) {
   2492 		/* current index record contains partial */
   2493 		len += dda->dda_index.dda_blksize;
   2494 	}
   2495 
   2496 	if (len > total) {
   2497 		len = total;
   2498 		if (dda->dda_ili == 0) {
   2499 			overflow = 1;
   2500 		}
   2501 	}
   2502 
   2503 	DDA_DEBUG2((dda_cmd_read_partial,
   2504 	    int, dda->dda_inst,
   2505 	    int32_t, partial));
   2506 
   2507 	data_offset = dda_data_offset(dda);
   2508 	uio->uio_loffset = data_offset;
   2509 	uio->uio_resid = len;
   2510 	(void) VOP_RWLOCK(dda->dda_data_vp, V_WRITELOCK_FALSE, NULL);
   2511 	err = VOP_READ(dda->dda_data_vp, uio, 0, dda->dda_cred, NULL);
   2512 	VOP_RWUNLOCK(dda->dda_data_vp, V_WRITELOCK_FALSE, NULL);
   2513 
   2514 	/*
   2515 	 * If a read error occurred or residual from dda adjusted length
   2516 	 * then don't return any data.
   2517 	 */
   2518 
   2519 	if (err) {
   2520 		DDA_DEBUG4((dda_cmd_read_vn_err,
   2521 		    int, dda->dda_inst,
   2522 		    int64_t, DDA_LBA(dda),
   2523 		    off64_t, data_offset,
   2524 		    int, err));
   2525 
   2526 		dda_restore_istate(dda, &istate);
   2527 		uio->uio_resid = total;
   2528 		dda_vn_error_skey(dda, err);
   2529 		if (dda->dda_rec_size == 0) {
   2530 			dda->dda_resid = total;
   2531 		} else {
   2532 			dda->dda_resid = total / blksize;
   2533 		}
   2534 		return (err);
   2535 	}
   2536 
   2537 	if (uio->uio_resid) {
   2538 		DDA_DEBUG2((dda_cmd_read_resid,
   2539 		    int, dda->dda_inst,
   2540 		    int32_t, uio->uio_resid));
   2541 
   2542 		uio->uio_resid = total;
   2543 		if (dda->dda_rec_size == 0) {
   2544 			dda->dda_resid = total;
   2545 		} else {
   2546 			dda->dda_resid = total / blksize;
   2547 		}
   2548 		dda_restore_istate(dda, &istate);
   2549 		return (EIO);
   2550 	}
   2551 
   2552 
   2553 	/*
   2554 	 * Successful read, adjust index record and counters.
   2555 	 */
   2556 
   2557 	dda->dda_pos += blkcount;
   2558 
   2559 	if (total == len) {
   2560 		dda->dda_blkno += blkcount;
   2561 		dda->dda_resid = 0;
   2562 	} else {
   2563 		uio->uio_resid = total - len;
   2564 		if (dda->dda_rec_size == 0) {
   2565 			dda->dda_resid = uio->uio_resid;
   2566 		} else {
   2567 			dda->dda_resid = uio->uio_resid / blksize;
   2568 		}
   2569 		dda->dda_blkno += uio->uio_resid / blksize;
   2570 	}
   2571 
   2572 	if (partial) {
   2573 		dda->dda_pos = 1;
   2574 		dda->dda_blkno++;
   2575 		dda->dda_index = index;
   2576 		dda->dda_index_offset += sizeof (dda_index_t);
   2577 	}
   2578 
   2579 	DDA_DEBUG3((dda_cmd_read_short,
   2580 	    int, dda->dda_inst,
   2581 	    int64_t, DDA_LBA(dda),
   2582 	    int32_t, dda->dda_resid));
   2583 
   2584 	if (overflow) {
   2585 		DDA_DEBUG2((dda_cmd_read_overflow,
   2586 		    int, dda->dda_inst,
   2587 		    int64_t, DDA_LBA(dda)));
   2588 		dda->dda_resid = 0;
   2589 		err = ENOMEM;
   2590 	}
   2591 
   2592 	return (err);
   2593 }
   2594 
   2595 /*
   2596  * dda_tape_locate
   2597  *
   2598  * Parameters:
   2599  *	- dda:		DDA tape drive.
   2600  *	- position:	Locate to LBA.
   2601  *
   2602  * Locate to LBA requested.
   2603  *
   2604  * Return Values:
   2605  *	0 : success
   2606  *	errno : failure, positioned at bot or eom
   2607  *
   2608  */
   2609 static int
   2610 dda_tape_locate(dda_t *dda, off64_t position)
   2611 {
   2612 	int		err;
   2613 	int		found;
   2614 	int64_t		lba;
   2615 	dda_istate_t	istate;
   2616 	int		rc;
   2617 
   2618 
   2619 	if (!dda->dda_loaded) {
   2620 		return (EIO);
   2621 	}
   2622 
   2623 	dda->dda_status = 0;
   2624 	dda->dda_resid = 0;
   2625 
   2626 	if (err = dda_write_index(dda)) {
   2627 		return (err);
   2628 	}
   2629 
   2630 	dda->dda_blkno = 0;
   2631 	dda->dda_resid = 0;
   2632 	dda->dda_flags = 0;
   2633 	DDA_SET_TRUNC(dda);
   2634 	lba = DDA_LBA(dda);
   2635 
   2636 	DDA_DEBUG3((dda_cmd_locate,
   2637 	    int, dda->dda_inst,
   2638 	    int64_t, DDA_LBA(dda),
   2639 	    off64_t, position));
   2640 
   2641 	dda_save_istate(dda, &istate);
   2642 	if (err = dda_bsearch(dda, position, dda_locate_compare, &found)) {
   2643 		DDA_DEBUG2((dda_cmd_locate_err,
   2644 		    int, dda->dda_inst,
   2645 		    int, err));
   2646 		dda_restore_istate(dda, &istate);
   2647 		return (err);
   2648 	}
   2649 
   2650 	if (!found) {
   2651 		/*
   2652 		 * Locate unsuccessful,
   2653 		 * position based on direction of search
   2654 		 */
   2655 		if (position < lba) {
   2656 			if (err = dda_tape_rewind(dda)) {
   2657 				return (err);
   2658 			}
   2659 			dda->dda_status = SUN_KEY_BOT;
   2660 			dda->dda_resid = 0;
   2661 		} else {
   2662 			if (err = dda_tape_eom(dda)) {
   2663 				return (err);
   2664 			}
   2665 			dda->dda_status = KEY_BLANK_CHECK;
   2666 			dda->dda_resid = 0;
   2667 		}
   2668 		err = EIO;
   2669 	}
   2670 	if (rc = dda_get_blkno(dda, &dda->dda_blkno)) {
   2671 		err = rc;
   2672 	}
   2673 
   2674 	DDA_DEBUG4((dda_cmd_locate_done,
   2675 	    int, dda->dda_inst,
   2676 	    int64_t, DDA_LBA(dda),
   2677 	    int64_t, dda_get_fileno(dda),
   2678 	    int64_t, dda->dda_blkno));
   2679 
   2680 	return (err);
   2681 }
   2682 
   2683 /*
   2684  * dda_tape_fsr
   2685  *
   2686  * Parameters:
   2687  *	- dda:		DDA tape drive.
   2688  *	- count:	Number of records to forward space.
   2689  *
   2690  * Forward space records the requested count.
   2691  * Set truncate needed for write that may follow.
   2692  * Clear filemark forward pending.
   2693  * Clear alternating write success at early warning.
   2694  * If filemark is hit during fsr then cross the filemark but report
   2695  * logical position in front of the filemark to the user.
   2696  *
   2697  * Return Values:
   2698  *	0 : success
   2699  *	errno : failure
   2700  *
   2701  */
   2702 static int
   2703 dda_tape_fsr(dda_t *dda, int count)
   2704 {
   2705 	int		err;
   2706 	off64_t		fsize;
   2707 	dda_istate_t	istate;
   2708 	int		fm;
   2709 	int64_t		blks;
   2710 
   2711 
   2712 	if (!dda->dda_loaded) {
   2713 		return (EIO);
   2714 	}
   2715 
   2716 	dda->dda_status = 0;
   2717 	dda->dda_resid = count;
   2718 
   2719 	if (err = dda_write_index(dda)) {
   2720 		return (err);
   2721 	}
   2722 
   2723 	DDA_SET_TRUNC(dda);
   2724 	DDA_CLR_FM_NEEDED(dda);
   2725 	DDA_CLR_EW(dda);
   2726 
   2727 	DDA_DEBUG4((dda_cmd_fsr,
   2728 	    int, dda->dda_inst,
   2729 	    int64_t, DDA_LBA(dda),
   2730 	    int64_t, dda_get_fileno(dda),
   2731 	    int, count));
   2732 
   2733 	fsize = dda->dda_index_fsize - sizeof (dda_index_t);
   2734 
   2735 	while (dda->dda_resid) {
   2736 		dda_save_istate(dda, &istate);
   2737 
   2738 		if (DDA_GET_FM_FWD_PEND(dda)) {
   2739 			dda->dda_status = SUN_KEY_EOF;
   2740 			return (EIO);
   2741 		}
   2742 
   2743 		if (dda->dda_pos >= DDA_INDEX_COUNT(dda)) {
   2744 			dda->dda_index_offset += sizeof (dda_index_t);
   2745 			if (dda->dda_index_offset > fsize) {
   2746 				dda_restore_istate(dda, &istate);
   2747 				dda->dda_status = KEY_BLANK_CHECK;
   2748 				err = EIO;
   2749 				break;
   2750 			}
   2751 			if (err = dda_read_index(dda)) {
   2752 				dda_restore_istate(dda, &istate);
   2753 				DDA_DEBUG2((dda_cmd_fsr_err,
   2754 				    int, dda->dda_inst,
   2755 				    int, err));
   2756 				return (err);
   2757 			}
   2758 		}
   2759 
   2760 		DDA_DEBUG4((dda_cmd_fsr_where,
   2761 		    int, dda->dda_inst,
   2762 		    int64_t, dda->dda_pos,
   2763 		    int64_t, dda->dda_index.dda_blkcount,
   2764 		    int64_t, dda->dda_index.dda_fmcount));
   2765 
   2766 		fm = DDA_IS_FM(dda);
   2767 		if (fm) {
   2768 			blks = 1;
   2769 		} else {
   2770 			blks = dda->dda_index.dda_blkcount - dda->dda_pos;
   2771 			if (dda->dda_resid <= blks) {
   2772 				blks = dda->dda_resid;
   2773 			}
   2774 		}
   2775 
   2776 		DDA_DEBUG2((dda_cmd_fsr_blks,
   2777 		    int, dda->dda_inst,
   2778 		    int64_t, blks));
   2779 
   2780 		dda->dda_pos += blks;
   2781 		dda->dda_blkno += blks;
   2782 
   2783 		if (fm) {
   2784 			DDA_DEBUG1((dda_cmd_fsr_fm,
   2785 			    int, dda->dda_inst));
   2786 			DDA_SET_FM_FWD_PEND(dda);
   2787 			DDA_SET_FM_NOSKIP(dda);
   2788 			dda->dda_blkno--;
   2789 			dda->dda_status = SUN_KEY_EOF;
   2790 			err = EIO;
   2791 			break;
   2792 		}
   2793 
   2794 		dda->dda_resid -= blks;
   2795 	}
   2796 
   2797 	DDA_DEBUG4((dda_cmd_fsr_done,
   2798 	    int, dda->dda_inst,
   2799 	    int64_t, DDA_LBA(dda),
   2800 	    int64_t, dda_get_fileno(dda),
   2801 	    int32_t, dda->dda_resid));
   2802 
   2803 	return (err);
   2804 }
   2805 
   2806 /*
   2807  * dda_tape_bsr
   2808  *
   2809  * Parameters:
   2810  *	- dda:		DDA tape drive.
   2811  *	- count:	Number of records to backward space.
   2812  *
   2813  * Backspace records the requested count.
   2814  * Set truncate needed for write that may follow.
   2815  * Clear filemark forward pending.
   2816  * Clear alternating write success at early warning.
   2817  * If filemark is hit during bsr then do not cross the filemark.
   2818  *
   2819  * Return Values:
   2820  *	0 : success
   2821  *	errno : failure
   2822  *
   2823  */
   2824 static int
   2825 dda_tape_bsr(dda_t *dda, int count)
   2826 {
   2827 	int		err = 0;
   2828 	dda_istate_t	istate;
   2829 	int64_t		blks;
   2830 
   2831 
   2832 	if (!dda->dda_loaded) {
   2833 		return (EIO);
   2834 	}
   2835 
   2836 	dda->dda_status = 0;
   2837 	dda->dda_resid = count;
   2838 
   2839 	if (err = dda_write_index(dda)) {
   2840 		return (err);
   2841 	}
   2842 
   2843 	DDA_SET_TRUNC(dda);
   2844 	DDA_CLR_FM_NEEDED(dda);
   2845 	DDA_CLR_EW(dda);
   2846 
   2847 	DDA_DEBUG4((dda_cmd_bsr,
   2848 	    int, dda->dda_inst,
   2849 	    int64_t, DDA_LBA(dda),
   2850 	    int64_t, dda_get_fileno(dda),
   2851 	    int, count));
   2852 
   2853 	while (dda->dda_resid) {
   2854 		dda_save_istate(dda, &istate);
   2855 
   2856 		if (DDA_GET_FM_FWD_PEND(dda)) {
   2857 			DDA_CLR_FM_FWD_PEND(dda);
   2858 			dda->dda_pos--;
   2859 		}
   2860 
   2861 		if (dda->dda_pos <= 0) {
   2862 			dda->dda_index_offset -= sizeof (dda_index_t);
   2863 			if (dda->dda_index_offset < 0) {
   2864 				dda_restore_istate(dda, &istate);
   2865 				dda->dda_status = SUN_KEY_BOT;
   2866 				err = EIO;
   2867 				break;
   2868 			}
   2869 			if (err = dda_read_index(dda)) {
   2870 				dda_restore_istate(dda, &istate);
   2871 				DDA_DEBUG2((dda_cmd_bsr_err,
   2872 				    int, dda->dda_inst,
   2873 				    int, err));
   2874 				return (err);
   2875 			}
   2876 			dda->dda_pos = DDA_INDEX_COUNT(dda);
   2877 		}
   2878 
   2879 		DDA_DEBUG4((dda_cmd_bsr_where,
   2880 		    int, dda->dda_inst,
   2881 		    int64_t, dda->dda_pos,
   2882 		    int64_t, dda->dda_index.dda_blkcount,
   2883 		    int64_t, dda->dda_index.dda_fmcount));
   2884 
   2885 		blks = 0;
   2886 		if (dda->dda_pos <= dda->dda_index.dda_blkcount) {
   2887 			blks = dda->dda_pos;
   2888 			if (dda->dda_resid <= blks) {
   2889 				blks = dda->dda_resid;
   2890 			}
   2891 		}
   2892 
   2893 		DDA_DEBUG2((dda_cmd_bsr_blks,
   2894 		    int, dda->dda_inst,
   2895 		    int64_t, blks));
   2896 
   2897 		dda->dda_pos -= blks;
   2898 		dda->dda_blkno -= blks;
   2899 
   2900 		if (DDA_IS_FM(dda)) {
   2901 			DDA_DEBUG3((dda_cmd_bsr_fm,
   2902 			    int, dda->dda_inst,
   2903 			    int64_t, DDA_LBA(dda),
   2904 			    int64_t, dda_get_fileno(dda)));
   2905 
   2906 			dda->dda_blkno = 0;
   2907 			dda->dda_status = SUN_KEY_EOF;
   2908 			err = EIO;
   2909 			break;
   2910 		}
   2911 
   2912 		dda->dda_resid -= blks;
   2913 	}
   2914 
   2915 	DDA_DEBUG4((dda_cmd_bsr_done,
   2916 	    int, dda->dda_inst,
   2917 	    int64_t, DDA_LBA(dda),
   2918 	    int64_t, dda_get_fileno(dda),
   2919 	    int32_t, dda->dda_resid));
   2920 
   2921 	return (err);
   2922 }
   2923 
   2924 /*
   2925  * dda_tape_fsf
   2926  *
   2927  * Parameters:
   2928  *	- dda:		DDA tape drive.
   2929  *	- count:	Number of filemarks to forward space.
   2930  *
   2931  * Forward space filemarks.
   2932  * Set truncate needed for write that may follow.
   2933  * Clear filemark forward pending.
   2934  * Clear alternating write success at early warning.
   2935  * If filemark forward pending then decrement the count.
   2936  * Binary search to the filemark.
   2937  *
   2938  * Return Values:
   2939  *	0 : success
   2940  *	errno : failure
   2941  *
   2942  */
   2943 static int
   2944 dda_tape_fsf(dda_t *dda, int count)
   2945 {
   2946 	int		err;
   2947 	int		found;
   2948 	dda_istate_t	istate;
   2949 	int64_t		fileno;
   2950 
   2951 
   2952 	if (!dda->dda_loaded) {
   2953 		return (EIO);
   2954 	}
   2955 
   2956 	dda->dda_status = 0;
   2957 	dda->dda_resid = count;
   2958 
   2959 	if (err = dda_write_index(dda)) {
   2960 		return (err);
   2961 	}
   2962 
   2963 	dda->dda_blkno = 0;
   2964 	DDA_SET_TRUNC(dda);
   2965 	DDA_CLR_FM_NEEDED(dda);
   2966 	DDA_CLR_EOT_EIO(dda);
   2967 	DDA_CLR_EW(dda);
   2968 
   2969 	DDA_DEBUG4((dda_cmd_fsf,
   2970 	    int, dda->dda_inst,
   2971 	    int64_t, DDA_LBA(dda),
   2972 	    int64_t, dda_get_fileno(dda),
   2973 	    int, count));
   2974 
   2975 	if (DDA_GET_FM_FWD_PEND(dda)) {
   2976 		DDA_CLR_FM_FWD_PEND(dda);
   2977 		count--;
   2978 
   2979 		DDA_DEBUG4((dda_cmd_fsf_pend,
   2980 		    int, dda->dda_inst,
   2981 		    int64_t, DDA_LBA(dda),
   2982 		    int64_t, dda_get_fileno(dda),
   2983 		    int, count));
   2984 	}
   2985 
   2986 	dda_save_istate(dda, &istate);
   2987 	fileno = dda_get_fileno(dda) + count;
   2988 
   2989 	if (fileno == 0) {
   2990 		err = dda_tape_rewind(dda);
   2991 		goto fsf_done;
   2992 	}
   2993 
   2994 	if (err = dda_bsearch(dda, fileno, dda_fsf_compare, &found)) {
   2995 		DDA_DEBUG2((dda_cmd_fsf_err,
   2996 		    int, dda->dda_inst,
   2997 		    int, err));
   2998 		dda_restore_istate(dda, &istate);
   2999 		return (err);
   3000 	}
   3001 
   3002 	if (found) {
   3003 		/*
   3004 		 * Forward space file successful
   3005 		 */
   3006 		dda->dda_resid = 0;
   3007 	} else {
   3008 		/*
   3009 		 * Forward space file unsuccessful,
   3010 		 * position based on direction of search
   3011 		 */
   3012 		if (count < 0) {
   3013 			if (err = dda_tape_rewind(dda)) {
   3014 				return (err);
   3015 			}
   3016 			dda->dda_status = SUN_KEY_BOT;
   3017 			dda->dda_resid = dda_get_fileno(dda) - fileno;
   3018 		} else {
   3019 			if (err = dda_tape_eom(dda)) {
   3020 				return (err);
   3021 			}
   3022 			if (err = dda_get_blkno(dda, &dda->dda_blkno)) {
   3023 				return (err);
   3024 			}
   3025 			dda->dda_status = KEY_BLANK_CHECK;
   3026 			dda->dda_resid = fileno - dda_get_fileno(dda);
   3027 		}
   3028 		err = EIO;
   3029 	}
   3030 
   3031 fsf_done:
   3032 	DDA_DEBUG4((dda_cmd_fsf_done,
   3033 	    int, dda->dda_inst,
   3034 	    int64_t, DDA_LBA(dda),
   3035 	    int64_t, dda_get_fileno(dda),
   3036 	    int32_t, dda->dda_resid));
   3037 
   3038 	return (err);
   3039 }
   3040 
   3041 /*
   3042  * dda_tape_bsf
   3043  *
   3044  * Parameters:
   3045  *	- dda:		DDA tape drive.
   3046  *	- count:	Number of filemarks to backward space.
   3047  *
   3048  * Backward space filemarks.
   3049  * Zero flags.
   3050  * Set truncate needed for write that may follow.
   3051  * Binary search to filemark.
   3052  *
   3053  * Return Values:
   3054  *	0 : success
   3055  *	errno : failure
   3056  *
   3057  */
   3058 static int
   3059 dda_tape_bsf(dda_t *dda, int count)
   3060 {
   3061 	int		err;
   3062 	int		found;
   3063 	dda_istate_t	istate;
   3064 	int64_t		fileno;
   3065 	int		rc;
   3066 
   3067 
   3068 	if (!dda->dda_loaded) {
   3069 		return (EIO);
   3070 	}
   3071 
   3072 	dda->dda_status = 0;
   3073 	dda->dda_resid = count;
   3074 
   3075 	if (err = dda_write_index(dda)) {
   3076 		return (err);
   3077 	}
   3078 
   3079 	dda->dda_flags = 0;
   3080 	dda->dda_blkno = DDA_BLKNO_UNKNOWN;
   3081 	DDA_SET_TRUNC(dda);
   3082 	fileno = dda_get_fileno(dda) - count;
   3083 
   3084 	DDA_DEBUG4((dda_cmd_bsf,
   3085 	    int, dda->dda_inst,
   3086 	    int64_t, DDA_LBA(dda),
   3087 	    int64_t, dda_get_fileno(dda),
   3088 	    int, count));
   3089 
   3090 	dda_save_istate(dda, &istate);
   3091 	if (err = dda_bsearch(dda, fileno, dda_bsf_compare, &found)) {
   3092 		DDA_DEBUG2((dda_cmd_bsf_err,
   3093 		    int, dda->dda_inst,
   3094 		    int, err));
   3095 		dda_restore_istate(dda, &istate);
   3096 		return (err);
   3097 	}
   3098 
   3099 	if (found) {
   3100 		/*
   3101 		 * Backward space file successful
   3102 		 */
   3103 		dda->dda_resid = 0;
   3104 	} else {
   3105 		/*
   3106 		 * Backward space file unsuccessful,
   3107 		 * position based on direction of search
   3108 		 */
   3109 		if (count < 0) {
   3110 			if (err = dda_tape_eom(dda)) {
   3111 				return (err);
   3112 			}
   3113 			if (rc = dda_get_blkno(dda, &dda->dda_blkno)) {
   3114 				err = rc;
   3115 			}
   3116 			dda->dda_status = KEY_BLANK_CHECK;
   3117 			dda->dda_resid = fileno - dda_get_fileno(dda);
   3118 		} else {
   3119 			if (err = dda_tape_rewind(dda)) {
   3120 				return (err);
   3121 			}
   3122 			dda->dda_status = SUN_KEY_BOT;
   3123 			dda->dda_resid = dda_get_fileno(dda) - fileno;
   3124 		}
   3125 		err = EIO;
   3126 	}
   3127 
   3128 	DDA_DEBUG4((dda_cmd_bsf_done,
   3129 	    int, dda->dda_inst,
   3130 	    int64_t, DDA_LBA(dda),
   3131 	    int64_t, dda_get_fileno(dda),
   3132 	    int32_t, dda->dda_resid));
   3133 
   3134 	return (err);
   3135 }
   3136 
   3137 /*
   3138  * dda_tape_eom
   3139  *
   3140  * Parameters:
   3141  *	- dda:		DDA tape drive.
   3142  *
   3143  * Position to end of media.
   3144  *
   3145  * Return Values:
   3146  *	0 : success
   3147  *	errno : failure
   3148  *
   3149  */
   3150 static int
   3151 dda_tape_eom(dda_t *dda)
   3152 {
   3153 	off64_t	fsize;
   3154 	int	err;
   3155 
   3156 
   3157 	if (!dda->dda_loaded) {
   3158 		return (EIO);
   3159 	}
   3160 
   3161 	dda->dda_status = 0;
   3162 	dda->dda_resid = 0;
   3163 
   3164 	if (err = dda_write_index(dda)) {
   3165 		return (err);
   3166 	}
   3167 
   3168 	dda->dda_flags = 0;
   3169 	dda->dda_blkno = 0;
   3170 
   3171 	fsize = dda->dda_index_fsize - sizeof (dda_index_t);
   3172 	if (fsize < 0) {
   3173 		DDA_DEBUG2((dda_cmd_eom_err,
   3174 		    int, dda->dda_inst,
   3175 		    int, err));
   3176 		dda->dda_status = KEY_MEDIUM_ERROR;
   3177 		return (EIO);
   3178 	}
   3179 	if (dda->dda_index_offset != fsize) {
   3180 		dda->dda_index_offset = fsize;
   3181 		if (err = dda_read_index(dda)) {
   3182 			DDA_DEBUG2((dda_cmd_eom_err,
   3183 			    int, dda->dda_inst,
   3184 			    int, err));
   3185 			return (err);
   3186 		}
   3187 	}
   3188 	dda->dda_pos = DDA_INDEX_COUNT(dda);
   3189 
   3190 	DDA_DEBUG4((dda_cmd_eom,
   3191 	    int, dda->dda_inst,
   3192 	    int64_t, DDA_LBA(dda),
   3193 	    int64_t, dda_get_fileno(dda),
   3194 	    int64_t, dda->dda_blkno));
   3195 
   3196 	return (0);
   3197 }
   3198 
   3199 /*
   3200  * dda_tape_rewind
   3201  *
   3202  * Parameters:
   3203  *	- dda:		DDA tape drive.
   3204  *
   3205  * Position to beginning of media.
   3206  *
   3207  * Return Values:
   3208  *	0 : success
   3209  *	errno : failure
   3210  *
   3211  */
   3212 static int
   3213 dda_tape_rewind(dda_t *dda)
   3214 {
   3215 	int	err = 0;
   3216 
   3217 
   3218 	if (!dda->dda_loaded) {
   3219 		return (EIO);
   3220 	}
   3221 
   3222 	dda->dda_status = 0;
   3223 	dda->dda_resid = 0;
   3224 
   3225 	if (err = dda_write_index(dda)) {
   3226 		return (err);
   3227 	}
   3228 
   3229 	if (DDA_GET_FM_NEEDED(dda)) {
   3230 		if (err = dda_tape_wfm(dda, 1)) {
   3231 			return (err);
   3232 		}
   3233 	}
   3234 
   3235 	dda->dda_flags = 0;
   3236 	dda->dda_blkno = 0;
   3237 	DDA_SET_TRUNC(dda);
   3238 
   3239 	dda->dda_index_offset = 0;
   3240 	if (err = dda_read_index(dda)) {
   3241 		DDA_DEBUG2((dda_cmd_rewind_err,
   3242 		    int, dda->dda_inst,
   3243 		    int, err));
   3244 		return (err);
   3245 	}
   3246 
   3247 	DDA_DEBUG2((dda_cmd_rewind,
   3248 	    int, dda->dda_inst,
   3249 	    int64_t, DDA_LBA(dda)));
   3250 
   3251 	return (0);
   3252 }
   3253 
   3254 /* index operations */
   3255 
   3256 /*
   3257  * dda_write_index
   3258  *
   3259  * Parameters:
   3260  *	- dda:		DDA tape drive.
   3261  *
   3262  * Write an index record at the index file position.
   3263  *
   3264  * Return Values:
   3265  *	0 : success
   3266  *	errno : failure
   3267  *
   3268  */
   3269 static int
   3270 dda_write_index(dda_t *dda)
   3271 {
   3272 	int		err;
   3273 	dda_index_t	index;
   3274 
   3275 	if (DDA_GET_INDEX(dda)) {
   3276 		DDA_CLR_INDEX(dda);
   3277 		DDA_BE_INDEX(dda->dda_index, index);
   3278 		if (err = dda_vn_write(dda, dda->dda_index_vp, &index,
   3279 		    sizeof (dda_index_t), dda->dda_index_offset)) {
   3280 			return (err);
   3281 		}
   3282 		dda->dda_index_fsize = dda->dda_index_offset +
   3283 		    sizeof (dda_index_t);
   3284 
   3285 		DDA_DEBUG4((dda_write_index,
   3286 		    int, dda->dda_inst,
   3287 		    int64_t, dda->dda_index.dda_lba,
   3288 		    int64_t, dda->dda_index.dda_fileno,
   3289 		    off64_t, dda->dda_index_offset));
   3290 	}
   3291 	return (0);
   3292 }
   3293 
   3294 /*
   3295  * dda_read_index
   3296  *
   3297  * Parameters:
   3298  *	- dda:		DDA tape drive.
   3299  *
   3300  * Read an index record from the index file position.
   3301  *
   3302  * Return Values:
   3303  *	0 : success
   3304  *	errno : failure
   3305  *
   3306  */
   3307 static int
   3308 dda_read_index(dda_t *dda)
   3309 {
   3310 	int		err;
   3311 	dda_index_t	index;
   3312 
   3313 	DDA_CLR_INDEX(dda);
   3314 	dda->dda_pos = 0;
   3315 	if (err = dda_vn_read(dda, dda->dda_index_vp, &index,
   3316 	    sizeof (dda_index_t), dda->dda_index_offset)) {
   3317 		return (err);
   3318 	}
   3319 	DDA_BE_INDEX(index, dda->dda_index);
   3320 
   3321 	DDA_DEBUG4((dda_read_index,
   3322 	    int, dda->dda_inst,
   3323 	    int64_t, dda->dda_index.dda_lba,
   3324 	    int64_t, dda->dda_index.dda_fileno,
   3325 	    off64_t, dda->dda_index_offset));
   3326 
   3327 	return (0);
   3328 }
   3329 
   3330 /*
   3331  * dda_gen_next_index
   3332  *
   3333  * Parameters:
   3334  *	- dda:		DDA tape drive.
   3335  *	- blksize:	Record size for index record.
   3336  *
   3337  * Generate the next index record with starting positions from the
   3338  * end of previous index record.
   3339  * Function is called after a change in record size or when data
   3340  * follows a filemark.
   3341  *
   3342  * Return Values:
   3343  *	None
   3344  *
   3345  */
   3346 static void
   3347 dda_gen_next_index(dda_t *dda, int32_t blksize)
   3348 {
   3349 	DDA_CLR_INDEX(dda);
   3350 	dda->dda_index.dda_offset = dda_data_offset(dda);
   3351 	dda->dda_index.dda_lba += DDA_INDEX_COUNT(dda);
   3352 	dda->dda_index.dda_fileno += dda->dda_index.dda_fmcount;
   3353 	dda->dda_index.dda_fmcount = 0;
   3354 	dda->dda_index.dda_blkcount = 0;
   3355 	dda->dda_index.dda_blksize = blksize;
   3356 	dda->dda_index_offset += sizeof (dda_index_t);
   3357 	dda->dda_pos = 0;
   3358 
   3359 	DDA_DEBUG3((dda_gen_next_index,
   3360 	    int, dda->dda_inst,
   3361 	    int64_t, dda->dda_index.dda_lba,
   3362 	    int64_t, dda->dda_index.dda_fileno));
   3363 
   3364 }
   3365 
   3366 /*
   3367  * dda_save_istate
   3368  *
   3369  * Parameters:
   3370  *	- dda:		DDA tape drive.
   3371  *	- istate:	Index record and index file offset.
   3372  *
   3373  * Save current index record and position.
   3374  *
   3375  * Return Values:
   3376  *	None
   3377  *
   3378  */
   3379 static void
   3380 dda_save_istate(dda_t *dda, dda_istate_t *istate)
   3381 {
   3382 	istate->dda_index_offset = dda->dda_index_offset;
   3383 	istate->dda_index = dda->dda_index;
   3384 	istate->dda_pos = dda->dda_pos;
   3385 	istate->dda_flags = dda->dda_flags;
   3386 }
   3387 
   3388 /*
   3389  * dda_restore_istate
   3390  *
   3391  * Parameters:
   3392  *	- dda:		DDA tape drive.
   3393  *	- istate:	Index record and index file offset.
   3394  *
   3395  * Restore saved index record and position.
   3396  *
   3397  * Return Values:
   3398  *	None
   3399  *
   3400  */
   3401 static void
   3402 dda_restore_istate(dda_t *dda, dda_istate_t *istate)
   3403 {
   3404 	dda->dda_index_offset = istate->dda_index_offset;
   3405 	dda->dda_index = istate->dda_index;
   3406 	dda->dda_pos = istate->dda_pos;
   3407 	if (istate->dda_flags & DDA_FLAG_INDEX) {
   3408 		DDA_SET_INDEX(dda);
   3409 	}
   3410 }
   3411 
   3412 /* alignment */
   3413 
   3414 /*
   3415  * dda_stripe_align
   3416  *
   3417  * Parameters:
   3418  *	- dda:		DDA tape drive.
   3419  *
   3420  * Align data file offset following after a filemark.
   3421  *
   3422  * Return Values:
   3423  *	Aligned data file offset.
   3424  *
   3425  */
   3426 static off64_t
   3427 dda_stripe_align(dda_t *dda)
   3428 {
   3429 	off64_t	amount = 0;
   3430 
   3431 	DDA_DEBUG1((dda_stripe_align_enter,
   3432 	    int, dda->dda_inst));
   3433 
   3434 	/*
   3435 	 * Called at bot write or when write data follows a file mark.
   3436 	 */
   3437 	if (dda->dda_metadata.dda_stripe > 0) {
   3438 		/*
   3439 		 * Start tape file on stripe boundary
   3440 		 */
   3441 		amount = dda->dda_index.dda_offset %
   3442 		    dda->dda_metadata.dda_stripe;
   3443 
   3444 		DDA_DEBUG3((dda_stripe_align_amount,
   3445 		    int, dda->dda_inst,
   3446 		    int32_t, dda->dda_metadata.dda_stripe,
   3447 		    off64_t, amount));
   3448 
   3449 		if (amount) {
   3450 			/*
   3451 			 * Stripe adjustment needed.
   3452 			 */
   3453 			amount = dda->dda_metadata.dda_stripe - amount;
   3454 
   3455 			DDA_DEBUG3((dda_stripe_align,
   3456 			    int, dda->dda_inst,
   3457 			    int32_t, dda->dda_metadata.dda_stripe,
   3458 			    off64_t, amount));
   3459 		}
   3460 	}
   3461 	return (amount);
   3462 }
   3463 
   3464 /*
   3465  * dda_data_offset
   3466  *
   3467  * Parameters:
   3468  *	- dda:		DDA tape drive.
   3469  *
   3470  * Generate data file offset using the index record and
   3471  * metadata direct I/O alignment.
   3472  *
   3473  * Return Values:
   3474  *	Data file offset.
   3475  *
   3476  */
   3477 static off64_t
   3478 dda_data_offset(dda_t *dda)
   3479 {
   3480 	off64_t	offset;
   3481 	off64_t	amount;
   3482 	int32_t	sector = dda->dda_metadata.dda_sector;
   3483 
   3484 	offset = dda->dda_index.dda_offset;
   3485 
   3486 	DDA_DEBUG2((dda_data_offset_start,
   3487 	    int, dda->dda_inst,
   3488 	    off64_t, offset));
   3489 
   3490 	if (dda->dda_pos <= dda->dda_index.dda_blkcount) {
   3491 
   3492 		offset += (dda->dda_pos * dda->dda_index.dda_blksize);
   3493 
   3494 		DDA_DEBUG2((dda_data_offset_le,
   3495 		    int, dda->dda_inst,
   3496 		    off64_t, offset));
   3497 
   3498 	} else {
   3499 
   3500 		offset += (dda->dda_index.dda_blkcount *
   3501 		    dda->dda_index.dda_blksize);
   3502 
   3503 		DDA_DEBUG2((dda_data_offset_gt,
   3504 		    int, dda->dda_inst,
   3505 		    off64_t, offset));
   3506 
   3507 	}
   3508 
   3509 	if (dda->dda_metadata.dda_sector > 0 &&
   3510 	    DDA_LEN_ALIGNED(dda->dda_index.dda_blksize, sector) == 0) {
   3511 
   3512 		/* adjust for direct I/O */
   3513 
   3514 		amount = DDA_OFF_ALIGNED(offset, sector);
   3515 
   3516 		if (amount) {
   3517 
   3518 			/* bytes needed for sector alignment */
   3519 
   3520 			amount = sector - amount;
   3521 		}
   3522 
   3523 		offset += amount;
   3524 
   3525 		DDA_DEBUG3((dda_data_offset_align,
   3526 		    int, dda->dda_inst,
   3527 		    off64_t, offset,
   3528 		    off64_t, amount));
   3529 	}
   3530 
   3531 	DDA_DEBUG3((dda_data_offset,
   3532 	    int, dda->dda_inst,
   3533 	    int64_t, DDA_LBA(dda),
   3534 	    off64_t, offset));
   3535 
   3536 	return (offset);
   3537 }
   3538 
   3539 /* space */
   3540 
   3541 /*
   3542  * dda_tape_capacity
   3543  *
   3544  * Parameters:
   3545  *	- dda:		DDA tape drive.
   3546  *	- space:	Amount of space remaining to eom.
   3547  *
   3548  * The amount of available space remaining to eom is from the last
   3549  * data or fm on tape to phyical eom. The position on media does not
   3550  * change the space remaining calculation. Filemarks count as 1 byte
   3551  * of used capacity. The size of the three media files (metadata,
   3552  * index, and data) are also subtracted from the capacity.
   3553  *
   3554  * Return Values:
   3555  *	0 : success
   3556  *	errno : failure
   3557  *
   3558  */
   3559 static int
   3560 dda_tape_capacity(dda_t *dda, int64_t *space)
   3561 {
   3562 	int		err;
   3563 	dda_index_t	last_index;
   3564 	off64_t 	last_index_offset;
   3565 	off64_t		last_index_fileno;
   3566 	off64_t		last_index_fmcount;
   3567 
   3568 
   3569 	/* get offset of last index file record */
   3570 	last_index_offset = dda->dda_index_fsize - sizeof (dda_index_t);
   3571 	if (last_index_offset < 0) {
   3572 		dda->dda_status = KEY_MEDIUM_ERROR;
   3573 		return (EIO);
   3574 	}
   3575 
   3576 	/* get total number of filemarks on tape */
   3577 	if (dda->dda_index_offset >= last_index_offset) {
   3578 		/* current or next index record is the last index record */
   3579 		last_index_fileno = dda->dda_index.dda_fileno;
   3580 		last_index_fmcount = dda->dda_index.dda_fmcount;
   3581 	} else {
   3582 		/* read last index record */
   3583 		if (err = dda_vn_read(dda, dda->dda_index_vp, &last_index,
   3584 		    sizeof (dda_index_t), last_index_offset)) {
   3585 			return (err);
   3586 		}
   3587 		DDA_BE_INDEX(last_index, last_index);
   3588 		last_index_fileno = last_index.dda_fileno;
   3589 		last_index_fmcount = last_index.dda_fmcount;
   3590 	}
   3591 
   3592 	*space = dda->dda_metadata.dda_capacity - /* max cart size minus */
   3593 	    dda->dda_data_fsize -		  /* data file size */
   3594 	    sizeof (dda_metadata_t) -		  /* metadata file size */
   3595 	    dda->dda_index_fsize -		  /* index file size */
   3596 	    last_index_fileno -			  /* total num of prev fms */
   3597 	    last_index_fmcount;			  /* remaining number of fms */
   3598 
   3599 	if (*space < 0) {
   3600 		*space = 0;
   3601 	}
   3602 
   3603 	DDA_DEBUG3((dda_capacity,
   3604 	    int, dda->dda_inst,
   3605 	    int64_t, dda->dda_metadata.dda_capacity,
   3606 	    int64_t, *space));
   3607 
   3608 	return (0);
   3609 }
   3610 
   3611 /*
   3612  * dda_ew_eom
   3613  *
   3614  * Parameters:
   3615  *	- dda:		DDA tape drive.
   3616  *	- count:	Bytes to write.
   3617  *	- avail:	Bytes available on media.
   3618  *	- ew:		Early warning.
   3619  *
   3620  * On return avail contains the number of bytes that can be written
   3621  * to the media. The ew flag is set if the write is past early warning.
   3622  *
   3623  * Return Values:
   3624  *	0 : success
   3625  *	errno : failure
   3626  *
   3627  */
   3628 static int
   3629 dda_ew_eom(dda_t *dda, int32_t count, int64_t *avail, int *ew)
   3630 {
   3631 	int64_t	space;
   3632 	int	err;
   3633 	int64_t	used;
   3634 
   3635 	if (err = dda_tape_capacity(dda, &space)) {
   3636 		return (err);
   3637 	}
   3638 
   3639 	used = dda->dda_metadata.dda_capacity - space;
   3640 
   3641 	if (used + count >= dda->dda_early_warn) {
   3642 		*ew = 1;
   3643 	} else {
   3644 		*ew = 0;
   3645 	}
   3646 	if (used + count > dda->dda_metadata.dda_capacity) {
   3647 		*avail = space;
   3648 	} else {
   3649 		*avail = count;
   3650 	}
   3651 
   3652 	DDA_DEBUG4((dda_ew_eom,
   3653 	    int, dda->dda_inst,
   3654 	    int32_t, count,
   3655 	    int64_t, *avail,
   3656 	    int, *ew));
   3657 
   3658 	return (0);
   3659 }
   3660 
   3661 /* search */
   3662 
   3663 /*
   3664  * dda_locate_compare
   3665  *
   3666  * Parameters:
   3667  *	- dda:		DDA tape drive.
   3668  *	- lba:		Locate to LBA.
   3669  *
   3670  * Locate LBA binary search compare function.
   3671  *
   3672  * Return Values:
   3673  *	0 : found
   3674  *	1 : forward
   3675  *	-1 : backward
   3676  *
   3677  */
   3678 static int
   3679 dda_locate_compare(dda_t *dda, int64_t lba)
   3680 {
   3681 	int64_t	last;
   3682 
   3683 	last = dda->dda_index.dda_lba + DDA_INDEX_COUNT(dda);
   3684 
   3685 	if (lba >= dda->dda_index.dda_lba && lba <= last) {
   3686 
   3687 		dda->dda_pos = lba - dda->dda_index.dda_lba;
   3688 
   3689 		return (0);
   3690 	}
   3691 
   3692 	if (lba < dda->dda_index.dda_lba) {
   3693 		return (-1);
   3694 	}
   3695 
   3696 	return (1);
   3697 }
   3698 
   3699 /*
   3700  * dda_fsf_compare
   3701  *
   3702  * Parameters:
   3703  *	- dda:		DDA tape drive.
   3704  *	- fileno:	Locate file number.
   3705  *
   3706  * Forward space file binary search compare function.
   3707  *
   3708  * Return Values:
   3709  *	0 : found
   3710  *	1 : forward
   3711  *	-1 : backward
   3712  *
   3713  */
   3714 static int
   3715 dda_fsf_compare(dda_t *dda, int64_t fileno)
   3716 {
   3717 	int64_t	last;
   3718 
   3719 	if (dda->dda_index.dda_fmcount) {
   3720 
   3721 		last = dda->dda_index.dda_fileno + dda->dda_index.dda_fmcount;
   3722 
   3723 		if (fileno > dda->dda_index.dda_fileno && fileno <= last) {
   3724 
   3725 			dda->dda_pos = dda->dda_index.dda_blkcount +
   3726 			    fileno - dda->dda_index.dda_fileno;
   3727 
   3728 			return (0);
   3729 		}
   3730 	}
   3731 
   3732 	if (fileno <= dda->dda_index.dda_fileno) {
   3733 		return (-1);
   3734 	}
   3735 
   3736 	return (1);
   3737 }
   3738 
   3739 /*
   3740  * dda_bsf_compare
   3741  *
   3742  * Parameters:
   3743  *	- dda:		DDA tape drive.
   3744  *	- fileno:	Locate file number.
   3745  *
   3746  * Backward space file binary search compare function.
   3747  *
   3748  * Return Values:
   3749  *	0 : found
   3750  *	1 : forward
   3751  *	-1 : backward
   3752  *
   3753  */
   3754 static int
   3755 dda_bsf_compare(dda_t *dda, int64_t fileno)
   3756 {
   3757 	int64_t	last;
   3758 
   3759 	if (dda->dda_index.dda_fmcount) {
   3760 
   3761 		last = dda->dda_index.dda_fileno + dda->dda_index.dda_fmcount;
   3762 
   3763 		if (fileno >= dda->dda_index.dda_fileno && fileno < last) {
   3764 
   3765 			dda->dda_pos = dda->dda_index.dda_blkcount +
   3766 			    fileno - dda->dda_index.dda_fileno;
   3767 
   3768 			return (0);
   3769 		}
   3770 	}
   3771 
   3772 	if (fileno < dda->dda_index.dda_fileno) {
   3773 		return (-1);
   3774 	}
   3775 
   3776 	return (1);
   3777 }
   3778 
   3779 /*
   3780  * dda_bsearch
   3781  *
   3782  * Parameters:
   3783  *	- dda:		DDA tape drive.
   3784  *	- key:		LBA or file number.
   3785  *	- compare:	Binary search comparison function.
   3786  *	- found:	Search successful.
   3787  *
   3788  * Binary search index file records for LBA or fileno.
   3789  *
   3790  * Return Values:
   3791  *	0 : success
   3792  *	errno : fs failure
   3793  *
   3794  */
   3795 static int
   3796 dda_bsearch(dda_t *dda,
   3797     int64_t key,
   3798     int (*compare)(dda_t *, int64_t),
   3799     int *found)
   3800 {
   3801 	int	err;
   3802 	int	res;
   3803 	off64_t	nel, width, base, two_width, last;
   3804 
   3805 	/*
   3806 	 * Index file binary search for lba or fileno
   3807 	 */
   3808 
   3809 	DDA_DEBUG2((dda_bsearch,
   3810 	    int, dda->dda_inst,
   3811 	    int64_t, key));
   3812 
   3813 	*found = 0;
   3814 
   3815 	/* bsearch(3C) */
   3816 	width = sizeof (dda_index_t);
   3817 	two_width = width + width;
   3818 
   3819 	base = 0;
   3820 	nel = dda->dda_index_fsize / sizeof (dda_index_t);
   3821 	last = base + width * (nel - 1);
   3822 
   3823 	while (last >= base) {
   3824 
   3825 		dda->dda_index_offset =
   3826 		    base + width * ((last - base) / two_width);
   3827 
   3828 		if (err = dda_read_index(dda)) {
   3829 			return (err);
   3830 		}
   3831 
   3832 		res = compare(dda, key);
   3833 
   3834 		if (res == 0) {
   3835 			*found = 1;
   3836 			return (0);
   3837 		}
   3838 
   3839 		if (res < 0) {
   3840 			last = dda->dda_index_offset - width;
   3841 		} else {
   3842 			base = dda->dda_index_offset + width;
   3843 		}
   3844 	}
   3845 
   3846 	return (0);
   3847 }
   3848 
   3849 /* vnode operations */
   3850 
   3851 /*
   3852  * dda_vn_open
   3853  *
   3854  * Parameters:
   3855  *	- dda:		DDA tape drive.
   3856  *	- vpp:		Pointer to a vnode file pointer.
   3857  *	- fname:	Filename to open.
   3858  *
   3859  * Open a dda media file from the kernel.
   3860  * Ensure the dda user has permission to open the file.
   3861  * On error convert the file open error into a sense key.
   3862  *
   3863  * Return Values:
   3864  *	0 : success
   3865  *	errno : failure
   3866  *
   3867  */
   3868 static int
   3869 dda_vn_open(dda_t *dda, struct vnode **vpp, char *fname)
   3870 {
   3871 	int		err;
   3872 
   3873 	if (err = vn_open(fname, UIO_SYSSPACE, DDA_VNODE_MODE, 0, vpp, 0, 0)) {
   3874 		DDA_DEBUG3((dda_vn_open_err,
   3875 		    int, dda->dda_inst,
   3876 		    char *, fname,
   3877 		    int, err));
   3878 		*vpp = NULL;
   3879 		dda_vn_error_skey(dda, err);
   3880 		return (err);
   3881 	}
   3882 
   3883 	err = VOP_ACCESS(*vpp, DDA_VNODE_MODE, 0, dda->dda_cred, NULL);
   3884 	if (err) {
   3885 		DDA_DEBUG3((dda_vn_open_access,
   3886 		    int, dda->dda_inst,
   3887 		    char *, fname,
   3888 		    int, err));
   3889 		(void) VOP_CLOSE(*vpp, DDA_VNODE_MODE, 1, (offset_t)0,
   3890 		    dda->dda_cred, NULL);
   3891 		VN_RELE(*vpp);
   3892 		*vpp = NULL;
   3893 		dda_vn_error_skey(dda, err);
   3894 	}
   3895 	return (err);
   3896 }
   3897 
   3898 /*
   3899  * dda_vn_close
   3900  *
   3901  * Parameters:
   3902  *	- dda:		DDA tape drive.
   3903  *	- vpp:		Pointer to a vnode file pointer.
   3904  *
   3905  * Close dda media file from the kernel.
   3906  * On error convert the file close error into a sense key.
   3907  *
   3908  * Return Values:
   3909  *	0 : success
   3910  *	errno : failure
   3911  *
   3912  */
   3913 static int
   3914 dda_vn_close(dda_t *dda, struct vnode **vpp)
   3915 {
   3916 	int		err;
   3917 
   3918 	if (*vpp == NULL) {
   3919 		DDA_DEBUG1((dda_vn_close_null,
   3920 		    int, dda->dda_inst));
   3921 		dda->dda_status = KEY_MEDIUM_ERROR;
   3922 		return (EIO);
   3923 	}
   3924 
   3925 	err = VOP_CLOSE(*vpp, DDA_VNODE_MODE, 1, (offset_t)0,
   3926 	    dda->dda_cred, NULL);
   3927 	if (err) {
   3928 		DDA_DEBUG3((dda_vn_close_err,
   3929 		    int, dda->dda_inst,
   3930 		    char *, dda_vn_get_fname(dda, *vpp),
   3931 		    int, err));
   3932 		dda_vn_error_skey(dda, err);
   3933 	}
   3934 	VN_RELE(*vpp);
   3935 	*vpp = NULL;
   3936 	return (err);
   3937 }
   3938 
   3939 /*
   3940  * dda_vn_lock
   3941  *
   3942  * Parameters:
   3943  *	- dda:		DDA tape drive.
   3944  *	- vp:		Vnode pointer to open file.
   3945  *	- cmd:		File lock or unlock command.
   3946  *
   3947  * Set or unset a file lock on the entire file.
   3948  * The file lock is held by the driver while the media is loaded.
   3949  *
   3950  * Return Values:
   3951  *      0 : success
   3952  *      errno : failure
   3953  *
   3954  */
   3955 static int
   3956 dda_vn_lock(dda_t *dda, struct vnode *vp, short cmd)
   3957 {
   3958 	flock64_t	flk;
   3959 	int		err;
   3960 
   3961 	if (vp == NULL) {
   3962 		DDA_DEBUG1((dda_vn_lock_null,
   3963 		    int, dda->dda_inst));
   3964 		dda->dda_status = KEY_MEDIUM_ERROR;
   3965 		return (EIO);
   3966 	}
   3967 
   3968 	/* lock or unlock entire file */
   3969 	bzero(&flk, sizeof (flock64_t));
   3970 	flk.l_type = cmd;
   3971 
   3972 	/* non-blocking file lock */
   3973 	err = VOP_FRLOCK(vp, F_SETLK, &flk, FREAD | FWRITE,
   3974 	    0, NULL, dda->dda_cred, NULL);
   3975 
   3976 	if (cmd == F_UNLCK && vn_has_flocks(vp)) {
   3977 		cleanlocks(vp, IGN_PID, 0);
   3978 	}
   3979 
   3980 	if (err) {
   3981 		DDA_DEBUG4((dda_vn_lock_err,
   3982 		    int, dda->dda_inst,
   3983 		    char *, dda_vn_get_fname(dda, vp),
   3984 		    int, cmd,
   3985 		    int, err));
   3986 		dda_vn_error_skey(dda, err);
   3987 	}
   3988 
   3989 	return (err);
   3990 }
   3991 
   3992 /*
   3993  * dda_vn_read
   3994  *
   3995  * Parameters:
   3996  *	- dda:		DDA tape drive.
   3997  *	- vp:		Vnode file pointer.
   3998  *	- buf:		File read buffer.
   3999  *	- len:		Length of read buffer.
   4000  *	- offset:	File offset to begin reading from.
   4001  *
   4002  * From the kernel read the requested buffer length from the file.
   4003  * On error convert the file read error into a sense key.
   4004  *
   4005  * Return Values:
   4006  *	0 : success
   4007  *	errno : failure
   4008  *
   4009  */
   4010 static int
   4011 dda_vn_read(dda_t *dda, struct vnode *vp, void *buf, int len, off64_t offset)
   4012 {
   4013 	int		err;
   4014 	struct iovec	iov;
   4015 	struct uio	uio;
   4016 
   4017 	if (vp == NULL) {
   4018 		DDA_DEBUG1((dda_vn_read_null,
   4019 		    int, dda->dda_inst));
   4020 		dda->dda_status = KEY_MEDIUM_ERROR;
   4021 		return (EIO);
   4022 	}
   4023 
   4024 	iov.iov_base = (caddr_t)buf;
   4025 	iov.iov_len = len;
   4026 
   4027 	uio.uio_iov = &iov;
   4028 	uio.uio_iovcnt = 1;
   4029 	uio.uio_segflg = UIO_SYSSPACE;
   4030 	uio.uio_loffset = offset;
   4031 	uio.uio_resid = len;
   4032 	uio.uio_fmode = FREAD;
   4033 	uio.uio_llimit = MAXOFFSET_T;
   4034 
   4035 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
   4036 	err = VOP_READ(vp, &uio, 0, dda->dda_cred, NULL);
   4037 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
   4038 
   4039 	if (err) {
   4040 		DDA_DEBUG4((dda_vn_read_err,
   4041 		    int, dda->dda_inst,
   4042 		    char *, dda_vn_get_fname(dda, vp),
   4043 		    off64_t, offset,
   4044 		    int, err));
   4045 		dda_vn_error_skey(dda, err);
   4046 		return (err);
   4047 	}
   4048 
   4049 	if (uio.uio_resid != 0) {
   4050 		DDA_DEBUG4((dda_vn_read_resid,
   4051 		    int, dda->dda_inst,
   4052 		    char *, dda_vn_get_fname(dda, vp),
   4053 		    off64_t, offset,
   4054 		    int32_t, uio.uio_resid));
   4055 		dda->dda_status = KEY_MEDIUM_ERROR;
   4056 		return (EIO);
   4057 	}
   4058 	return (0);
   4059 }
   4060 
   4061 /*
   4062  * dda_vn_write
   4063  *
   4064  * Parameters:
   4065  *	- dda:		DDA tape drive.
   4066  *	- vp:		Vnode file pointer.
   4067  *	- buf:		File write buffer.
   4068  *	- len:		Length of write buffer.
   4069  *	- offset:	File offset to begin writing.
   4070  *
   4071  * From the kernel write the requested buffer length to the file.
   4072  * On error convert the file write error into a sense key.
   4073  *
   4074  * Return Values:
   4075  *	0 : success
   4076  *	errno : failure
   4077  *
   4078  */
   4079 static int
   4080 dda_vn_write(dda_t *dda, struct vnode *vp, void *buf, int len, off64_t offset)
   4081 {
   4082 	int		err;
   4083 	struct iovec	iov;
   4084 	struct uio	uio;
   4085 
   4086 	if (vp == NULL) {
   4087 		DDA_DEBUG1((dda_vn_write_null,
   4088 		    int, dda->dda_inst));
   4089 		dda->dda_status = KEY_MEDIUM_ERROR;
   4090 		return (EIO);
   4091 	}
   4092 
   4093 	iov.iov_base = (caddr_t)buf;
   4094 	iov.iov_len = len;
   4095 
   4096 	uio.uio_iov = &iov;
   4097 	uio.uio_iovcnt = 1;
   4098 	uio.uio_segflg = UIO_SYSSPACE;
   4099 	uio.uio_loffset = offset;
   4100 	uio.uio_resid = len;
   4101 	uio.uio_fmode = FWRITE;
   4102 	uio.uio_llimit = MAXOFFSET_T;
   4103 
   4104 	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
   4105 	err = VOP_WRITE(vp, &uio, FWRITE|FTRUNC, dda->dda_cred, NULL);
   4106 	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
   4107 
   4108 	if (err) {
   4109 		DDA_DEBUG4((dda_vn_write_err,
   4110 		    int, dda->dda_inst,
   4111 		    char *, dda_vn_get_fname(dda, vp),
   4112 		    off64_t, offset,
   4113 		    int, err));
   4114 		dda_vn_error_skey(dda, err);
   4115 		return (err);
   4116 	}
   4117 
   4118 	if (uio.uio_resid != 0) {
   4119 		DDA_DEBUG4((dda_vn_write_resid,
   4120 		    int, dda->dda_inst,
   4121 		    char *, dda_vn_get_fname(dda, vp),
   4122 		    off64_t, offset,
   4123 		    int32_t, uio.uio_resid));
   4124 		dda->dda_status = KEY_MEDIUM_ERROR;
   4125 		return (EIO);
   4126 	}
   4127 	return (0);
   4128 }
   4129 
   4130 /*
   4131  * dda_vn_truncate
   4132  *
   4133  * Parameters:
   4134  *	- dda:		DDA tape drive.
   4135  *	- vp:		Vnode file pointer.
   4136  *	- offset:	Truncate file at offset.
   4137  *
   4138  * Truncate the file.
   4139  * On error convert the file truncate error into a sense key.
   4140  *
   4141  * Return Values:
   4142  *	0 : success
   4143  *	errno : failure
   4144  *
   4145  */
   4146 static int
   4147 dda_vn_truncate(dda_t *dda, struct vnode *vp, off64_t offset)
   4148 {
   4149 	int		err;
   4150 	struct vattr	vattr;
   4151 
   4152 	if (vp == NULL) {
   4153 		DDA_DEBUG1((dda_vn_truncate_null,
   4154 		    int, dda->dda_inst));
   4155 		dda->dda_status = KEY_MEDIUM_ERROR;
   4156 		return (EIO);
   4157 	}
   4158 
   4159 	vattr.va_size = offset;
   4160 	vattr.va_mask = AT_SIZE;
   4161 	err = VOP_SETATTR(vp, &vattr, 0, dda->dda_cred, NULL);
   4162 	if (err) {
   4163 		DDA_DEBUG4((dda_vn_truncate_err,
   4164 		    int, dda->dda_inst,
   4165 		    char *, dda_vn_get_fname(dda, vp),
   4166 		    off64_t, offset,
   4167 		    int, err));
   4168 		dda_vn_error_skey(dda, err);
   4169 	}
   4170 	return (err);
   4171 }
   4172 
   4173 /*
   4174  * dda_vn_sync
   4175  *
   4176  * Parameters:
   4177  *	- dda:		DDA tape drive.
   4178  *	- vp:		Vnode file pointer.
   4179  *
   4180  * Flush file to disk.
   4181  * On error convert the file flush error into a sense key.
   4182  *
   4183  * Return Values:
   4184  *	0 : success
   4185  *	errno : failure
   4186  *
   4187  */
   4188 static int
   4189 dda_vn_sync(dda_t *dda, struct vnode *vp)
   4190 {
   4191 	int		err;
   4192 
   4193 	if (vp == NULL) {
   4194 		DDA_DEBUG1((dda_vn_sync_null,
   4195 		    int, dda->dda_inst));
   4196 		dda->dda_status = KEY_MEDIUM_ERROR;
   4197 		return (EIO);
   4198 	}
   4199 
   4200 	err = VOP_FSYNC(vp, FSYNC, dda->dda_cred, NULL);
   4201 	if (err) {
   4202 		DDA_DEBUG3((dda_vn_sync_err,
   4203 		    int, dda->dda_inst,
   4204 		    char *, dda_vn_get_fname(dda, vp),
   4205 		    int, err));
   4206 		dda_vn_error_skey(dda, err);
   4207 	}
   4208 	return (err);
   4209 }
   4210 
   4211 /*
   4212  * dda_vn_size
   4213  *
   4214  * Parameters:
   4215  *	- dda:		DDA tape drive.
   4216  *	- vp:		Vnode file pointer.
   4217  *	- fsize:	File size.
   4218  *
   4219  * Get dda media file size.
   4220  * On error convert the file size error into a sense key.
   4221  *
   4222  * Return Values:
   4223  *	0 : success
   4224  *	errno : failure
   4225  *
   4226  */
   4227 static int
   4228 dda_vn_size(dda_t *dda, struct vnode *vp, off64_t *fsize)
   4229 {
   4230 	int		err;
   4231 	struct vattr	vattr;
   4232 
   4233 	if (vp == NULL) {
   4234 		DDA_DEBUG1((dda_vn_size_null,
   4235 		    int, dda->dda_inst));
   4236 		dda->dda_status = KEY_MEDIUM_ERROR;
   4237 		return (EIO);
   4238 	}
   4239 
   4240 	vattr.va_mask = AT_SIZE;
   4241 	err = VOP_GETATTR(vp, &vattr, 0, dda->dda_cred, NULL);
   4242 	if (err) {
   4243 		DDA_DEBUG3((dda_vn_size_err,
   4244 		    int, dda->dda_inst,
   4245 		    char *, dda_vn_get_fname(dda, vp),
   4246 		    int, err));
   4247 		dda_vn_error_skey(dda, err);
   4248 	} else {
   4249 		*fsize = (off64_t)vattr.va_size;
   4250 	}
   4251 	return (err);
   4252 }
   4253 
   4254 /*
   4255  * dda_vn_get_fname
   4256  *
   4257  * Parameters:
   4258  *	- dda:		DDA tape drive.
   4259  *	- vp:		Vnode file pointer.
   4260  *
   4261  * Get dda media filename from the vnode pointer for tracing.
   4262  *
   4263  * Return Values:
   4264  *	filename
   4265  *
   4266  */
   4267 static char *
   4268 dda_vn_get_fname(dda_t *dda, struct vnode *vp)
   4269 {
   4270 	char	*fname;
   4271 
   4272 	if (vp == dda->dda_metadata_vp) {
   4273 		fname = DDA_METADATA_FNAME;
   4274 	} else if (vp == dda->dda_index_vp) {
   4275 		fname = DDA_INDEX_FNAME;
   4276 	} else if (vp == dda->dda_data_vp) {
   4277 		fname = DDA_DATA_FNAME;
   4278 	} else {
   4279 		fname = DDA_UNKNOWN_FNAME;
   4280 	}
   4281 	return (fname);
   4282 }
   4283 
   4284 /*
   4285  * dda_vn_error_skey
   4286  *
   4287  * Parameters:
   4288  *	- dda:		DDA tape drive.
   4289  *	- int:		errno
   4290  *
   4291  * Convert filesystem or kernel errno into tape drive sense key.
   4292  *
   4293  * Return Values:
   4294  *	None
   4295  *
   4296  */
   4297 static void
   4298 dda_vn_error_skey(dda_t *dda, int err)
   4299 {
   4300 	switch (err) {
   4301 	case 0:		/* no error */
   4302 		dda->dda_status = KEY_NO_SENSE;
   4303 		break;
   4304 	case EINVAL:	/* invalid arg */
   4305 		dda->dda_status = KEY_ILLEGAL_REQUEST;
   4306 		break;
   4307 	case EFBIG:	/* file too large */
   4308 	case ENOSPC:	/* no space */
   4309 		dda->dda_status = SUN_KEY_EOT;
   4310 		break;
   4311 	case EACCES:	/* permission denied */
   4312 	case EROFS:	/* read only fs */
   4313 		dda->dda_status = KEY_WRITE_PROTECT;
   4314 		break;
   4315 	case EISDIR:	/* is directory */
   4316 	case ENOENT:	/* no such file or directory */
   4317 		dda->dda_status = KEY_MEDIUM_ERROR;
   4318 		break;
   4319 	/* ESTALE: stale nfs file handle */
   4320 	/* EMFILE: too many open files */
   4321 	/* EMLINK: too many links */
   4322 	/* EAGAIN: resource temporarily unavailable */
   4323 	/* ENOMEM: not enough core */
   4324 	/* ENOLCK: no record locks available */
   4325 	default:
   4326 		dda->dda_status = KEY_RECOVERABLE_ERROR;
   4327 		break;
   4328 	}
   4329 }
   4330