xref: /illumos-gate/usr/src/cmd/ndmpd/tlm/tlm_info.c (revision f3041bfa)
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 }
384