The OpenVault approach centralizes virtually all of the configuration and management problems for a given library into a piece of software custom written for that library. This means that new library support can be added to an existing environment by simply adding a new piece of software.
The Library Control Program (LCP) is the part of the OpenVault system which knows the intimate details of a particular library and its configuration and control procedures. The language which the MLM Core program speaks to the LCP and the corresponding response language are collectively called the Abstract Library Interface (ALI). ALI is designed to abstract away as many of the details of a library as practicable, without compromising the ability of the OpenVault system as a whole to efficiently manage its resources.
An LCP can be thought of as a black-box language translator device and/or a device management module. The LCP is responsible for performing the tasks that the MLM Core asks it to do while efficiently managing the resources of the library. It speaks ALI with the MLM Core, and some device-specific language to the library itself.
Each LCP has responsibility only for the information that it can gain from reading its configuration file and talking to the connected library. The responsibility to read and determine the information at run time also means that they are the authoritative source for that information. Specifically, the library itself is the authoritative source for information about the library, the LCP is just a buffer and a translator. The MLM Core will ask for device information at (re)boot time or when it needs updated information for some reason. The MLM Core database is available for use as a persistent store by the LCP, however.
We assume that the MLM Core will use information from the DCP's (Drive Control Programs) associated with each drive in a library in conjunction with information from the LCP to manage both of them.
| command | During the command phase the sender transmits the text of the command. The sender assigns a unique task ID to each command it generates, and sends that task ID as part of the outgoing command. The task ID will be used to match responses with the correct command. |
| ack | During the ack phase the receiver of the command sends back a packet indicating that it has successfully received the command with the given task ID. The sender cannot send another command until it receives the ack for the prior command. This allows the receiver to throttle the command sequence if necessary. It is possible for the receiver to send back an unacceptable response instead of an ack if the command was incorrectly constructed. In that case, there would be no data phase. |
| data | During the data phase the receiver of the command sends back the task ID, so as to identify which command is being responded to, and the the actual return value. Note that the return value can be an indication of success, of failure, or a value being returned. Return values may intervene on the channel between transmission of a command and receipt of the corresponding ACK. Commands, ACKs, and return values may intervene on the channel between transmission of an ACK and receipt of the corresponding return value. |
Each end of the communications channel must be prepared to both read and write the channel when it desires to either send or receive on the channel. For example, if one end desires to send on the channel but the channel is full and our write would block, we must be prepared to read any available data on the incoming channel. The next effect is that the only blocking I/O operation permitted on the channel is a select() call. This requirement is how we avoid the possibility of deadlocks on access to the comm channel.
| ALI | The language spoken by the MLM Core to the LCP. |
| ALI/R | The language spoken by the LCP to the MLM Core. The full name is the ALI Response language. |
| cartridge |
A cartridge is the physical shell that encases the writeable media.
Note that not all types of media are writeable, eg: CDROM.
We distinguish between a cartridge and the media it contains because
an LCP is only concerned with the cartridge and not the media,
and some types of cartridges contain more that one piece of media,
eg: two sided optical disks.
|
| PCL |
The Physical Cartridge Label is some form of cartridge
identification on the outside of the cartridge,
instead of stored on the media inside the cartridge.
This is usually a barcode, and is usually machine readable,
but could also be handwritten notes for a non-sighted library.
|
| form factor |
This is the name for the type of cartridges handled by the library.
For example, "DLT", "8mm", "4mm", etc. are valid form factors.
The names presented here are "blessed names" in that they must be
the same names as MLM Core uses for physical cartridge types.
See the document on
Pre-Defined Tokens and Descriptions
for more examples.
Note that the format of the bits on the media contained in the cartridge is not specified here. For exmple: a "3480" form factor could be written with bits in 3480 format or with bits in 3490 format (ie: it is really a 3490 tape). Again, see the document on Pre-Defined Tokens and Descriptions for more examples.
|
| drive |
This refers to the device used to access the contents of the media,
eg: this could be a tape drive or an optical disc drive.
Note that the LCP never accesses the media,
it only moves the cartridge to the drive so that a DCP,
and then the application, can access the media.
The MLM Core needs to know the names of the drives contained within an LCP. The LCP needs to know the correspondence between the OpenVault name for a drive and the addressing information for that drive within the library, but the MLM Core does not because it will always refer to it by name.
|
| slot ID |
This is a text string provided by the LCP,
which OpenVault treats as an opaque handle,
referring to a particular physical slot in the library.
OpenVault will only display a slotID or do a
string comparison with another slotID to check for equality.
The LCP should generate slotIDs such that when a human looks at them they make some sort of sense in terms of the topology of the library. For example: "slot 34", "bay 3, slot 128", and "room H, rack 4, tape 22" are all good slotIDs. The slotID must be sufficient to uniquely identify any slot under the control of that LCP. The slotIDs must also be parseable by the LCP. SlotIDs will be used by the Administrator to do physical slot addressing, and non-sighted libraries must use them for cartridge mounts, so the LCP needs to be able to recover the semantic information from the slotID.
|
| bayID |
This is a text string provided by the LCP,
which OpenVault treats as an opaque handle,
referring to a particular group of physical slots in the library.
OpenVault will only display a bayID or do a
string comparison with another bayID to check for equality.
The MLM Core uses bayIDs to compare access times
(ie: locality information) for carts and drives.
The LCP should generate bayIDs such that when a human looks at them they make some sort of sense in terms of the topology of the library. For example: "bay 3", "bay 4", and "room H" are all good bayIDs. For some libraries, the difference between one bay and another will be obvious based on topology and access times. For example, each silo in a group of Storage Tek silos would be a separate bay, and each room in a tape library building would be a bay. They are defined based on a large increase in the access time for a cartridge between inside the bay versus outside the bay.
|
| mount |
The mount command is used to mount cartridge(s) into drive(s).
The mount arguments are a single drive name
and a set of triplets of slotIDs, PCLs, and sides.
The operation is to take one of the cartridges from the given slots
and put it into the given drive.
In sighted libraries,
the cartridge in a given slot must have the corresponding PCL
or it will be skipped.
Note that there may be only one slot specified. If there is more than one slot specified, which slot is mounted is explicitly an LCP decision.
|
||||||||||||||||
| unmount |
The unmount command is used to unmount a cartridge from a drive.
The unmount arguments are a drive name
and either a list of slotIDs or a wildcard token.
The operation is to take the cartridge from the given drive
and put it into one of the given slots,
or any available slot if the wildcard token is used.
Note that there may be only one slot specified. If there is more than one slot specified, which slot the cartridge is placed in is explicitly an LCP decision.
|
||||||||||||||||
| move |
The move command is used to move a cartridge from one
physical slot in the library to another physical slot.
The move source is both a slotID
and the PCL for the cartridge in that slot.
The destination is a single slotID.
In sighted libraries,
the PCL is used as a cross-check on the contents of the source slot.
|
||||||||||||||||
| eject |
The eject command is used
in conjunction with the openPort command
to push a cartridge out of the library.
It takes a pair consisting of a slotIDs and a PCL
representing the cartridge that is to be operated on.
In sighted libraries,
the cartridge in that slot must have that PCL or an error is returned.
The implementation of the eject command will vary from LCP to LCP,
but there seem to be 3 basic cases:
When a cartridge is ejected it should immediately be marked as inaccessable in the slotmap maintained in the MLM Core by the LCP. This implies that an LCP that cannot immediately push the cartridge out of the library must be prepared to store the fact that a particular slotID (and therefore PCL) has been marked for ejection and filter that PCL out of the slotmap that it pushes into the MLM Core until the cartridge is actually removed from the library. The LCP is free to mark a slotID as inaccessable in order to accomplish this.
|
||||||||||||||||
| openPort |
The openPort command is used in conjunction with the eject
command to push cartridges out of the library.
It may also be used on its own in order to do cartridge import operations.
The function of the openPort command is to ready the library
for the operator to have physical access to the cartridge inventory.
Once physical access is gained, new cartridges can be put into the library. Given the three classes of libraries defined above (note that any given library might be in a different class for export than it is for import):
See the description of the ready and ready not commands in ALI/R for more information about how an LCP takes a library offline during an openPort operation. There will be a configurable switch in OpenVault for each non-sighted LCP. The switch tells OpenVault what to do when the slotmap for that library changes. If the occupancy information in the slotmap has not changed, should OpenVault continue normal operation of that library or stop and wait for the operator to verify the correctness of the slotmap. Cartridge export operations are explained above.
|
||||||||||||||||
| scan |
The scan command and its variations are used to force
the LCP to (re)verify the PCLs of the cartridges in the library.
| ||||||||||||||||
| activate |
The activate command and its variations are used to start/stop
the LCP's interactions with the library.
The LCP will generate one of the ready command variations
just before it has finished processing the activate command.
| ||||||||||||||||
| reset |
The reset command is used to force the LCP to do whatever is
required to get the library to reinitialize and run any internal
diagnostics.
This is a best effort command, the LCP should do everything
that it can, but there is no hard requirement to do anything.
The ready not command will likely be used by the LCP to tell the MLM Core that the LCP is temporarily busy and not available for cartridge mounts while the reset is taking place.
|
||||||||||||||||
| exit |
The exit command is used to tell the LCP to clean up and exit.
The LCP should store any persistent information in the MLM Core database, do any closedown operations that are required by its interface to the library, then it should exit.
|
||||||||||||||||
| barrier |
The barrier command is used to force the LCP to compelete work
on all commands received prior to the barrier command before it
begins work on any commands that might have followed it.
An LCP is in general free to execute the commands that it receives in any convenient order. Since there might be circumstances where the MLM Core will require an explicit order that a sequence of commands must be executed in, the barrier command can be used to force that ordering.
| ||||||||||||||||
| attribute |
The attribute command is used to set and unset named attributes
in the LCP.
You can think of attributes in an LCP as named memory locations.
Some of the attributes defined by an LCP may be read-only to the MLM Core.
It is permissible for the act of setting or accessing an attribute to
cause some operation to happen as a side effect.
A list of attribute names that should be supported by every LCP is listed in a section below, and in the Pre-Defined Tokens and Descriptions document.
|
||||||||||||||||
| show |
The show command is used to obtain the current value of an attribute.
Some of the attributes defined by an LCP may be write-only to the MLM Core.
|
||||||||||||||||
| cancel | The cancel command is used to prevent the execution of a command that has already been queued in the LCP but not yet started. The cancelled command will return a response cancelled status, while the response for the cancel command itself will follow. |
| slotmap |
A slotmap is an array of elements provided by the LCP that allow
the MLM Core to operate and administer the library,
with one element per named slot in the library.
Note that there may be free slots with names and free slots without names.
Various pieces of information about each named slot is stored by the MLM Core and refreshed by the LCP when appropriate. The stored data includes:
Some libraries do not have names for empty slots. The slotmap for such an LCP will only contain information on slots that are occupied and the LCP must provide a count of the number of unnamed free slots for each form factor in each bay.
|
| message |
A message is an uninterpreted character string that the LCP would
like to be stored in the MLM Core logs, displayed on the operator console,
sent to the administrator, or possibly all of the above.
|
| severity level |
A severity level is a level of urgency associated with a
message.
This determines (along with site policy) whether the text of the message
is simply stored in the MLM Core logs or
displayed on the operator or administrator consoles
or both.
|
| operator vs. administrator |
A message is targetted by the generating LCP at either an
operator or an administrator.
An Operator is assumed to be the person who has day to day responsibility
for maintaining the hardware and the cartridge pool.
An Administrator is assumed to be the person who has control over
library configuration and access issues.
The two functions could be supported by the same person.
|
| message |
The message command is used to send a message of some
severity level to the MLM Core's Operator Interface,
Administrator Interface, and/or logfile.
Based on the severity level and site policy,
messages may be (re)directed to some combination of those destinations.
This command provides a mechanism for the LCP to send messages to the operator and/or administrator based on LCP-dependent conditions or errors.
|
| config |
The config command copies configuration information
(especially changed slotmap information)
from the LCP up to the MLM Core for use.
The MLM Core stores a non-authoritative copy of all the slotmap information for all the LCPs it controls. Each LCP must use the config command in ALI/R to update the copy of the slotmap information in the MLM Core whenever it changes. Note that since slotmaps are defined to be stable in ALI Version 1, the slotmap should only change as a result of Administrator or Operator actions. In a full scope, all information associated with the LCP should be deleted and replaced with the information listed in the config command. In a partial scope, only the pieces of information about the LCP that are listed in the config command should be replaced. It is expected that the norm will be to use the full scope option on startup and/or major changes to the library configuration, and that the partial scope will be used when a cartridge movement operation happens. Very large libraries can initially use a partially populated full scope command followed by a series of partial scope commands for startup information if a full scope would be too unwieldy. The config command is used to:
|
| ready |
The ready command and its variations are used to tell
the MLM Core the current status of the library,
ie: is it available for cartridge operations?
|
| attribute |
The attribute command is used to set and unset named attributes
in the MLM Core in order to create persistent storage for whatever
the LCP deems necessary.
The MLM Core simply stores these attributes, there are never any
side effects of setting them.
|
| show |
The show command is used to obtain the value of an attribute
that was stored in the MLM Core by the LCP.
|
| cancel | The cancel command is used to prevent the execution of a command that has already been queued in the MLM Core but not yet started. The cancelled command will return a response cancelled status, while the response for the cancel command itself will follow. This is really only here for completeness, it is not expected that any LCPs will need to use it. |
Syntactic conventions are the same as for CAPI, including that single quotes may be used in place of double quotes in all contexts.
| commands |
mountStmt unmountStmt moveStmt ejectStmt openportStmt scanStmt activateStmt barrierStmt resetStmt exitStmt attributeStmt showStmt cancelStmt responseStmt |
| mountStmt |
mount mountArgs ; |
| mountArgs |
/* empty */ task [ string ] mountArgs drive [ string ] mountArgs slot [ string string string ] mountArgs |
| unmountStmt |
unmount unmountArgs ; |
| unmountArgs |
/* empty */ task [ string ] unmountArgs drive [ string ] unmountArgs slotid [ string ] unmountArgs any unmountArgs |
| moveStmt |
move moveArgs ; |
| moveArgs |
/* empty */ task [ string ] moveArgs from [ string string ] moveArgs to [ string ] moveArgs |
| ejectStmt |
eject ejectArgs ; |
| ejectArgs |
/* empty */ task [ string ] ejectArgs slot [ string string ] ejectArgs |
| scanStmt |
scan scanArgs ; |
| scanArgs |
/* empty */ task [ string ] scanArgs all scanArgs from [ string ] scanArgs to [ string ] scanArgs |
| openportStmt |
openport task [ string ] ; |
| activateStmt |
activate activateArgs ; |
| activateArgs |
/* empty */ task [ string ] activateArgs enable activateArgs disable activateArgs |
| barrierStmt |
barrier task [ string ] ; |
| resetStmt |
reset task [ string ] ; |
| exitStmt |
exit task [ string ] ; |
| attributeStmt |
attribute attributeArgs ; |
| attributeArgs |
/* empty */ task [ string ] attributeArgs type [ string ] attributeArgs name [ string ] attributeArgs set [ string string ] attributeArgs unset [ string ] attributeArgs |
| showStmt |
show showArgs ; |
| showArgs |
/* empty */ task [ string ] showArgs type [ string ] showArgs name [ string ] showArgs report [ listOfStrings ] showArgs reportmode [ string ] showArgs |
| cancelStmt |
cancel cancelArgs ; |
| cancelArgs |
/* empty */ task [ string ] cancelArgs whichtask [ string ] cancelArgs |
| responseStmt |
response responseArgs ; |
| responseArgs |
/* empty */ whichtask [ string ] responseArgs accepted responseArgs unacceptable responseArgs success responseArgs error [ string ] responseArgs cancelled responseArgs text [ listOfStrings ] responseArgs |
| listOfStrings |
/* empty */ STRING listOfStrings |
| string |
STRING |
| commands |
responseStmt messageStmt configStmt readyStmt attributeStmt showStmt cancelStmt |
| messageStmt |
message messageArgs ; |
| messageArgs |
/* empty */ task [ string ] messageArgs who [ string ] messageArgs severity [ string ] messageArgs text [ listOfStrings ] messageArgs |
| configStmt |
config configArgs ; |
| configArgs |
/* empty */ task [ string ] configArgs scope [ string ] configArgs slot [ string string string string string string ] configArgs bay [ string string ] configArgs drive [ string string string string string ] configArgs freeslots [ string string string ] configArgs delslots [ string ] configArgs perf [ string string ] configArgs |
| readyStmt |
ready readyArgs ; |
| readyArgs |
/* empty */ task [ string ] readyArgs disconnected readyArgs broken readyArgs not [ listOfStrings ] readyArgs |
| attributeStmt |
attribute attributeArgs ; |
| attributeArgs |
/* empty */ task [ string ] attributeArgs type [ string ] attributeArgs name [ string ] attributeArgs set [ string string ] attributeArgs unset [ string ] attributeArgs |
| showStmt |
show showArgs ; |
| showArgs |
/* empty */ task [ string ] showArgs type [ string ] showArgs name [ string ] showArgs report [ listOfStrings ] showArgs reportmode [ string ] showArgs |
| cancelStmt |
cancel cancelArgs ; |
| cancelArgs |
/* empty */ task [ string ] cancelArgs whichtask [ string ] cancelArgs |
| responseStmt |
response responseArgs ; |
| responseArgs |
/* empty */ whichtask [ string ] responseArgs accepted responseArgs unacceptable responseArgs success responseArgs error [ string ] responseArgs cancelleD responseArgs text [ listOfStrings ] responseArgs |
| listOfStrings |
/* empty */ STRING listOfStrings |
| string |
STRING |
| Message Structure | Resulting Look |
| "This is a long single string message output by an LCP that is not concerned about a specific structure on the screen." | This is a long single string message output by an LCP that is not concerned about a specific structure on the screen. |
| "This is a set of short messages." "Taken together they have a structure." "But they should also be distinct." |
This is a set of short messages. Taken together they have a structure. But they should also be distinct. |
| Error String | Meaning | ALI Commands |
|---|---|---|
| ALI_E_NONE | no error | |
| ALI_E_NOSLOT | unknown slot | |
| ALI_E_NOPCL | unknown PCL | |
| ALI_E_NOBAY | unknown bay | |
| ALI_E_NODRIVE | unknown drive | |
| ALI_E_NOATTR | unknown attribute | |
| ALI_E_NOTYPE | unknown type | |
| ALI_E_NOCMD | unknown command | |
| ALI_E_NOTASK | unknown task id | |
| ALI_E_ACCESS | access denied/object inaccessible | |
| ALI_E_BADVAL | bad attribute value | |
| ALI_E_SRCFULL | source location full | |
| ALI_E_SRCEMPTY | source location empty | |
| ALI_E_DSTFULL | destination location full | |
| ALI_E_DSTEMPTY | destination location empty | |
| ALI_E_AGAIN | retry recommended | |
| ALI_E_READY | target not ready | |
| ALI_E_PCL | PCL mismatch | |
| ALI_E_SEQUENCE | Command sequence error | |
| ALI_E_ABORT | Command aborted by LCP | |
| ALI_E_LIBRARY | library or device driver failure | |
| ALI_E_SHAPE | Cart-drive fungibility error |
There are undoubtedly more error codes, but they have not yet been defined.
Quoted values must be used literally as shown. Unquoted values are descriptions or variable names. The following acronyms are used: r/w - readable and writeable, r/o - readable only, w/o - writeable only.
| Type | Name | Attr Name | Access | Description of Contents |
| "LCP" | "" | "name" | r/o | OpenVault name for that library |
| "LCP" | "" | "support_PCLs" | r/o | true/false: does this lib support PCLs |
| "LCP" | "" | "vendor" | r/o | make and model number of library |
| "LCP" | "" | "loglevel" | r/w | severity level of messages to log |
| "bayID" | bayID | "description" | r/o | prose describing how to physically find that bay in the library |
| "slotID" | slotID | "description" | r/o | prose describing how to physically find that slot in the library |