/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* BSD 3 Clause License
*
* Copyright (c) 2007, The Storage Networking Industry Association.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither the name of The Storage Networking Industry Association (SNIA)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include "tlm.h"
#include "tlm_proto.h"
#include <sys/errno.h>
extern tlm_chain_link_t *tlm_un_ref(tlm_chain_link_t *old_top,
tlm_chain_link_t *link);
static tlm_info_t tlm_info;
/*
* Mutex for concurrent access to job_stats
*/
mutex_t jstat_mtx;
/*
* get the number of libraries
*/
int
tlm_library_count(void)
{
int lib;
tlm_library_t *library;
for (lib = 1; lib <= tlm_info.ti_library_count; lib++) {
library = tlm_library(lib);
if (library != NULL &&
library->tl_drive_count == 0) {
return (0);
}
}
return (tlm_info.ti_library_count);
}
/*
* get the library whose number matches
*/
tlm_library_t *
tlm_library(int lib)
{
tlm_library_t *library = tlm_info.ti_library;
while (library != NULL) {
if (library->tl_number == lib) {
return (library);
}
library = library->tl_next;
}
errno = TLM_ERROR_RANGE;
return (NULL);
}
/*
* get the info about this drive
*/
tlm_drive_t *
tlm_drive(int lib, int drv)
{
tlm_drive_t *drive;
tlm_library_t *library = tlm_library(lib);
if (library == NULL) {
return (NULL);
}
drive = library->tl_drive;
while (drive != NULL) {
if (drv == drive->td_number) {
return (drive);
}
drive = drive->td_next;
}
return (NULL);
}
/*
* get the info about this slot
*/
tlm_slot_t *
tlm_slot(int lib, int slt)
{
tlm_slot_t *slot = NULL;
tlm_library_t *library = tlm_library(lib);
if (library != NULL)
slot = library->tl_slot;
while (slot != NULL) {
if (slt == slot->ts_number) {
return (slot);
}
slot = slot->ts_next;
}
return (NULL);
}
/*
* add a link to the INFO chain
*/
tlm_job_stats_t *
tlm_new_job_stats(char *name)
{
tlm_chain_link_t *new_link;
tlm_job_stats_t *job_stats;
new_link = ndmp_malloc(sizeof (tlm_chain_link_t));
if (new_link == 0)
return (0);
job_stats = ndmp_malloc(sizeof (tlm_job_stats_t));
if (job_stats == 0) {
free(new_link);
return (0);
}
new_link->tc_ref_count = 1;
new_link->tc_data = (void *)job_stats;
(void) strlcpy(job_stats->js_job_name, name, TLM_MAX_BACKUP_JOB_NAME);
(void) mutex_lock(&jstat_mtx);
if (tlm_info.ti_job_stats == 0) {
new_link->tc_next = new_link;
new_link->tc_prev = new_link;
} else {
tlm_chain_link_t *next_link = tlm_info.ti_job_stats;
tlm_chain_link_t *prev_link = next_link->tc_prev;
new_link->tc_next = next_link;
new_link->tc_prev = prev_link;
prev_link->tc_next = new_link;
next_link->tc_prev = new_link;
}
tlm_info.ti_job_stats = new_link;
(void) mutex_unlock(&jstat_mtx);
return (job_stats);
}
/*
* make sure this Job Stats buffer is not deleted while we use it
*/
tlm_job_stats_t *
tlm_ref_job_stats(char *name)
{
static tlm_job_stats_t fake_job_stats;
tlm_chain_link_t *link;
(void) mutex_lock(&jstat_mtx);
link = tlm_info.ti_job_stats;
if (link == 0) {
/*
* our tables are empty
*/
(void) mutex_unlock(&jstat_mtx);
return (&fake_job_stats);
}
do {
tlm_job_stats_t *job_stats;
job_stats = (tlm_job_stats_t *)link->tc_data;
if (strcmp(job_stats->js_job_name, name) == 0) {
link->tc_ref_count++;
(void) mutex_unlock(&jstat_mtx);
return (job_stats);
}
link = link->tc_next;
} while (link != tlm_info.ti_job_stats);
NDMP_LOG(LOG_DEBUG,
"TAPE BACKUP> Ref for job [%s] was not found", name);
(void) mutex_unlock(&jstat_mtx);
return (&fake_job_stats);
}
/*
* remove a link to the INFO chain
*/
void
tlm_un_ref_job_stats(char *name)
{
tlm_chain_link_t *link;
(void) mutex_lock(&jstat_mtx);
link = tlm_info.ti_job_stats;
if (link == 0) {
NDMP_LOG(LOG_DEBUG, "TAPE BACKUP>"
" Internal error for job [%s], could not delete", name);
return;
}
do {
tlm_job_stats_t *job_stats;
job_stats = (tlm_job_stats_t *)link->tc_data;
if (strcmp(job_stats->js_job_name, name) == 0) {
tlm_info.ti_job_stats =
tlm_un_ref(tlm_info.ti_job_stats, link);
(void) mutex_unlock(&jstat_mtx);
return;
}
link = link->tc_next;
} while (link != tlm_info.ti_job_stats);
(void) mutex_unlock(&jstat_mtx);
NDMP_LOG(LOG_DEBUG,
"TAPE BACKUP> Delete for job [%s] was not found", name);
}
/*
* one party does not care about this blob, can we let it go?
*/
tlm_chain_link_t *
tlm_un_ref(tlm_chain_link_t *old_top, tlm_chain_link_t *link)
{
tlm_chain_link_t *chain_link = old_top;
tlm_chain_link_t *new_top;
/*
* count down the number of
* interested parties for this blob
*/
link->tc_ref_count--;
if (link->tc_ref_count > 0) {
/*
* there is still interest in this blob,
* no change yet
*
* returning "old_top" means there is no change in the links
*/
return (old_top);
}
/*
* no one cares about this data anymore
* find out how to delete it
*/
do {
if (chain_link == link) {
tlm_chain_link_t *next;
tlm_chain_link_t *prev;
/*
* If there are one or two elements in the list, then
* the prev and next pointers point to one element in
* the list, the element itself and the other element
* correspondingly. So we must distinguish if there
* are only one or two elements in the list. If
* either of the 'prev' or 'next' pointers point to
* the link itself, then we have only one element in
* the list.
*/
if (link->tc_next == link->tc_prev &&
link->tc_next == link) {
/*
* there is only this one link in the chain
* delete this and the chain is empty
*/
new_top = 0;
} else {
new_top = link->tc_next;
}
next = link->tc_next;
prev = link->tc_prev;
prev->tc_next = next;
next->tc_prev = prev;
free(link->tc_data);
free(link);
return (new_top);
}
chain_link = chain_link->tc_next;
} while (chain_link != old_top);
NDMP_LOG(LOG_DEBUG, "TAPE BACKUP> un_ref target not found.");
return (old_top);
}
/*
* the following section is global, but not really part of the
* public interface. Use of this outside of the tlm_*.c files
* is for special cases only.
*/
/*
* add a new tape library data blob to the list of libraries
* returns the new tape library data blob just created
*/
int
tlm_insert_new_library(scsi_link_t *slink)
{
tlm_library_t **p_library = &tlm_info.ti_library;
tlm_library_t *library = ndmp_malloc(sizeof (tlm_library_t));
while (*p_library != NULL) {
p_library = &(*p_library)->tl_next;
}
tlm_info.ti_library_count++;
library->tl_number = tlm_info.ti_library_count;
library->tl_slink = slink;
library->tl_capability_robot = TRUE;
*p_library = library;
return (library->tl_number);
}
/*
* add a new tape drive data blob to the list of drives in a library
* returns the new tape drive data blob just created
*/
int
tlm_insert_new_drive(int lib)
{
tlm_library_t *library = tlm_library(lib);
tlm_drive_t *drive = ndmp_malloc(sizeof (tlm_drive_t));
tlm_drive_t **p_drive = &library->tl_drive;
while (*p_drive != NULL) {
p_drive = &(*p_drive)->td_next;
}
library->tl_drive_count++;
library->tl_capability_drives = TRUE;
drive->td_library = library;
drive->td_number = library->tl_drive_count;
*p_drive = drive;
return (drive->td_number);
}
/*
* add a new tape slot data blob to the list of slots in a library
* returns the new tape slot data blob just created
*/
int
tlm_insert_new_slot(int lib)
{
tlm_library_t *library = tlm_library(lib);
tlm_slot_t *slot = ndmp_malloc(sizeof (tlm_slot_t));
tlm_slot_t **p_slot = &library->tl_slot;
while (*p_slot != NULL) {
p_slot = &(*p_slot)->ts_next;
}
library->tl_slot_count++;
library->tl_capability_slots = TRUE;
slot->ts_library = library;
slot->ts_number = library->tl_slot_count;
*p_slot = slot;
return (slot->ts_number);
}