blob: 89b143eb1ac2d3e0ba3a1f51e25049fe63e5e915 [file] [log] [blame]
/*
* Copyright (c) 2000-2001 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef DRIVE_H
#define DRIVE_H
/* drive.[hc] - drive abstraction
*
* drive_t provides a framework for device-independent drive abstraction,
* as well as initialization of appropriate drive handlers.
*
* A drive_t is a drive manager providing capabilities for reading, writing,
* and manipulating media objects (e.g., tape cartridges).
*
* All writing and reading is done within the scope of a media file. Writes
* may be cut short due to media events (e.g., EOM). The mark
* mechanism allows the caller to determine what portion of the write data
* stream is guaranteed to have been committed to media.
*
* Marks may be placed in the stream during writes. During subsequent
* reads of the data stream, the media object may be positioned at a
* specific mark, or to the next mark in the stream.
*
* To accomodate end-of-media uncertainty, the marks are set in two steps.
* First the caller asks to set a mark at a position within the write stream,
* providing a callback function. The callback will be invoked when the data
* prior to that mark has been committed to media.
*
* The caller must re-position the media (e.g., change media objects or
* begin a new media file) and re-write any portion of the data written
* after the last committed mark. It is entirely possible for part of that
* data to have made it onto the previous media file, due to the uncertainty
* of end-of-media handling of some drives. Thus the caller must be prepared
* for portions of data read from the end of one media file to be duplicated
* at the beginning of the next media file.
*
* To allow repositioning the stream in the above scenarios,
* drive_t supplies forward-space-file, backward-space-file, rewind,
* seek_mark, and get_mark operators.
*
* A call to the end_read or end_write operator virtually positions the
* media at the beginning of the next media file. Thus if a caller calls
* begin read, looks at the header and decides to overwrite the media
* file, a call to the bsf operator must be made prior to the call to
* begin_write. However, if the media is positioned at EOD and the caller calls
* begin_read, EOD will be returned and no repositioning is needed. A call
* to begin_write will append a new media file after the last media file.
*
* Drive_init1 selects and instantiates a drive manager for each drive
* identified on the command line. This is done by showing the drive
* successively to each drive strategy module. The drive strategies
* supply a match score. The strategy with the highest score gets to
* instantiate a drive manager for that drive.
*
* Drive_init2 allocates and initializes read and write header buffers for
* each drive, and calls each drive manager's init operator, which begins async
* initialization of the drive. This includes determining if a media object
* is currently mounted in that drive.
*
* Drive_init3 synchronizes with the async initializations kicked off by
* drive_init2.
*
* Each drive strategy is defined by a drive_strategy_t. This supplies
* a match function, and an instantiate function.
*
* The match function lets the given strategy determine if it is the correct
* strategy to choose. The instantiate function creates a driver manager.
*
* The I/O write model presents the user with a function to get a write buffer,
* or get a page-aligned write buffer, and a function to take back the buffer
* and commit part or all of that buffer to media. The read model is similar;
* the caller may ask for a buffer filled with read data, and gives the buffer
* back after the data is used. These models facilitate high-performance
* operation, since the buffers can be used in direct I/O.
*/
/* drive_hdr_t - drive media file header
*
* A drive media file header is imbedded in the global media file header
* structure, which is in turn placed at the beginning of each media file. The
* drive hdr has three parts: generally useful drive-related info, info
* specific to the selected drive strategy, and upper layer info. Each drive
* handler contains two drive header images; a read hdr and a write hdr.
*
* CAUTION! the various components of the media file header are carefully
* crafted to fit in DRIVE_HDR_SZ bytes.
*/
#define DRIVE_HDR_SZ sizeofmember( global_hdr_t, gh_upper )
struct drive_hdr {
uint32_t dh_drivecnt; /* 4 4 */
/* number of drives used to dump the fs */
uint32_t dh_driveix; /* 4 8 */
/* 0-based index of the drive used to dump this stream */
int32_t dh_strategyid; /* 4 c */
/* ID of the drive strategy used to produce this dump */
char dh_pad1[ 0x1f4 ]; /* 1f4 200 */
/* padding */
char dh_specific[ 0x200 ]; /* 200 400 */
/* drive strategy-specific info */
char dh_upper[ DRIVE_HDR_SZ - 0x400 ]; /* 800 c00 */
/* header info private to upper software layers */
};
typedef struct drive_hdr drive_hdr_t;
/* drive_strategy_t - drive strategy
*
* The drive strategy has two operators, ds_match() and ds_instantiate().
* ds_match() returns an integer indicating the degree of match of the
* strategy to the drives indicated on the command line. ds_init()
* initializes the drive strategy, creates and initializes a drive manager
* for each drive, and if possible positions each drive at the beginning of
* the current file and reads the file header into d_readhdr. ds_drivep
* points to an array of drive managers, and ds_drivecnt indicates
* the length of that array.
*/
struct drive; /* forward declaration */
struct drive_strategy {
int ds_id;
/* strategy ID
*/
char *ds_description;
/* a short char string describing strategy
*/
int ( * ds_match )( int argc,
char *argv[ ],
struct drive *drivep );
/* returns degree of match. drivep has been pre-allocated
* and initialized with generic info.
*/
bool_t ( * ds_instantiate )( int argc,
char *argv[ ],
struct drive *drivep );
/* creates a drive manager instance, by filling in the
* blanks of the pre-allocated drive descriptor
* returns FALSE on failure.
*/
off64_t ds_recmarksep;
/* recommended maximum separation (in bytes)
* between marks. can be observed when sending
* long data streams to the drive. this field is
* transfered to d_recmarksep during instantiation.
*/
off64_t ds_recmfilesz;
/* recommended maximum length of media files.
* transfered to d_recmarksep during instantiation.
*/
};
typedef struct drive_strategy drive_strategy_t;
/* definitions of strategy ids
*/
#define DRIVE_STRATEGY_SCSITAPE 0
#define DRIVE_STRATEGY_SIMPLE 1
#define DRIVE_STRATEGY_RMT 0 /* same as SCSITAPE for now */
/* drive_mark_t - token identifying a mark within a media object file
*
* 64 bit cookie, the structure of which is known only to the drive manager
* which generated it. generated by do_get_mark, given to do_seek_mark.
*/
typedef off64_t drive_mark_t;
/* drive mark callback function
* invoked for each mark registered with do_set_mark, in the same order.
* committed is TRUE if the data up to the mark was committed to media.
* committed is FALSE if it is POSSIBLE that some data prior to the mark
* was NOT committed.
*/
struct drive_markrec; /* forward decl */
typedef void ( * drive_mcbfp_t )( void *context_t,
struct drive_markrec *markrecp,
bool_t committed );
/* drive_markrec_t - context for set mark callback function
*
* caller allocates and passes ptr to do_set_mark, along with a callback func.
* callback returns the record, which must be freed by the original caller.
*
*/
struct drive_markrec {
drive_mark_t dm_log; /* identifies position within mfile */
drive_mcbfp_t dm_cbfuncp; /* caller's callback function */
void *dm_cbcontextp; /* caller's context */
struct drive_markrec *dm_nextp; /* for linked list */
};
typedef struct drive_markrec drive_markrec_t;
/* drive_t - drive manager
*
* A drive manager is described by a set of generic parameters
* and operators.
*/
struct drive_ops; /* forward declaration */
struct drive {
drive_strategy_t *d_strategyp;
/* back ptr to strategy
*/
struct drive_ops *d_opsp;
/* pointer to drive operations
*/
void *d_contextp;
/* manager-specific data
*/
void *d_strmcontextp;
/* stream-specific data
*/
global_hdr_t *d_greadhdrp;
/* global portion of media file header of
* media file drive currently positioned.
*/
drive_hdr_t *d_readhdrp;
/* drive portion of media file header of
* media file drive currently positioned.
*/
global_hdr_t *d_gwritehdrp;
/* global portion of media file header to
* be written by the next begin_write op.
*/
drive_hdr_t *d_writehdrp;
/* drive portion of media file header to
* be written by the next begin_write op.
*/
char *d_pathname; /* e.g., /dev/tape */
ix_t d_index; /* e.g., 0, 1, 2, ... */
bool_t d_isnamedpipepr; /* is a named pipe */
bool_t d_isunnamedpipepr;/* is an unnamed pipe */
int d_capabilities;/* see DRIVE_CAP_xxx below */
off64_t d_cap_est; /* capacity estimate in bytes; -1 if unknown */
int d_rate_est; /* bytes per second; -1 if unknown */
drive_markrec_t *d_markrecheadp; /* linked list of mark records */
drive_markrec_t *d_markrectailp; /* yet to be committed */
off64_t d_recmarksep; /* transfered from strategy on instantiation */
off64_t d_recmfilesz; /* transfered from strategy on instantiation */
};
typedef struct drive drive_t;
struct drive_ops {
bool_t ( * do_init )( drive_t *drivep );
/* initializes drive, and begins async
* determination of media object presence
* returns FALSE if session should be aborted.
*/
bool_t ( * do_sync )( drive_t *drivep );
/* synchronizes with the activity kicked off
* by do_init. returns FALSE if session should
* be aborted.
*/
int ( * do_begin_read )( drive_t *drivep );
/* prepares the drive manager for reading.
* if the media is positioned at BOM or just
* after a file mark, current media file is
* begun. Otherwise, the drive will advance
* media to just after the next file mark first.
* loads the read header buffer with the
* header at the beginning of the media file.
* return value will be set non zero:
* BLANK - blank tape, positioned
* at BOT and ready for a
* do_begin_write;
* FOREIGN - unrecognized data at
* BOT, positioned
* at BOT and ready for a
* do_begin_write;
* EOD - tried to read past end of
* recorded data;
* EOM - tried to read past end of media
* object;
* MEDIA - no media object in drive;
* FORMAT - unrecognized media file header;
* VERSION - unsupported media file header;
* CORRUPTION - encountered corrupt data
* at beginning of media file;
* DEVICE - drive hardware error, other
* than missing media;
* INVAL - operator error;
* CORE - driver wants core dump;
* STOP - upper level asked lengthy
* drive op to give up.
* OVERWRITE - overwrite option to dump
* specified by user. Assume tape
* positioned and ready for write.
* if not successful (non-zero return), caller
* must NOT call end_read prior to next
* begin_read. if successful, caller MUST call
* end_read prior to next begin_read.
*/
char * ( * do_read )( drive_t *drivep,
size_t wanted_bufsz,
size_t *actual_bufszp,
int *statp );
/* asks the drive manager for a buffered filled
* with the next read stream data.
* the actual buffer size supplied may
* be shorter than requested; it will never
* be longer than requested. the buffer
* should be returned to the drive manager as
* soon as possible, to facilitate drive
* streaming. the actual buffer size may
* be short due to the internal buffering
* mechanism, or due to media events; in
* the latter case, *statp will explain why:
* EOD - tried to read past end of
* recorded data; this is semant-
* ically equiv. to EOF, but
* occurs on last media file only.
* EOF - hit end of media file prior
* to completing read; probably
* due to a write fail during dump,
* or were near end of tape (e.g.,
* early warning).
* EOM - tried to read past end of media
* object;
* MEDIA - no media object in drive;
* CORRUPTION - encountered corrupt data;
* DEVICE - drive hardware error, other
* than missing media;
* CORE - driver wants core dump;
* in all cases, the buffer returned contains
* valid data (although the buffer size may
* be zero!).
*/
void ( * do_return_read_buf )( drive_t *drivep,
char *bufp,
size_t bufsz );
/* returns the buffer obtained
* from the previous do_read() call.
* the entire buffer must be returned
* in one shot.
*/
void ( * do_get_mark )( drive_t *drivep,
drive_mark_t *drivemarkp );
/* returns (by reference) a mark corresponding
* to the next byte which will be read by a
* call to do_read(). will be used in a later
* session to seek to that position.
*/
int ( * do_seek_mark )( drive_t *drivep,
drive_mark_t *drivemarkp );
/* searches for the specified mark within the
* current file. returns zero if the mark
* was found, or an error explaining why not:
* EOF - end of file was encountered;
* EOD - end of recorded date encountered;
* EOM - end of media encountered;
* CORRUPTION - encountered corrupt data;
* DEVICE - device error;
*/
int ( * do_next_mark )( drive_t *drivep );
/* if d_capabilities has DRIVE_CAP_NEXTMARK set,
* drive has the capability to
* seek forward to the next mark. returns
* zero if a mark was found, or an error code:
* EOF - end of file was encountered;
* EOD - end of recorded date encountered;
* EOM - end of media encountered;
* DEVICE - device error;
* if currently at a mark, will go to the next.
*/
void ( *do_end_read )( drive_t *drivep );
/* ends the file read. must be called prior
* to beginning another read or write session.
* ensures that the next call to begin_read
* will position the media at the next media
* file.
*/
int ( * do_begin_write )( drive_t *drivep );
/* begins a write media file for writing.
* asserts the media is positioned at BOM or
* just after a file mark. write header will
* be placed at the head of the file.
* same return codes as do_write():
* EOM - end of media object encountered;
* MEDIA - media object missing or broken;
* DEVICE - device error;
* CORE - driver error
*/
void ( * do_set_mark )( drive_t *drivep,
drive_mcbfp_t cbfuncp,
void *cbcontextp,
drive_markrec_t *markrecp );
/* marks the position in the write stream
* where the next write will occur.
* At the time the data written
* prior to the mark is committed to media,
* the callback will be invoked, with
* the context and markrec pointers. The caller
* append his mark context to the drive markrec
* buffer pointed to by markrecp. the drive
* manager will use the drive_markrec_t
* to track the progress of the mark.
* If EOM is encountered before the
* mark is committed to media, the mark
* callback for all uncommitted marks will
* be called, but with the committed flag
* set to FALSE. it is up to the
* caller to free the mark buffers he previously
* allocated. note the drive strategy member
* d_recmarksep, the recommended maximum
* separation between marks. This is a hint
* based on underlying drive characteristics.
* the caller should record the committed
* marks; when do_write() fails due to
* EOM, the caller can resume writing after
* last committed marked point in the write
* stream.
*/
char * ( * do_get_write_buf )( drive_t *drivep,
size_t wanted_bufsz,
size_t *actual_bufszp );
/* asks the drive manager for a buffer.
* returns a pointer to a buffer, and its
* size. must call do_write() before
* calling do_get_write_buf() again. By asking
* the drive manager for a buffer, buffer
* copying can be avoided. This facilitates
* achieving streaming performance on tape
* media. Also, the drive manager can implement
* a double-buffering scheme, causing source
* reads and drive writes to occur
* simultaneously. note that the buffer can
* be larger or smaller than the wanted bufsz,
* but will be at least 1 byte in length.
*/
int ( * do_write )( drive_t *drivep,
char *bufp,
size_t bufsz );
/* asks the drive manager to write bufsz
* bytes from the buffer, which was acquired
* from a previous call to do_get_write_buf().
* returns the following status values:
* EOM - end of media object encountered;
* MEDIA - media object missing or broken;
* DEVICE - device error;
* CORE - driver error;
* in the case of a non-zero return status,
* the caller must refer to the last mark
* callback received, to know the last data
* guaranteed to have been committed to media.
* any writes subsequent to the placement of
* that mark may or may not be on media.
* the caller should therefore be prepared
* to see the same data twice when crossing
* a media file boundary while reading.
* note that no indication of the actual
* number of bytes written is returned.
* even if only part of the buffer
* obtained from do_get_write_buf()
* is used, the do_write() call returns the
* entire buffer to the drive manager; it
* is not available for subsequent writes.
* instead, the caller must get another buffer
* using do_get_write_buf().
*/
size_t ( * do_get_align_cnt )( drive_t *drivep );
/* used during writing. returns the number
* of bytes which should be written to
* page-align the next do_get_write_buf()
* call. NOTE: the caller can assume that
* alignment will be maintained after the
* initial alignment done using this info.
*/
int ( * do_end_write )( drive_t *drivep, off64_t *ncommittedp );
/* terminates a media file write sequence.
* flushes any buffered data not yet committed
* to media, and calls callbacks for all marks
* not yet returned. just like do_write(), can
* encounter EOM, in which case the
* last affirmative mark callback received will
* indicate what portion of the write data
* stream may have not been committed to media.
* EOM - end of media object encountered;
* MEDIA - media object missing or broken;
* DEVICE - device error;
* returns by reference number of bytes
* committed to media for the media file.
* this is the number of bytes written to
* media, which may be greater than what the
* client wrote due to record padding.
* NOTE: if last call to do_write returned
* an error, do_end_write will not do any
* I/O, and will return 0.
*/
int ( * do_fsf )( drive_t *drivep,
int count,
int *statp );
/* if d_capabilities has DRIVE_CAP_FSF set,
* drive has the capability to
* forward space count files. returns the
* number of actual files forwarded to. for
* example, if count is one, and there is a
* file after the current file, positions to
* the beginning of that file and returns 1.
* if the current file is the last one on the
* medium, returns 0, and leaves position at
* the end of recorded data, after the file
* mark. if there is a following file,
* positions such that the next read will
* retrieve the first data in that file.
* furthermore, *statp will be set in the
* following cases:
* EOD - encountered end of recorded data
* EOM - encountered end of media
* DEVICE - device error;
* NOTE: if media is positioned anywhere other
* than at the beginning of a media file,
* behaves as if position is at most recent
* file mark or BOT.
*/
int ( * do_bsf )( drive_t *drivep,
int count,
int *statp );
/* if d_capabilities has DRIVE_CAP_BSF set,
* drive has the capability to backward space
* count files. returns the number of actual
* files backed to.
* can only be invoked when not reading or
* writing (i.e., only after calling end_read
* or end_write, or prior to calling begin_read
* or begin_write). if count is zero, backs
* up to the beginning of the last media file
* read or written. if count is 1, backs up to
* the media file preceeding that one. returns
* the number of media files skipped. if
* the current file is the first one on the
* medium, returns 0, and leaves position
* at the beginning of recorded data. if count
* is one and there is a preceeding file,
* positions such that the next read will
* retrieve the first data in that file.
* furthermore, *statp will be set in the
* following cases:
* BOM - hit beginning of recorded data;
* DEVICE - device error;
*/
int ( * do_rewind )( drive_t *drivep );
/* if d_capabilities has DRIVE_CAP_REWIND set,
* drive has the capability to
* position at beginning of recorded data
* DEVICE - device error;
*/
int ( * do_erase )( drive_t *drivep );
/* if d_capabilities has DRIVE_CAP_ERASE set,
* drive has the capability to
* erase: all content of media object is
* eradicated.
* DEVICE - device error;
*/
int ( * do_eject_media )( drive_t *drivep );
/* if d_capabilities has DRIVE_CAP_EJECT set,
* drive has capability
* to eject media, and will do so when called.
* DEVICE - device error;
*/
int ( * do_get_device_class )( drive_t *drivep );
/* returns the media class of the device
* (see below).
*/
void ( * do_display_metrics )( drive_t *drivep );
/* use BARE mlog to print useful throughput
* and performance info. set to NULL if
* nothing to say.
*/
void ( * do_quit )( drive_t * drivep );
/* tells the drive manager to de-allocate
* resources, INCLUDING the slave process.
*/
};
typedef struct drive_ops drive_ops_t;
/* the drive managers are visible globally, but should be accessed sparingly.
* valid after drive_init1() returns successfully
*/
extern drive_t **drivepp;
extern size_t drivecnt;
extern size_t partialmax;
/* drive capabilities - bit positions in the capabilities mask
* DO NOT CHANGE: used in dh_capabilities field of scsi drive hdr.
*/
#define DRIVE_CAP_BSF ( 1 << 0 ) /* can backspace files */
#define DRIVE_CAP_FSF ( 1 << 1 ) /* can forwardspace files */
#define DRIVE_CAP_REWIND ( 1 << 2 ) /* can rewind */
#define DRIVE_CAP_FILES ( 1 << 4 ) /* supports multiple files */
#define DRIVE_CAP_APPEND ( 1 << 5 ) /* can append to end of rec. data */
#define DRIVE_CAP_OVERWRITE ( 1 << 6 ) /* can overwrite recorded data */
#define DRIVE_CAP_ERASE ( 1 << 6 ) /* can erase media */
#define DRIVE_CAP_NEXTMARK ( 1 << 8 ) /* can seek to a next good mark */
#define DRIVE_CAP_EJECT ( 1 << 12 ) /* can eject media */
#define DRIVE_CAP_AUTOREWIND ( 1 << 13 ) /* rewinds on media insertion */
#define DRIVE_CAP_READ ( 1 << 14 ) /* can read media */
#define DRIVE_CAP_REMOVABLE ( 1 << 15 ) /* can change media */
/* drive manager error codes - interpretation specific to and described
* in context of use.
*/
#define DRIVE_ERROR_CORRUPTION 1
#define DRIVE_ERROR_EOF 2
#define DRIVE_ERROR_EOD 3
#define DRIVE_ERROR_EOM 4
#define DRIVE_ERROR_BOM 5
#define DRIVE_ERROR_DEVICE 6
#define DRIVE_ERROR_FORMAT 7
#define DRIVE_ERROR_MEDIA 8
#define DRIVE_ERROR_VERSION 9
#define DRIVE_ERROR_CORE 10
#define DRIVE_ERROR_TIMEOUT 11
#define DRIVE_ERROR_STOP 12
#define DRIVE_ERROR_INVAL 13
#define DRIVE_ERROR_BLANK 14
#define DRIVE_ERROR_FOREIGN 15
#define DRIVE_ERROR_OVERWRITE 16
/* drive_init1 - select and instantiate a drive manager for each drive
* specified on the command line.
*
* Highly heuristic, using all avalable sources of information, including
* the command line (command name and parameters), experimentation, and
* drive-specific media functions, but excluding time-consuming operations
* such as tape motion.
*
* sets globals drivepp and drivecnt.
*
* Returns FALSE if utility should be aborted.
*/
extern bool_t drive_init1( int argc, char *argv[] );
/* drive_init2 - allocate and initialize read and write hdr buffers,
* and cause each drive manager to asynchronously determine if
* drive has media object mounted.
*
* Returns FALSE if the session should be aborted.
*/
extern bool_t drive_init2( int argc,
char *argv[],
global_hdr_t *gwhdrtemplatep );
/* drive_init3 - synchronize with async activity kicked off by drive_init3.
*
* Returns FALSE if the session should be aborted.
*/
extern bool_t drive_init3( void );
/* drive_mark_commit - invokes callback for all drive marks committed
* to media. ncommitted is the number of bytes actually committed to
* media so far. mark records with a mark offset less than or equal to
* ncommitted will have their callbacks invoked.
*/
extern void drive_mark_commit( drive_t *drivep, off64_t ncommitted );
/* drive_mark_discard - invokes callback of all uncommitted marks,
* indicating the commit did not occur.
*/
extern void drive_mark_discard( drive_t *drivep );
/* drive_display_metrics - display drive throughput and streaming metrics
* for all drives
*/
extern void drive_display_metrics( void );
/* device classes
* used for determining which media driver to employ
*/
#define DEVICE_NONREMOVABLE 1
#define DEVICE_TAPE_REMOVABLE 2
#define DEVICE_DISK_REMOVABLE 3
#endif /* DRIVE_H */