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 <syslog.h>
  40 #include <stdlib.h>
  41 #include "tlm.h"
  42 #include "tlm_proto.h"
  43 #include <sys/errno.h>
  44 
  45 
  46 extern  tlm_chain_link_t *tlm_un_ref(tlm_chain_link_t *old_top,
  47     tlm_chain_link_t *link);
  48 
  49 static  tlm_info_t tlm_info;
  50 
  51 /*
  52  * Mutex for concurrent access to job_stats
  53  */
  54 mutex_t jstat_mtx;
  55 
  56 
  57 /*
  58  * get the number of libraries
  59  */
  60 int
  61 tlm_library_count(void)
  62 {
  63         int     lib;
  64         tlm_library_t   *library;
  65 
  66         for (lib = 1; lib <= tlm_info.ti_library_count; lib++) {
  67                 library = tlm_library(lib);
  68                 if (library != NULL &&
  69                     library->tl_drive_count == 0) {
  70                         return (0);
  71                 }
  72         }
  73         return (tlm_info.ti_library_count);
  74 }
  75 
  76 /*
  77  * get the library whose number matches
  78  */
  79 tlm_library_t *
  80 tlm_library(int lib)
  81 {
  82         tlm_library_t   *library = tlm_info.ti_library;
  83         while (library != NULL) {
  84                 if (library->tl_number == lib) {
  85                         return (library);
  86                 }
  87                 library = library->tl_next;
  88         }
  89         errno = TLM_ERROR_RANGE;
  90         return (NULL);
  91 }
  92 
  93 /*
  94  * get the info about this drive
  95  */
  96 tlm_drive_t *
  97 tlm_drive(int lib, int drv)
  98 {
  99         tlm_drive_t     *drive;
 100         tlm_library_t   *library = tlm_library(lib);
 101 
 102         if (library == NULL) {
 103                 return (NULL);
 104         }
 105         drive = library->tl_drive;
 106         while (drive != NULL) {
 107                 if (drv == drive->td_number) {
 108                         return (drive);
 109                 }
 110                 drive = drive->td_next;
 111         }
 112         return (NULL);
 113 }
 114 
 115 /*
 116  * get the info about this slot
 117  */
 118 tlm_slot_t *
 119 tlm_slot(int lib, int slt)
 120 {
 121         tlm_slot_t      *slot = NULL;
 122         tlm_library_t   *library = tlm_library(lib);
 123 
 124         if (library != NULL)
 125                 slot = library->tl_slot;
 126         while (slot != NULL) {
 127                 if (slt == slot->ts_number) {
 128                         return (slot);
 129                 }
 130                 slot = slot->ts_next;
 131         }
 132         return (NULL);
 133 }
 134 
 135 /*
 136  * add a link to the INFO chain
 137  */
 138 tlm_job_stats_t *
 139 tlm_new_job_stats(char *name)
 140 {
 141         tlm_chain_link_t *new_link;
 142         tlm_job_stats_t *job_stats;
 143 
 144         new_link = ndmp_malloc(sizeof (tlm_chain_link_t));
 145         if (new_link == 0)
 146                 return (0);
 147 
 148         job_stats = ndmp_malloc(sizeof (tlm_job_stats_t));
 149         if (job_stats == 0) {
 150                 free(new_link);
 151                 return (0);
 152         }
 153 
 154         new_link->tc_ref_count = 1;
 155         new_link->tc_data = (void *)job_stats;
 156         (void) strlcpy(job_stats->js_job_name, name, TLM_MAX_BACKUP_JOB_NAME);
 157 
 158         (void) mutex_lock(&jstat_mtx);
 159         if (tlm_info.ti_job_stats == 0) {
 160                 new_link->tc_next = new_link;
 161                 new_link->tc_prev = new_link;
 162         } else {
 163                 tlm_chain_link_t *next_link = tlm_info.ti_job_stats;
 164                 tlm_chain_link_t *prev_link = next_link->tc_prev;
 165 
 166                 new_link->tc_next = next_link;
 167                 new_link->tc_prev = prev_link;
 168                 prev_link->tc_next = new_link;
 169                 next_link->tc_prev = new_link;
 170         }
 171         tlm_info.ti_job_stats = new_link;
 172         (void) mutex_unlock(&jstat_mtx);
 173 
 174         return (job_stats);
 175 }
 176 
 177 /*
 178  * make sure this Job Stats buffer is not deleted while we use it
 179  */
 180 tlm_job_stats_t *
 181 tlm_ref_job_stats(char *name)
 182 {
 183         static  tlm_job_stats_t fake_job_stats;
 184         tlm_chain_link_t        *link;
 185 
 186         (void) mutex_lock(&jstat_mtx);
 187         link = tlm_info.ti_job_stats;
 188         if (link == 0) {
 189                 /*
 190                  * our tables are empty
 191                  */
 192                 (void) mutex_unlock(&jstat_mtx);
 193                 return (&fake_job_stats);
 194         }
 195 
 196         do {
 197                 tlm_job_stats_t *job_stats;
 198                 job_stats = (tlm_job_stats_t *)link->tc_data;
 199 
 200                 if (strcmp(job_stats->js_job_name, name) == 0) {
 201                         link->tc_ref_count++;
 202                         (void) mutex_unlock(&jstat_mtx);
 203                         return (job_stats);
 204                 }
 205                 link = link->tc_next;
 206         } while (link != tlm_info.ti_job_stats);
 207         syslog(LOG_DEBUG,
 208             "TAPE BACKUP> Ref for job [%s] was not found", name);
 209         (void) mutex_unlock(&jstat_mtx);
 210 
 211         return (&fake_job_stats);
 212 }
 213 
 214 /*
 215  * remove a link to the INFO chain
 216  */
 217 void
 218 tlm_un_ref_job_stats(char *name)
 219 {
 220         tlm_chain_link_t *link;
 221 
 222         (void) mutex_lock(&jstat_mtx);
 223         link = tlm_info.ti_job_stats;
 224         if (link == 0) {
 225                 syslog(LOG_DEBUG, "TAPE BACKUP>"
 226                     " Internal error for job [%s], could not delete", name);
 227                 return;
 228         }
 229         do {
 230                 tlm_job_stats_t *job_stats;
 231                 job_stats = (tlm_job_stats_t *)link->tc_data;
 232 
 233                 if (strcmp(job_stats->js_job_name, name) == 0) {
 234                         tlm_info.ti_job_stats =
 235                             tlm_un_ref(tlm_info.ti_job_stats, link);
 236                         (void) mutex_unlock(&jstat_mtx);
 237                         return;
 238                 }
 239                 link = link->tc_next;
 240         } while (link != tlm_info.ti_job_stats);
 241         (void) mutex_unlock(&jstat_mtx);
 242         syslog(LOG_DEBUG,
 243             "TAPE BACKUP> Delete for job [%s] was not found", name);
 244 }
 245 
 246 /*
 247  * one party does not care about this blob, can we let it go?
 248  */
 249 tlm_chain_link_t *
 250 tlm_un_ref(tlm_chain_link_t *old_top, tlm_chain_link_t *link)
 251 {
 252         tlm_chain_link_t *chain_link = old_top;
 253         tlm_chain_link_t *new_top;
 254 
 255         /*
 256          * count down the number of
 257          * interested parties for this blob
 258          */
 259         link->tc_ref_count--;
 260         if (link->tc_ref_count > 0) {
 261                 /*
 262                  * there is still interest in this blob,
 263                  * no change yet
 264                  *
 265                  * returning "old_top" means there is no change in the links
 266                  */
 267                 return (old_top);
 268         }
 269 
 270         /*
 271          * no one cares about this data anymore
 272          * find out how to delete it
 273          */
 274         do {
 275                 if (chain_link == link) {
 276                         tlm_chain_link_t *next;
 277                         tlm_chain_link_t *prev;
 278 
 279                         /*
 280                          * If there are one or two elements in the list, then
 281                          * the prev and next pointers point to one element in
 282                          * the list, the element itself and the other element
 283                          * correspondingly.  So we must distinguish if there
 284                          * are only one or two elements in the list.  If
 285                          * either of the 'prev' or 'next' pointers point to
 286                          * the link itself, then we have only one element in
 287                          * the list.
 288                          */
 289                         if (link->tc_next == link->tc_prev &&
 290                             link->tc_next == link) {
 291                                 /*
 292                                  * there is only this one link in the chain
 293                                  * delete this and the chain is empty
 294                                  */
 295                                 new_top = 0;
 296                         } else {
 297                                 new_top = link->tc_next;
 298                         }
 299                         next = link->tc_next;
 300                         prev = link->tc_prev;
 301                         prev->tc_next = next;
 302                         next->tc_prev = prev;
 303                         free(link->tc_data);
 304                         free(link);
 305                         return (new_top);
 306                 }
 307                 chain_link = chain_link->tc_next;
 308         } while (chain_link != old_top);
 309         syslog(LOG_DEBUG, "TAPE BACKUP> un_ref target not found.");
 310         return (old_top);
 311 }
 312 
 313 /*
 314  * the following section is global, but not really part of the
 315  * public interface.  Use of this outside of the tlm_*.c files
 316  * is for special cases only.
 317  */
 318 
 319 /*
 320  * add a new tape library data blob to the list of libraries
 321  * returns the new tape library data blob just created
 322  */
 323 int
 324 tlm_insert_new_library(scsi_link_t *slink)
 325 {
 326         tlm_library_t **p_library = &tlm_info.ti_library;
 327         tlm_library_t *library = ndmp_malloc(sizeof (tlm_library_t));
 328 
 329         while (*p_library != NULL) {
 330                 p_library = &(*p_library)->tl_next;
 331         }
 332         tlm_info.ti_library_count++;
 333         library->tl_number = tlm_info.ti_library_count;
 334         library->tl_slink = slink;
 335         library->tl_capability_robot = TRUE;
 336         *p_library = library;
 337         return (library->tl_number);
 338 }
 339 
 340 /*
 341  * add a new tape drive data blob to the list of drives in a library
 342  * returns the new tape drive data blob just created
 343  */
 344 int
 345 tlm_insert_new_drive(int lib)
 346 {
 347         tlm_library_t *library = tlm_library(lib);
 348         tlm_drive_t *drive = ndmp_malloc(sizeof (tlm_drive_t));
 349         tlm_drive_t **p_drive = &library->tl_drive;
 350 
 351         while (*p_drive != NULL) {
 352                 p_drive = &(*p_drive)->td_next;
 353         }
 354         library->tl_drive_count++;
 355         library->tl_capability_drives = TRUE;
 356 
 357         drive->td_library = library;
 358         drive->td_number = library->tl_drive_count;
 359         *p_drive = drive;
 360         return (drive->td_number);
 361 }
 362 
 363 /*
 364  * add a new tape slot data blob to the list of slots in a library
 365  * returns the new tape slot data blob just created
 366  */
 367 int
 368 tlm_insert_new_slot(int lib)
 369 {
 370         tlm_library_t *library = tlm_library(lib);
 371         tlm_slot_t *slot = ndmp_malloc(sizeof (tlm_slot_t));
 372         tlm_slot_t **p_slot = &library->tl_slot;
 373 
 374         while (*p_slot != NULL) {
 375                 p_slot = &(*p_slot)->ts_next;
 376         }
 377         library->tl_slot_count++;
 378         library->tl_capability_slots = TRUE;
 379 
 380         slot->ts_library = library;
 381         slot->ts_number = library->tl_slot_count;
 382         *p_slot = slot;
 383         return (slot->ts_number);
 384 }