1 /*
   2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 #include <stdlib.h>
  40 #include "tlm.h"
  41 #include "tlm_proto.h"
  42 #include <sys/errno.h>
  43 
  44 
  45 extern  tlm_chain_link_t *tlm_un_ref(tlm_chain_link_t *old_top,
  46     tlm_chain_link_t *link);
  47 
  48 static  tlm_info_t tlm_info;
  49 
  50 /*
  51  * Mutex for concurrent access to job_stats
  52  */
  53 mutex_t jstat_mtx;
  54 
  55 
  56 /*
  57  * get the number of libraries
  58  */
  59 int
  60 tlm_library_count(void)
  61 {
  62         int     lib;
  63         tlm_library_t   *library;
  64 
  65         for (lib = 1; lib <= tlm_info.ti_library_count; lib++) {
  66                 library = tlm_library(lib);
  67                 if (library != NULL &&
  68                     library->tl_drive_count == 0) {
  69                         return (0);
  70                 }
  71         }
  72         return (tlm_info.ti_library_count);
  73 }
  74 
  75 /*
  76  * get the library whose number matches
  77  */
  78 tlm_library_t *
  79 tlm_library(int lib)
  80 {
  81         tlm_library_t   *library = tlm_info.ti_library;
  82         while (library != NULL) {
  83                 if (library->tl_number == lib) {
  84                         return (library);
  85                 }
  86                 library = library->tl_next;
  87         }
  88         errno = TLM_ERROR_RANGE;
  89         return (NULL);
  90 }
  91 
  92 /*
  93  * get the info about this drive
  94  */
  95 tlm_drive_t *
  96 tlm_drive(int lib, int drv)
  97 {
  98         tlm_drive_t     *drive;
  99         tlm_library_t   *library = tlm_library(lib);
 100 
 101         if (library == NULL) {
 102                 return (NULL);
 103         }
 104         drive = library->tl_drive;
 105         while (drive != NULL) {
 106                 if (drv == drive->td_number) {
 107                         return (drive);
 108                 }
 109                 drive = drive->td_next;
 110         }
 111         return (NULL);
 112 }
 113 
 114 /*
 115  * get the info about this slot
 116  */
 117 tlm_slot_t *
 118 tlm_slot(int lib, int slt)
 119 {
 120         tlm_slot_t      *slot = NULL;
 121         tlm_library_t   *library = tlm_library(lib);
 122 
 123         if (library != NULL)
 124                 slot = library->tl_slot;
 125         while (slot != NULL) {
 126                 if (slt == slot->ts_number) {
 127                         return (slot);
 128                 }
 129                 slot = slot->ts_next;
 130         }
 131         return (NULL);
 132 }
 133 
 134 /*
 135  * add a link to the INFO chain
 136  */
 137 tlm_job_stats_t *
 138 tlm_new_job_stats(char *name)
 139 {
 140         tlm_chain_link_t *new_link;
 141         tlm_job_stats_t *job_stats;
 142 
 143         new_link = ndmp_malloc(sizeof (tlm_chain_link_t));
 144         if (new_link == 0)
 145                 return (0);
 146 
 147         job_stats = ndmp_malloc(sizeof (tlm_job_stats_t));
 148         if (job_stats == 0) {
 149                 free(new_link);
 150                 return (0);
 151         }
 152 
 153         new_link->tc_ref_count = 1;
 154         new_link->tc_data = (void *)job_stats;
 155         (void) strlcpy(job_stats->js_job_name, name, TLM_MAX_BACKUP_JOB_NAME);
 156 
 157         (void) mutex_lock(&jstat_mtx);
 158         if (tlm_info.ti_job_stats == 0) {
 159                 new_link->tc_next = new_link;
 160                 new_link->tc_prev = new_link;
 161         } else {
 162                 tlm_chain_link_t *next_link = tlm_info.ti_job_stats;
 163                 tlm_chain_link_t *prev_link = next_link->tc_prev;
 164 
 165                 new_link->tc_next = next_link;
 166                 new_link->tc_prev = prev_link;
 167                 prev_link->tc_next = new_link;
 168                 next_link->tc_prev = new_link;
 169         }
 170         tlm_info.ti_job_stats = new_link;
 171         (void) mutex_unlock(&jstat_mtx);
 172 
 173         return (job_stats);
 174 }
 175 
 176 /*
 177  * make sure this Job Stats buffer is not deleted while we use it
 178  */
 179 tlm_job_stats_t *
 180 tlm_ref_job_stats(char *name)
 181 {
 182         static  tlm_job_stats_t fake_job_stats;
 183         tlm_chain_link_t        *link;
 184 
 185         (void) mutex_lock(&jstat_mtx);
 186         link = tlm_info.ti_job_stats;
 187         if (link == 0) {
 188                 /*
 189                  * our tables are empty
 190                  */
 191                 (void) mutex_unlock(&jstat_mtx);
 192                 return (&fake_job_stats);
 193         }
 194 
 195         do {
 196                 tlm_job_stats_t *job_stats;
 197                 job_stats = (tlm_job_stats_t *)link->tc_data;
 198 
 199                 if (strcmp(job_stats->js_job_name, name) == 0) {
 200                         link->tc_ref_count++;
 201                         (void) mutex_unlock(&jstat_mtx);
 202                         return (job_stats);
 203                 }
 204                 link = link->tc_next;
 205         } while (link != tlm_info.ti_job_stats);
 206         NDMP_LOG(LOG_DEBUG,
 207             "TAPE BACKUP> Ref for job [%s] was not found", name);
 208         (void) mutex_unlock(&jstat_mtx);
 209 
 210         return (&fake_job_stats);
 211 }
 212 
 213 /*
 214  * remove a link to the INFO chain
 215  */
 216 void
 217 tlm_un_ref_job_stats(char *name)
 218 {
 219         tlm_chain_link_t *link;
 220 
 221         (void) mutex_lock(&jstat_mtx);
 222         link = tlm_info.ti_job_stats;
 223         if (link == 0) {
 224                 NDMP_LOG(LOG_DEBUG, "TAPE BACKUP>"
 225                     " Internal error for job [%s], could not delete", name);
 226                 return;
 227         }
 228         do {
 229                 tlm_job_stats_t *job_stats;
 230                 job_stats = (tlm_job_stats_t *)link->tc_data;
 231 
 232                 if (strcmp(job_stats->js_job_name, name) == 0) {
 233                         tlm_info.ti_job_stats =
 234                             tlm_un_ref(tlm_info.ti_job_stats, link);
 235                         (void) mutex_unlock(&jstat_mtx);
 236                         return;
 237                 }
 238                 link = link->tc_next;
 239         } while (link != tlm_info.ti_job_stats);
 240         (void) mutex_unlock(&jstat_mtx);
 241         NDMP_LOG(LOG_DEBUG,
 242             "TAPE BACKUP> Delete for job [%s] was not found", name);
 243 }
 244 
 245 /*
 246  * one party does not care about this blob, can we let it go?
 247  */
 248 tlm_chain_link_t *
 249 tlm_un_ref(tlm_chain_link_t *old_top, tlm_chain_link_t *link)
 250 {
 251         tlm_chain_link_t *chain_link = old_top;
 252         tlm_chain_link_t *new_top;
 253 
 254         /*
 255          * count down the number of
 256          * interested parties for this blob
 257          */
 258         link->tc_ref_count--;
 259         if (link->tc_ref_count > 0) {
 260                 /*
 261                  * there is still interest in this blob,
 262                  * no change yet
 263                  *
 264                  * returning "old_top" means there is no change in the links
 265                  */
 266                 return (old_top);
 267         }
 268 
 269         /*
 270          * no one cares about this data anymore
 271          * find out how to delete it
 272          */
 273         do {
 274                 if (chain_link == link) {
 275                         tlm_chain_link_t *next;
 276                         tlm_chain_link_t *prev;
 277 
 278                         /*
 279                          * If there are one or two elements in the list, then
 280                          * the prev and next pointers point to one element in
 281                          * the list, the element itself and the other element
 282                          * correspondingly.  So we must distinguish if there
 283                          * are only one or two elements in the list.  If
 284                          * either of the 'prev' or 'next' pointers point to
 285                          * the link itself, then we have only one element in
 286                          * the list.
 287                          */
 288                         if (link->tc_next == link->tc_prev &&
 289                             link->tc_next == link) {
 290                                 /*
 291                                  * there is only this one link in the chain
 292                                  * delete this and the chain is empty
 293                                  */
 294                                 new_top = 0;
 295                         } else {
 296                                 new_top = link->tc_next;
 297                         }
 298                         next = link->tc_next;
 299                         prev = link->tc_prev;
 300                         prev->tc_next = next;
 301                         next->tc_prev = prev;
 302                         free(link->tc_data);
 303                         free(link);
 304                         return (new_top);
 305                 }
 306                 chain_link = chain_link->tc_next;
 307         } while (chain_link != old_top);
 308         NDMP_LOG(LOG_DEBUG, "TAPE BACKUP> un_ref target not found.");
 309         return (old_top);
 310 }
 311 
 312 /*
 313  * the following section is global, but not really part of the
 314  * public interface.  Use of this outside of the tlm_*.c files
 315  * is for special cases only.
 316  */
 317 
 318 /*
 319  * add a new tape library data blob to the list of libraries
 320  * returns the new tape library data blob just created
 321  */
 322 int
 323 tlm_insert_new_library(scsi_link_t *slink)
 324 {
 325         tlm_library_t **p_library = &tlm_info.ti_library;
 326         tlm_library_t *library = ndmp_malloc(sizeof (tlm_library_t));
 327 
 328         while (*p_library != NULL) {
 329                 p_library = &(*p_library)->tl_next;
 330         }
 331         tlm_info.ti_library_count++;
 332         library->tl_number = tlm_info.ti_library_count;
 333         library->tl_slink = slink;
 334         library->tl_capability_robot = TRUE;
 335         *p_library = library;
 336         return (library->tl_number);
 337 }
 338 
 339 /*
 340  * add a new tape drive data blob to the list of drives in a library
 341  * returns the new tape drive data blob just created
 342  */
 343 int
 344 tlm_insert_new_drive(int lib)
 345 {
 346         tlm_library_t *library = tlm_library(lib);
 347         tlm_drive_t *drive = ndmp_malloc(sizeof (tlm_drive_t));
 348         tlm_drive_t **p_drive = &library->tl_drive;
 349 
 350         while (*p_drive != NULL) {
 351                 p_drive = &(*p_drive)->td_next;
 352         }
 353         library->tl_drive_count++;
 354         library->tl_capability_drives = TRUE;
 355 
 356         drive->td_library = library;
 357         drive->td_number = library->tl_drive_count;
 358         *p_drive = drive;
 359         return (drive->td_number);
 360 }
 361 
 362 /*
 363  * add a new tape slot data blob to the list of slots in a library
 364  * returns the new tape slot data blob just created
 365  */
 366 int
 367 tlm_insert_new_slot(int lib)
 368 {
 369         tlm_library_t *library = tlm_library(lib);
 370         tlm_slot_t *slot = ndmp_malloc(sizeof (tlm_slot_t));
 371         tlm_slot_t **p_slot = &library->tl_slot;
 372 
 373         while (*p_slot != NULL) {
 374                 p_slot = &(*p_slot)->ts_next;
 375         }
 376         library->tl_slot_count++;
 377         library->tl_capability_slots = TRUE;
 378 
 379         slot->ts_library = library;
 380         slot->ts_number = library->tl_slot_count;
 381         *p_slot = slot;
 382         return (slot->ts_number);
 383 }