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
tlm_library_count(void)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 *
tlm_library(int lib)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 *
tlm_drive(int lib,int drv)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 *
tlm_slot(int lib,int slt)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 *
tlm_new_job_stats(char * name)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 *
tlm_ref_job_stats(char * name)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
tlm_un_ref_job_stats(char * name)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 *
tlm_un_ref(tlm_chain_link_t * old_top,tlm_chain_link_t * link)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
tlm_insert_new_library(scsi_link_t * slink)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
tlm_insert_new_drive(int lib)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
tlm_insert_new_slot(int lib)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 }
384