dda.c revision cee0fb94c0d4227de0a00efc162fb2739844b641
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Driver for Disk Archiving (dda)
*
* DDA emulates the st tape driver BSD mode for MMS disk archiving.
*
* A limited number of MTIO operations are implemented by DDA.
*
* USCSI commands are not implemented by DDA.
*
* Tape drive operations such as load, capacity and read block limits
* are DDA ioctl commands.
*
* DDA media is implemented as a cartridge directory containing three
* files: metadata, index and data.
*
* The metadata file contains cartridge information such as version,
* capacity, stripe and directio alignment and the write protect tab.
*
* The index file contains index records. An index record contains the
* data file offset, number of consective same size records and the
* number of consective filemarks. The data file offset is adjusted
* for stripe and directio alignment. Stripe alignment only occurs at
* bot and when data follows a filemark. Directio is only enabled at bot.
*
* The data file only contains user data with holes for stripe and directio
* alignment.
*
*/
/* _init, _info, and _fini */
/* prop_op, and ddi_prop_op */
/* ddi_create_minor_node */
/* this driver */
/* this driver also used by cb_ops, */
/* ddi_get_instance, and ddi_prop_op */
/* this driver also used by cb_ops, */
/* ddi_create_minor_node, */
/* ddi_get_instance, and ddi_prop_op */
#include <limits.h>
#include "dda.h"
/* vnode mode is read, write, large files, allow symlinks */
/* maximum block size */
/* early warning capacity - space */
/* block number unknown */
#define DDA_BLKNO_UNKNOWN 1000000000
/* file name unknown */
#define DDA_UNKNOWN_FNAME "?"
/* operation flags and macros */
/* metadata flag */
/* read only tape */
#define DDA_GET_READ_ONLY(x) ((x->dda_read_only || \
DDA_GET_WPROTECT(x)) ? 1 : 0)
/* alignment macros */
/* index record calculations */
#define DDA_IS_BOT(x) (x->dda_index_offset == 0 && \
x->dda_pos == 0 ? 1 : 0)
#define DDA_IS_BLANK(x) (x->dda_index_offset == 0 && \
DDA_INDEX_COUNT(x) == 0 ? 1 : 0)
#define DDA_IS_FM(x) (DDA_IS_BLANK(x) ? 0 : \
x->dda_index.dda_fmcount && \
dda_blkcount && \
x->dda_index.dda_fmcount)
#ifdef MMSDEBUG
int dda_debug = 1;
#else
int dda_debug = 0;
#endif
/* index record state */
typedef struct dda_istate {
} dda_istate_t;
/* driver operations */
void **resultp);
int *rvalp);
/* tape operations */
/* support routines */
/* index record write, read, generate, save and restore */
/* stripe and directio alignment */
/* space */
/* search */
int *found);
/* vnode operations */
/* cb_ops structure */
static struct cb_ops dda_cb_ops = {
nodev, /* no strategy - nodev returns ENXIO */
nodev, /* no print */
nodev, /* no dump */
nodev, /* no devmap */
nodev, /* no mmap */
nodev, /* no segmap */
nochpoll, /* returns ENXIO for non-pollable devices */
NULL, /* streamtab struct; if not NULL, all above */
/* fields are ignored */
CB_REV, /* cb_ops revision number */
nodev, /* no aread */
nodev /* no awrite */
};
/* dev_ops structure */
static struct dev_ops dda_dev_ops = {
0, /* reference count */
nulldev, /* no identify - nulldev returns 0 */
nulldev, /* no probe */
nodev, /* no reset - nodev returns ENXIO */
nodev /* no power */
};
/* modldrv structure */
#define DDA_LINKINFO "driver for disk archiving"
static char dda_linkinfo[100];
};
/* modlinkage structure */
static struct modlinkage dda_ml = {
&dda_md,
};
/* dev_info structure, one instance per dda device */
static void *dda_state;
extern char hw_serial[];
/* Loadable module configuration entry points */
/*
* _init
*
* Parameters:
* None
*
* Globals:
* - dda_state: Uninitialized list of DDA drives.
* - dda_linkinfo: DDA description string.
* - dda_ml: DDA module linkage structure.
*
* Initialize list of emulated tape drives.
* Create driver description reported to user.
* Export driver specification to the kernel.
*
* Return Values:
* 0 : success
* non-zero : failure
*
*/
int
_init(void)
{
int rc;
return (rc);
}
}
return (rc);
}
/*
* _info
*
* Parameters:
* - modinfop: Opaque module information structure.
*
* Globals:
* - dda_ml: DDA module linkage structure.
*
* Report DDA module information.
*
* Return Values:
* non-zero : success
* 0 : failure
*
*/
int
{
int rc;
}
return (rc);
}
/*
* _fini
*
* Parameters:
* - none
*
* Globals:
* - dda_ml: DDA module linkage structure.
* - dda_state: DDA drive list.
*
* Prepare to unload the DDA driver from the kernel.
* Release DDA drive list to the system.
*
* Return Values:
* 0 : success
* non-zero : failure
*
*/
int
_fini(void)
{
int rc;
return (rc);
}
return (rc);
}
/* Device configuration entry points */
/*
* dda_attach
*
* Parameters:
* - dip: Device information structure.
* - cmd: Attach command.
*
* Globals:
* - dda_state: Pointer to list of DDA drives.
*
* Create and initialize one DDA tape drive for each dda.conf instance.
* Create BSD no-rewind tape drive minor node.
* Assign generated serial number to the drive.
* Initialize exclusive drive access mutex.
* Set drive state to unload.
*
* Return Values:
* DDI_SUCCESS : success
* DDI_FAILURE : failure
*
*/
static int
{
switch (cmd) {
case DDI_ATTACH:
instance);
return (DDI_FAILURE);
}
instance);
return (DDI_FAILURE);
}
instance);
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/*
* dda_detach
*
* Parameters:
* - dip: Device information structure.
* - cmd: Detach command.
*
* Globals:
* - dda_state: Pointer to list of DDA drives.
*
* Get drive instance from the list of drives.
* If media is loaded in the drive then unload the media.
* Remove minor device node.
* Release exclusive access mutex.
* Release memory.
*
* Return Values:
* DDI_SUCCESS : success
* DDI_FAILURE : failure
*
*/
static int
{
switch (cmd) {
case DDI_DETACH:
instance);
return (DDI_FAILURE);
}
if (dda->dda_loaded) {
(void) dda_tape_unload(dda);
}
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/*
* dda_getinfo
*
* Parameters:
* - dip: Device information structure.
* - cmd: Information command.
* - arg: Device structure.
* - resultp: Pointer for information requested.
*
* Globals:
* - dda_state: List of DDA emulated tape drives.
*
* Return drive instance information to the kernel.
*
* Return Values:
* DDI_SUCCESS : success
* DDI_FAILURE : failure
*
*/
/*ARGSUSED*/
static int
{
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
instance);
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
case DDI_INFO_DEVT2INSTANCE:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/* Main entry points */
/*
* dda_open
*
* Parameters:
* - devp: Device structure.
* - flag: Device open mode.
* - otyp: Character or block device open.
* - credp: User credentials.
*
* Globals:
* - dda_state: List of DDA emulated tape drives.
*
* Verify character device open.
* Get drive structure.
* Lock drive to ensure sequential access.
* If drive is already in-use then unlock drive and return busy.
* If drive is not loaded then prevent read only or write non-blocking
* access to the drive.
* Save open process pid as the test for drive in-use.
* Set read only mode.
* Unlock drive.
*
* Return Values:
* DDI_SUCCESS : success
* DDI_FAILURE : failure
*
*/
static int
{
return (EINVAL);
}
return (ENXIO);
}
/*
* The real tape driver does not allow a drive to be
* opened multiple times.
*/
return (EBUSY);
}
if (!dda->dda_loaded) {
/*
* The real tape driver does not allow an unloaded tape
* drive to be opened in read only or blocking mode.
*/
return (EIO);
}
}
/* user credentials */
/* set open flag */
/* get read only mode */
return (0);
}
/*
* dda_open
*
* Parameters:
* - devp: Device structure.
* - flag: Device open mode.
* - otyp: Character or block device open.
* - credp: User credentials.
*
* Globals:
* - dda_state: List of DDA emulated tape drives.
*
* Verify character device close.
* Get drive structure.
* Lock drive to ensure sequential access.
* Append filemark if loaded and needed.
* Unlock drive.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err = 0;
return (EINVAL);
}
return (ENXIO);
}
if (DDA_GET_FM_FWD_PEND(dda)) {
}
DDA_GET_FM_NEEDED(dda) &&
DDA_GET_READ_ONLY(dda) == 0) {
} else {
}
/* only reset record size at bot for bsb no rewind */
if (DDA_IS_BOT(dda)) {
dda->dda_rec_size = 0;
}
return (err);
}
/*
* dda_read
*
* Parameters:
* - dev: Device structure.
* - uio: Vector I/O operations.
* - credp: User credentials.
*
* Globals:
* - dda_state: List of DDA emulated tape drives.
*
* Get drive structure.
* Lock drive to ensure sequential access.
* Call tape read function.
* Unlock drive.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (ENXIO);
}
return (err);
}
/*
* dda_write
*
* Parameters:
* - dev: Device structure.
* - uio: Vector I/O operations.
* - credp: User credentials.
*
* Globals:
* - dda_state: List of DDA emulated tape drives.
*
* Get drive structure.
* Lock drive to ensure sequential access.
* Call tape write function.
* Unlock drive.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (ENXIO);
}
return (err);
}
/*
* dda_ioctl
*
* Parameters:
* - dev: Device structure.
* - cmd: DDA or MTIO command.
* - flag: User data model.
* - credp: User credentials.
* - rvalp: Return error number.
*
* Globals:
* - dda_state: List of DDA emulated tape drives.
*
* Interface to execute DDA commands and selected MTIO commands.
*
* The DDA commands perform operations normally handled by a real tape
* drive such as load, capacity, write protect tab, read block limits,
* loaded cartridge pcl.
*
* MTIO commands support unload, motion, write filemark, erase, drive status,
* drive type, record size, and setting incorrect length indicator.
*
* Get drive structure.
* Determine command to execute.
* Lock drive to ensure sequential access.
* Call function to emulate MTIO functionality.
* Unlock drive.
*
* Return Values:
* Cartridge write protect command:
* 0 : read only
* -1 : read write
*
* All other commands:
* 0 : success
* errno : failure
*
* Note:
* DDA emulates BSD no-rewind behavior.
*
*/
/*ARGSUSED5*/
static int
{
int tmp;
char *path;
int err = 0;
return (ENXIO);
}
switch (cmd) {
case DDA_CMD_LOAD: {
} else {
}
return (err);
}
case DDA_CMD_NAME: {
if (!dda->dda_loaded) {
return (EIO);
}
}
return (err);
}
case DDA_CMD_CAPACITY: {
if (!dda->dda_loaded) {
return (EIO);
}
return (err);
}
sizeof (dda_capacity_t), flag)) {
return (EFAULT);
}
return (0);
}
case DDA_CMD_WPROTECT: {
if (!dda->dda_loaded) {
return (EIO);
}
if (DDA_GET_WPROTECT(dda) != 0) {
/* write protect tab on */
return (0);
}
/* write protect tab off */
return (-1);
}
case DDA_CMD_BLKLMT: {
sizeof (dda_blklmt_t), flag)) {
return (EFAULT);
}
return (0);
}
case DDA_CMD_SERIAL: {
dda->dda_serial);
sizeof (dda_serial_t), flag)) {
return (EFAULT);
}
return (0);
}
case USCSICMD: {
return (ENOTTY);
}
case MTIOCGETPOS: {
if (!dda->dda_loaded) {
return (EIO);
}
return (EFAULT);
}
return (0);
}
case MTIOCRESTPOS: {
return (EFAULT);
}
if (!dda->dda_loaded) {
return (EIO);
}
return (EINVAL);
}
return (err);
}
case MTIOCLTOP: {
int rval;
return (EFAULT);
}
}
return (rval);
}
case MTIOCTOP: {
#ifdef _MULTI_DATAMODEL
/*
* For use when a 32 bit app makes a call into a
* 64 bit ioctl
*/
struct mtop32 mtop_32_for_64;
#endif /* _MULTI_DATAMODEL */
int rval = 0;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
return (EFAULT);
}
break;
case DDI_MODEL_NONE:
return (EFAULT);
}
/* prevent sign extension */
break;
}
#else /* ! _MULTI_DATAMODEL */
return (EFAULT);
}
/* prevent sign extension */
#endif /* _MULTI_DATAMODEL */
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
break;
}
/*
* Convert 64 bit back to 32 bit before doing
* copyout. This is what the ILP32 app expects.
*/
}
break;
case DDI_MODEL_NONE:
}
break;
}
#else /* ! _MULTI_DATAMODE */
} else {
}
}
#endif /* _MULTI_DATAMODE */
return (rval);
}
case MTIOCGET: {
#ifdef _MULTI_DATAMODEL
struct mtget32 mtg_local32;
#endif /* _MULTI_DATAMODEL */
if (!dda->dda_loaded) {
} else {
}
dda->dda_status = 0;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
return (EFAULT);
}
break;
case DDI_MODEL_NONE:
return (EFAULT);
}
break;
}
#else /* ! _MULTI_DATAMODE */
return (EFAULT);
}
#endif /* _MULTI_DATAMODE */
return (0);
}
case MTIOCGETDRIVETYPE: {
#ifdef _MULTI_DATAMODEL
struct mtdrivetype_request32 mtdtrq32;
#endif /* _MULTI_DATAMODEL */
struct mtdrivetype_request mtdtrq;
struct mtdrivetype mtdrtyp;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
{
sizeof (struct mtdrivetype_request32), flag)) {
return (EFAULT);
}
break;
}
case DDI_MODEL_NONE:
sizeof (struct mtdrivetype_request), flag)) {
return (EFAULT);
}
break;
}
#else /* ! _MULTI_DATAMODEL */
sizeof (struct mtdrivetype_request), flag)) {
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
return (EINVAL);
}
ST_BSF |
ST_BSR |
tmp = sizeof (struct mtdrivetype);
return (EFAULT);
}
return (0);
}
case MTIOCREADIGNOREILI: {
int set_ili;
return (EFAULT);
}
if (!dda->dda_loaded) {
return (EIO);
}
if (dda->dda_rec_size) {
return (ENOTTY);
}
return (EINVAL);
}
return (0);
}
} /* switch end */
return (ENOTTY);
}
/* tape operations */
/*
* dda_tape_op
*
* Parameters:
* - dda: DDA tape drive.
* - mtop: Magnetic tape operation structure.
*
* Perform the MTIO command by calling the appropriate DDA function.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
case MTTELL:
if (!dda->dda_loaded) {
return (EIO);
}
return (0);
case MTSEEK: {
if (!dda->dda_loaded) {
return (EIO);
}
}
/* turn seek into tell command */
}
return (err);
}
case MTWEOF:
return (EINVAL);
}
return (err);
case MTFSF:
return (err);
case MTBSF:
return (err);
case MTFSR:
return (err);
case MTBSR:
return (err);
case MTRETEN:
case MTREW:
return (err);
case MTNOP:
return (0);
case MTERASE:
return (err);
case MTEOM:
return (err);
case MTOFFL:
return (err);
case MTSRSZ:
return (EINVAL);
}
return (EINVAL);
}
if (!dda->dda_loaded) {
return (EIO);
}
if (dda->dda_rec_size) {
}
return (0);
case MTGRSZ:
if (!dda->dda_loaded) {
return (EIO);
}
return (0);
}
return (ENOTTY);
}
/*
* dda_tape_load
*
* Parameters:
* - dda: DDA tape drive.
* - path: DDA media directory.
*
* If the drive is already loaded and the path is different then
* reject the load command and return.
* If the drive is already loaded and the path is the same then
* accept the load command and return.
* If not loaded open the DDA media files.
* If write protect tab is set read only.
* Calculate data file offset to early warning.
* Set unit attention status.
* Set truncate need flag since the media is at BOT.
* DDA media is now loaded and ready for access.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
char *fname;
int err;
short status;
dda->dda_status = 0;
if (dda->dda_loaded) {
"%d loaded already %s",
return (EIO);
}
"%d load resume %s",
return (0);
}
/* reset media data, the drive data is not reset */
goto load_error;
}
goto load_error;
}
goto load_error;
}
goto load_error;
}
/* check for media in-use and prevent write protect tab access */
goto load_error;
}
sizeof (dda_metadata_t), 0)) {
goto load_error;
}
/* non-floating point early warning to eom percentage calculation */
}
}
/* set media loaded */
char *, path));
return (0);
char *, path,
int, err));
/* cleanup */
if (dda->dda_index_vp) {
}
if (dda->dda_data_vp) {
}
if (dda->dda_metadata_vp) {
}
return (err);
}
/*
* dda_tape_op
*
* Parameters:
* - dda: DDA tape drive.
*
* Write filemark if needed to emulate st bsd mode.
* Unload media from the drive.
* Report first error encounter.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int rc;
int err = 0;
short status;
/*
* Close all files, report first error
*/
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
if (DDA_GET_FM_NEEDED(dda)) {
if (err == 0) {
}
}
}
if (err == 0) {
}
}
if (err == 0) {
}
}
if (err == 0) {
}
}
if (err == 0) {
} else {
int, err));
}
return (err);
}
/* support routines */
/*
* dda_gen_serial_num
*
* Parameters:
* - dda: DDA tape drive.
*
* Globals:
* - hw_serial: Hostid.
*
* Generate DDA unit serial number from the computer hostid and drive
* instance number.
*
* Return Values:
* None
*
*/
static void
{
char sn[100];
int len;
int off;
int hostid_i;
/*
* Generate unit serial number:
* zeros, hostid, instance number
*/
/*
* Use least significant part of generated serial number
*/
off = 0;
}
}
/*
* dda_set_unloaded
*
* Parameters:
* - dda: DDA tape drive.
*
* Set DDA drive unloaded.
* Zero DDA media structure members.
* Set fileno to -1 for status.
*
* Return Values:
* None
*
*/
static void
{
dda->dda_loaded = 0;
}
/*
* dda_get_fileno
*
* Parameters:
* - dda: DDA tape drive.
*
* Get DDA media fileno based on st bsd behavior.
*
* Return Values:
* fileno : filemark number
*
*/
static int64_t
{
}
if (DDA_GET_FM_FWD_PEND(dda)) {
if (DDA_GET_FM_NOSKIP(dda)) {
fileno--;
}
}
return (fileno);
}
/*
* dda_get_blkno
*
* Parameters:
* - dda: DDA tape drive.
*
* Get DDA media blkno.
* If positioned at filemark then the blkno is 0.
* Otherwise backup until bot or filemark is encountered.
*
* Return Values:
* fileno : filemark number
*
*/
static int
{
int err = 0;
*blkno = 0;
return (0);
}
while (dda->dda_index_offset >= 0) {
break;
}
break;
}
}
return (err);
}
/*
* dda_write_truncate
*
* Parameters:
* - dda: DDA tape drive.
*
* Truncate DDA media at the current position.
* If at bot then align data file offset for directio.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
if (DDA_IS_BOT(dda)) {
}
}
if (DDA_INDEX_COUNT(dda) == 0) {
if (dda->dda_index_offset < 0) {
dda->dda_index_offset = 0;
} else {
return (err);
}
}
}
}
return (err);
}
return (err);
}
dda_data_offset(dda))) {
return (err);
}
if (DDA_IS_BOT(dda)) {
return (err);
}
}
return (0);
}
/*
* dda_tape_erase
*
* Parameters:
* - dda: DDA tape drive.
*
* Erase DDA media from the current position.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
if (DDA_GET_READ_ONLY(dda)) {
return (EACCES);
}
/*
* Erase from current logical position
*/
int, err));
}
return (err);
}
/*
* dda_sync
*
* Parameters:
* - dda: DDA tape drive.
*
* Flush DDA media files to disk.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
int rc;
short status;
/*
* Sync all files, report first error
*/
if (err == 0) {
}
}
if (err == 0) {
}
}
return (err);
}
/*
* dda_tape_wfm
*
* Parameters:
* - dda: DDA tape drive.
* - count: Number of filemarks to write.
*
* If zero filemarks then flush media to disk and return.
* Truncate DDA media if needed.
* If at physical end of media and no filemarks can be
* written then set status and return.
* Write the number of filemarks requested.
* Update position on media.
* Set residual for the number of filemarks not written.
* Flush DDA media to disk.
*
* Return Values:
* 0 : success
* errno : failure
*
* Note:
* A filemark is counted as 1 byte of used tape space.
*/
static int
{
int err;
int ew;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
if (DDA_GET_READ_ONLY(dda)) {
return (EACCES);
}
int, count));
if (count == 0) {
return (err);
}
return (err);
}
return (err);
}
if (avail == 0) {
/*
* Physical end of media.
*/
return (EIO);
}
return (err);
}
return (err);
}
return (0);
}
/*
* dda_tape_write
*
* Parameters:
* - dda: DDA tape drive.
* - uio: Vector I/O operations.
*
* DDA write supports all write lengths allowed by the kernel.
*
* A variable length write may span two index records when the
* length is not modulus max record size.
*
* A fixed length write requires the data length to be a multiple
* the record size.
*
* If read only media then set write protect status and return.
* If zero length write then return.
* Calculate number of blocks to write based on the record size.
* Truncate media if needed.
* Get early warning and physical end of media.
* Adjust length to write in blocks based on tape space remaining.
* If positioned past early warning then alternating write failures
* occur.
* Get data file offset.
* Write the data to the data file.
* If write error then set status and return errno.
* If write returns residual then adjust counts and truncate
* incomplete blocks.
* Update index record with new media position.
* If write crosses into early warning then set status.
* Write complete.
*
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
int ew;
int rc;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
if (DDA_GET_READ_ONLY(dda)) {
return (EACCES);
}
return (0);
}
if (dda->dda_rec_size == 0) {
/* variable block(s) */
if (len > DDA_MAX_REC_SIZE) {
/* write may span this index record and next */
} else {
/* single block write */
blkcount = 1;
}
} else {
/* fixed block(s) */
return (EINVAL);
}
}
return (err);
}
return (err);
}
if (ew) {
/*
* Logical end of media, alternating
* zero byte writes after early warning.
*/
int, DDA_GET_EW(dda)));
if (DDA_GET_EW(dda)) {
/*
* Physical end of media hit.
*/
return (EIO);
}
return (0);
}
/*
* Next early warning write is zero bytes.
*/
}
/* at least one block */
/*
* Physical end of media hit.
*/
return (EIO);
}
/* adjust counts */
if (dda->dda_rec_size == 0) {
partial = 0;
} else {
}
}
}
if (DDA_IS_BOT(dda)) {
} else {
goto write_error;
}
}
}
/* write data */
if (err) {
int, err));
goto write_error;
}
if (dda->dda_rec_size == 0) {
partial = 0;
}
/* remove blocks from data */
blks++;
}
if (blkcount == 0) {
goto write_error;
}
goto write_error;
}
}
/* update index record block count */
goto write_error;
}
/* increment position within index record by blocks written */
if (partial) {
goto write_error;
}
goto write_error;
}
}
} else {
if (dda->dda_rec_size == 0) {
} else {
}
}
if (ew) {
}
return (err);
/* no blocks written */
if (dda->dda_rec_size == 0) {
} else {
}
if (DDA_IS_BOT(dda)) {
}
if (err == 0) {
}
}
int, err));
if (err) {
/* original error */
return (err);
}
return (EIO);
}
/*
* dda_tape_read
*
* Parameters:
* - dda: DDA tape drive.
* - uio: Vector I/O operations.
*
* DDA read supports all read lengths allowed by the kernel.
*
* A variable length read may span two index records.
*
* The DDA variable length read supports the ILI (incorrect length
* indicator).
*
* A fixed length read requires the data length to be a multiple of
* the record size.
*
* If zero length read then return.
* Calculate the number of blocks to read based on the
* record size.
* Get early warning and physical end of media.
* Adjust length (blocks) to read based on tape space remaining.
* Read the data from the data file.
* If read error occurred then set status and return.
* If read returns residual then adjust counts.
* Update the index record with new media position.
* Read complete.
*
*
* Return Values:
* 0 : success
* errno : failure
*
*/
int
{
int err;
int overflow = 0;
int noskip;
int partial = 0;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
return (0);
}
if (dda->dda_rec_size == 0) {
/* variable */
if (len > DDA_MAX_REC_SIZE) {
/* read may span this index record and next */
/* actual partial blksize determined below */
partial = 1;
}
} else {
/* single block read */
blkcount = 1;
}
} else {
/* fixed */
return (EINVAL);
}
return (EINVAL);
}
}
if (DDA_GET_FM_FWD_PEND(dda)) {
if (noskip) {
return (0);
}
}
return (err);
}
fsize -= sizeof (dda_index_t);
int, DDA_GET_EOT_EIO(dda)));
if (DDA_GET_EOT_EIO(dda) == 0) {
return (EIO);
}
return (0);
}
return (err);
}
}
return (0);
}
overflow = 1;
}
} else {
}
blkcount = 1;
partial = 0;
int, overflow));
}
if (partial) {
/* get partial from next index record */
partial = 0;
partial = 0;
} else if (index.dda_blkcount == 0) {
partial = 0;
}
}
if (blkcount == 0) {
if (dda->dda_rec_size == 0) {
} else {
}
return (0);
}
if (partial) {
}
} else if (partial) {
/* current index record contains partial */
}
overflow = 1;
}
}
if (err) {
int, err));
if (dda->dda_rec_size == 0) {
} else {
}
return (err);
}
if (dda->dda_rec_size == 0) {
} else {
}
return (EIO);
}
} else {
if (dda->dda_rec_size == 0) {
} else {
}
}
if (partial) {
}
if (overflow) {
}
return (err);
}
/*
* dda_tape_locate
*
* Parameters:
* - dda: DDA tape drive.
* - position: Locate to LBA.
*
* Locate to LBA requested.
*
* Return Values:
* 0 : success
* errno : failure, positioned at bot or eom
*
*/
static int
{
int err;
int found;
int rc;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
int, err));
return (err);
}
if (!found) {
/*
* Locate unsuccessful,
* position based on direction of search
*/
return (err);
}
} else {
return (err);
}
}
}
}
return (err);
}
/*
* dda_tape_fsr
*
* Parameters:
* - dda: DDA tape drive.
* - count: Number of records to forward space.
*
* Forward space records the requested count.
* Set truncate needed for write that may follow.
* Clear filemark forward pending.
* Clear alternating write success at early warning.
* If filemark is hit during fsr then cross the filemark but report
* logical position in front of the filemark to the user.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
int fm;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
int, count));
int, err));
return (err);
}
fsize -= sizeof (dda_index_t);
if (DDA_GET_FM_FWD_PEND(dda)) {
return (EIO);
}
break;
}
int, err));
return (err);
}
}
if (fm) {
blks = 1;
} else {
}
}
if (fm) {
break;
}
}
return (err);
}
/*
* dda_tape_bsr
*
* Parameters:
* - dda: DDA tape drive.
* - count: Number of records to backward space.
*
* Backspace records the requested count.
* Set truncate needed for write that may follow.
* Clear filemark forward pending.
* Clear alternating write success at early warning.
* If filemark is hit during bsr then do not cross the filemark.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err = 0;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
int, count));
if (DDA_GET_FM_FWD_PEND(dda)) {
}
if (dda->dda_index_offset < 0) {
break;
}
int, err));
return (err);
}
}
blks = 0;
}
}
break;
}
}
return (err);
}
/*
* dda_tape_fsf
*
* Parameters:
* - dda: DDA tape drive.
* - count: Number of filemarks to forward space.
*
* Forward space filemarks.
* Set truncate needed for write that may follow.
* Clear filemark forward pending.
* Clear alternating write success at early warning.
* If filemark forward pending then decrement the count.
* Binary search to the filemark.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
int found;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
int, count));
if (DDA_GET_FM_FWD_PEND(dda)) {
count--;
int, count));
}
if (fileno == 0) {
goto fsf_done;
}
int, err));
return (err);
}
if (found) {
/*
* Forward space file successful
*/
} else {
/*
* Forward space file unsuccessful,
* position based on direction of search
*/
if (count < 0) {
return (err);
}
} else {
return (err);
}
return (err);
}
}
}
return (err);
}
/*
* dda_tape_bsf
*
* Parameters:
* - dda: DDA tape drive.
* - count: Number of filemarks to backward space.
*
* Backward space filemarks.
* Zero flags.
* Set truncate needed for write that may follow.
* Binary search to filemark.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
int found;
int rc;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
int, count));
int, err));
return (err);
}
if (found) {
/*
* Backward space file successful
*/
} else {
/*
* Backward space file unsuccessful,
* position based on direction of search
*/
if (count < 0) {
return (err);
}
}
} else {
return (err);
}
}
}
return (err);
}
/*
* dda_tape_eom
*
* Parameters:
* - dda: DDA tape drive.
*
* Position to end of media.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
int, err));
return (err);
}
fsize -= sizeof (dda_index_t);
if (fsize < 0) {
int, err));
return (EIO);
}
int, err));
return (err);
}
}
return (err);
}
/*
* dda_tape_rewind
*
* Parameters:
* - dda: DDA tape drive.
*
* Position to beginning of media.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err = 0;
if (!dda->dda_loaded) {
return (EIO);
}
dda->dda_status = 0;
if (DDA_GET_FM_NEEDED(dda)) {
return (err);
}
}
dda->dda_index_offset = 0;
int, err));
return (err);
}
return (0);
}
/* index operations */
/*
* dda_write_index
*
* Parameters:
* - dda: DDA tape drive.
*
* Write an index record at the index file position.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (err);
}
return (0);
}
/*
* dda_read_index
*
* Parameters:
* - dda: DDA tape drive.
*
* Read an index record from the index file position.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (err);
}
return (0);
}
/*
* dda_gen_next_index
*
* Parameters:
* - dda: DDA tape drive.
* - blksize: Record size for index record.
*
* Generate the next index record with starting positions from the
* end of previous index record.
* Function is called after a change in record size or when data
* follows a filemark.
*
* Return Values:
* None
*
*/
static void
{
}
/*
* dda_save_istate
*
* Parameters:
* - dda: DDA tape drive.
* - istate: Index record and index file offset.
*
* Save current index record and position.
*
* Return Values:
* None
*
*/
static void
{
}
/*
* dda_restore_istate
*
* Parameters:
* - dda: DDA tape drive.
* - istate: Index record and index file offset.
*
* Restore saved index record and position.
*
* Return Values:
* None
*
*/
static void
{
}
/* alignment */
/*
* dda_stripe_align
*
* Parameters:
* - dda: DDA tape drive.
*
* Align data file offset following after a filemark.
*
* Return Values:
* Aligned data file offset.
*
*/
static off64_t
{
/*
* Called at bot write or when write data follows a file mark.
*/
/*
* Start tape file on stripe boundary
*/
if (amount) {
/*
* Stripe adjustment needed.
*/
}
}
return (amount);
}
/*
* dda_data_offset
*
* Parameters:
* - dda: DDA tape drive.
*
* Align data file offset for the index record.
* If directio is enable then the alignment is calculated.
*
* Return Values:
* Aligned data file offset.
*
*/
static off64_t
{
} else {
}
/* fs supports directio */
if (amount) {
/* bytes needed for sector alignment */
}
}
}
return (offset);
}
/*
* dda_sector_align
*
* Parameters:
* - dda: DDA tape drive.
*
* If filesystem is capable of directio then update metadata file with
* sector size.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
/*
* Set sector alignment at bot then use to eom.
*/
return (EIO);
}
/* ufs directio flag */
/*
* Directio on, do sector alignment.
*/
} else {
/*
* Directio off, don't do sector alignment.
*/
}
/*
* Metadata already contains sector alignment.
*/
return (0);
}
/*
* Save sector alignment change.
*/
sizeof (dda_metadata_t), 0)) {
int, err));
return (err);
}
return (0);
}
/* space */
/*
* dda_tape_capacity
*
* Parameters:
* - dda: DDA tape drive.
* - space: Amount of space remaining to eom.
*
* The amount of space remaining to eom is same no matter the
* media position.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (err);
}
return (err);
}
index_fsize -= sizeof (dda_index_t);
sizeof (dda_index_t), index_fsize)) {
return (err);
}
if (*space < 0) {
*space = 0;
}
return (0);
}
/*
* dda_tape_capacity
*
* Parameters:
* - dda: DDA tape drive.
* - count: Bytes to write.
* - avail: Bytes available on media.
* - ew: Early warning.
*
* On return avail contains the number of bytes that can be written
* to the media. The ew flag is set if the write is past early warning.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (err);
}
*ew = 1;
} else {
*ew = 0;
}
} else {
}
int, *ew));
return (0);
}
/* search */
/*
* dda_locate_compare
*
* Parameters:
* - dda: DDA tape drive.
* - lba: Locate to LBA.
*
* Locate LBA binary search compare function.
*
* Return Values:
* 0 : found
* 1 : forward
* -1 : backward
*
*/
static int
{
return (0);
}
return (-1);
}
return (1);
}
/*
* dda_fsf_compare
*
* Parameters:
* - dda: DDA tape drive.
* - fileno: Locate file number.
*
* Forward space file binary search compare function.
*
* Return Values:
* 0 : found
* 1 : forward
* -1 : backward
*
*/
static int
{
return (0);
}
}
return (-1);
}
return (1);
}
/*
* dda_bsf_compare
*
* Parameters:
* - dda: DDA tape drive.
* - fileno: Locate file number.
*
* Backward space file binary search compare function.
*
* Return Values:
* 0 : found
* 1 : forward
* -1 : backward
*
*/
static int
{
return (0);
}
}
return (-1);
}
return (1);
}
/*
* dda_bsearch
*
* Parameters:
* - dda: DDA tape drive.
* - key: LBA or file number.
* - compare: Binary search comparison function.
* - found: Search successful.
*
* Binary search index file records for LBA or fileno.
*
* Return Values:
* 0 : success
* errno : fs failure
*
*/
static int
int *found)
{
int err;
int res;
/*
* Index file binary search for lba or fileno
*/
*found = 0;
return (err);
}
/* bsearch(3C) */
width = sizeof (dda_index_t);
base = 0;
return (err);
}
if (res == 0) {
*found = 1;
return (0);
}
if (res < 0) {
} else {
}
}
return (0);
}
/* vnode operations */
/*
* dda_vn_open
*
* Parameters:
* - dda: DDA tape drive.
* - vpp: Pointer to a vnode file pointer.
* - fname: Filename to open.
*
* Open a dda media file from the kernel.
* Ensure the dda user has permission to open the file.
* On error convert the file open error into a sense key.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
char *, fname,
int, err));
return (err);
}
if (err) {
char *, fname,
int, err));
}
return (err);
}
/*
* dda_vn_close
*
* Parameters:
* - dda: DDA tape drive.
* - vpp: Pointer to a vnode file pointer.
*
* Close dda media file from the kernel.
* On error convert the file close error into a sense key.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (EIO);
}
if (err) {
int, err));
}
return (err);
}
/*
* dda_vn_lock
*
* Parameters:
* - dda: DDA tape drive.
* - vp: Vnode pointer to open file.
* - cmd: File lock or unlock command.
*
* Set or unset a file lock on the entire file.
* The file lock is held by the driver while the media is loaded.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (EIO);
}
/* lock or unlock entire file */
/* non-blocking file lock */
}
if (err) {
int, cmd,
int, err));
}
return (err);
}
/*
* dda_vn_read
*
* Parameters:
* - dda: DDA tape drive.
* - vp: Vnode file pointer.
* - buf: File read buffer.
* - len: Length of read buffer.
* - offset: File offset to begin reading from.
*
* From the kernel read the requested buffer length from the file.
* On error convert the file read error into a sense key.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (EIO);
}
if (err) {
int, err));
return (err);
}
return (EIO);
}
return (0);
}
/*
* dda_vn_write
*
* Parameters:
* - dda: DDA tape drive.
* - vp: Vnode file pointer.
* - buf: File write buffer.
* - len: Length of write buffer.
* - offset: File offset to begin writing.
*
* From the kernel write the requested buffer length to the file.
* On error convert the file write error into a sense key.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (EIO);
}
if (err) {
int, err));
return (err);
}
return (EIO);
}
return (0);
}
/*
* dda_vn_truncate
*
* Parameters:
* - dda: DDA tape drive.
* - vp: Vnode file pointer.
* - offset: Truncate file at offset.
*
* Truncate the file.
* On error convert the file truncate error into a sense key.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (EIO);
}
if (err) {
int, err));
}
return (err);
}
/*
* dda_vn_sync
*
* Parameters:
* - dda: DDA tape drive.
* - vp: Vnode file pointer.
*
* Flush file to disk.
* On error convert the file flush error into a sense key.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (EIO);
}
if (err) {
int, err));
}
return (err);
}
/*
* dda_vn_size
*
* Parameters:
* - dda: DDA tape drive.
* - vp: Vnode file pointer.
* - fsize: File size.
*
* Get dda media file size.
* On error convert the file size error into a sense key.
*
* Return Values:
* 0 : success
* errno : failure
*
*/
static int
{
int err;
return (EIO);
}
if (err) {
int, err));
} else {
}
return (err);
}
/*
* dda_vn_get_fname
*
* Parameters:
* - dda: DDA tape drive.
* - vp: Vnode file pointer.
*
* Get dda media filename from the vnode pointer for tracing.
*
* Return Values:
* filename
*
*/
static char *
{
char *fname;
} else {
}
return (fname);
}
/*
* dda_vn_error_skey
*
* Parameters:
* - dda: DDA tape drive.
* - int: errno
*
* Convert filesystem or kernel errno into tape drive sense key.
*
* Return Values:
* None
*
*/
static void
{
switch (err) {
case 0: /* no error */
break;
case EINVAL: /* invalid arg */
break;
case EFBIG: /* file too large */
case ENOSPC: /* no space */
break;
case EACCES: /* permission denied */
case EROFS: /* read only fs */
break;
case EISDIR: /* is directory */
case ENOENT: /* no such file or directory */
break;
/* ESTALE: stale nfs file handle */
/* EMFILE: too many open files */
/* EMLINK: too many links */
/* EAGAIN: resource temporarily unavailable */
/* ENOMEM: not enough core */
/* ENOLCK: no record locks available */
default:
break;
}
}