1 /*
2  * Copyright (c) 1998,1999,2000
3  *	Traakan, Inc., Los Altos, CA
4  *	All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  */
36 
37 
38 #include "ndmagents.h"
39 
40 
41 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
42 void
ndmca_jobcontrol_register_callbacks(struct ndm_session * sess,struct ndmca_jobcontrol_callbacks * callbacks)43 ndmca_jobcontrol_register_callbacks (struct ndm_session *sess,
44       struct ndmca_jobcontrol_callbacks *callbacks)
45 {
46    /*
47     * Only allow one register.
48     */
49    if (!sess->jobcontrol_cbs) {
50       sess->jobcontrol_cbs = NDMOS_API_MALLOC (sizeof(struct ndmca_jobcontrol_callbacks));
51       if (sess->jobcontrol_cbs) {
52          memcpy (sess->jobcontrol_cbs, callbacks, sizeof(struct ndmca_jobcontrol_callbacks));
53       }
54    }
55 }
56 
57 void
ndmca_jobcontrol_unregister_callbacks(struct ndm_session * sess)58 ndmca_jobcontrol_unregister_callbacks (struct ndm_session *sess)
59 {
60    if (sess->jobcontrol_cbs) {
61       NDMOS_API_FREE (sess->jobcontrol_cbs);
62       sess->jobcontrol_cbs = NULL;
63    }
64 }
65 
66 
67 
68 int ndmca_monitor_backup_tape_tcp (struct ndm_session *sess);
69 int ndmca_monitor_recover_tape_tcp (struct ndm_session *sess);
70 int ndmca_monitor_shutdown_tape_tcp (struct ndm_session *sess);
71 
72 int
ndmca_op_create_backup(struct ndm_session * sess)73 ndmca_op_create_backup (struct ndm_session *sess)
74 {
75 	struct ndm_control_agent *ca = sess->control_acb;
76 	int			rc;
77 
78 	ca->tape_mode = NDMP9_TAPE_RDWR_MODE;
79 	ca->mover_mode = NDMP9_MOVER_MODE_READ;
80 	ca->is_label_op = 0;
81 
82 	rc = ndmca_backreco_startup (sess);
83 	if (rc) return rc;
84 
85 	rc = ndmca_data_start_backup (sess);
86 	if (rc == 0) {
87 	    rc = ndmca_monitor_startup (sess);
88 	    if (rc == 0) {
89 		rc = ndmca_monitor_backup (sess);
90 	    }
91 	}
92 
93 	if (rc == 0)
94 	    rc = ndmca_monitor_shutdown (sess);
95 	else
96 	    ndmca_monitor_shutdown (sess);
97 
98 	ndmca_media_tattle (sess);
99 
100 	return rc;
101 }
102 
103 int
ndmca_op_recover_files(struct ndm_session * sess)104 ndmca_op_recover_files (struct ndm_session *sess)
105 {
106 	struct ndm_control_agent *ca = sess->control_acb;
107 	int			rc;
108 
109 	ca->tape_mode = NDMP9_TAPE_READ_MODE;
110 	ca->mover_mode = NDMP9_MOVER_MODE_WRITE;
111 	ca->is_label_op = 0;
112 
113 	rc = ndmca_backreco_startup (sess);
114 	if (rc) return rc;
115 
116 	rc = ndmca_data_start_recover (sess);
117 	if (rc == 0) {
118 		rc = ndmca_monitor_startup (sess);
119 		if (rc == 0) {
120 			rc = ndmca_monitor_recover (sess);
121 		}
122 	}
123 
124 	if (rc == 0)
125 	    rc = ndmca_monitor_shutdown (sess);
126 	else
127 	    ndmca_monitor_shutdown (sess);
128 
129 	if (rc == 0) {
130 	    if (ca->recover_log_file_count > 0) {
131 		struct ndm_control_agent *ca = sess->control_acb;
132 		int		    n_nlist = ca->job.nlist_tab.n_nlist;
133 
134 		ndmalogf (sess, 0, 0,
135 			  "LOG_FILE messages: %d OK, %d ERROR, total %d of %d",
136 			  ca->recover_log_file_ok,
137 			  ca->recover_log_file_error,
138 			  ca->recover_log_file_count,
139 			  n_nlist);
140 	   if (ca->recover_log_file_ok < n_nlist) {
141 		ndmalogf (sess, 0, 0,
142 			  "LOG_FILE messages: WARNING OK(%d) < (%d)Expected in namelist",
143 			  ca->recover_log_file_ok, n_nlist);
144 		}
145 		if (ca->recover_log_file_ok < ca->recover_log_file_count) {
146 		    rc = 1;
147 		}
148 	    } else {
149 		ndmalogf (sess, 0, 1,
150 			  "DATA did not report any LOG_FILE messages");
151 	    }
152 	}
153 
154 	if(!ca->job.tape_tcp)
155 		ndmca_media_tattle (sess);
156 
157 	return rc;
158 }
159 
160 int
ndmca_op_recover_fh(struct ndm_session * sess)161 ndmca_op_recover_fh (struct ndm_session *sess)
162 {
163 	struct ndm_control_agent *ca = sess->control_acb;
164 	int			rc;
165 
166 	ca->tape_mode = NDMP9_TAPE_READ_MODE;
167 	ca->mover_mode = NDMP9_MOVER_MODE_WRITE;
168 	ca->is_label_op = 0;
169 
170 	rc = ndmca_backreco_startup (sess);
171 	if (rc) return rc;
172 
173 	rc = ndmca_data_start_recover_filehist (sess);
174 	if (rc == 0) {
175 		rc = ndmca_monitor_startup (sess);
176 		if (rc == 0) {
177 			rc = ndmca_monitor_recover (sess);
178 		}
179 	}
180 
181 	if (rc == 0)
182 	    rc = ndmca_monitor_shutdown (sess);
183 	else
184 	    ndmca_monitor_shutdown (sess);
185 
186 	ndmca_media_tattle (sess);
187 
188 	return rc;
189 }
190 
ndmca_data_est(struct ndm_control_agent * ca)191 char *ndmca_data_est(struct ndm_control_agent *ca)
192 {
193     char *estb;
194     static char estb_buf[64];
195 
196     estb = 0;
197     if (ca->data_state.est_bytes_remain.valid &&
198 	(ca->data_state.est_bytes_remain.value >= 1024)) {
199 	snprintf(estb_buf,
200 		 sizeof (estb_buf),
201 		 " left %lldKB",
202 		 ca->data_state.est_bytes_remain.value/1024LL);
203 	estb = estb_buf;
204     }
205 
206     return estb;
207 }
208 
209 int
ndmca_monitor_backup(struct ndm_session * sess)210 ndmca_monitor_backup (struct ndm_session *sess)
211 {
212 	struct ndm_control_agent *ca = sess->control_acb;
213 	int			count;
214 	ndmp9_data_state	ds;
215 	ndmp9_mover_state	ms;
216 	char *estb;
217 
218 	if (ca->job.tape_tcp) {
219 		return ndmca_monitor_backup_tape_tcp(sess);
220 	}
221 
222 	ndmalogf (sess, 0, 3, "Monitoring backup");
223 
224    for (count = 0; count < 10; count++) {
225       /*
226        * check if job needs to be cancelled
227        */
228       if (sess->jobcontrol_cbs && sess->jobcontrol_cbs->is_job_canceled) {
229          if (sess->jobcontrol_cbs->is_job_canceled(sess)) {
230 			   ndmalogf (sess, 0, 0, "Job was cancelled, cancelling NDMP operation");
231             return -1;
232          }
233       }
234 
235       ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10);
236       if (ndmca_monitor_get_states(sess) < 0)
237          break;
238 
239 #if 0
240 		if (count > 2)
241 			ndmca_mon_show_states(sess);
242 #endif
243 
244 		ds = ca->data_state.state;
245 		ms = ca->mover_state.state;
246 
247 		estb = ndmca_data_est(ca);
248 
249 		ndmalogf (sess, 0, 1,
250 			  "DATA: bytes %lldKB%s  MOVER: written %lldKB record %d",
251 			  ca->data_state.bytes_processed/1024LL,
252 			  estb ? estb : "",
253 			  ca->mover_state.bytes_moved/1024LL,
254 			  ca->mover_state.record_num);
255 
256 		ca->job.bytes_written = ca->data_state.bytes_processed;
257 
258 		if (ds == NDMP9_DATA_STATE_ACTIVE
259 		 && ms == NDMP9_MOVER_STATE_ACTIVE) {
260 			count = 0;
261 			continue;
262 		}
263 
264 		/*
265 		 * Check MOVER for needed tape change during DATA_FLOW_TO_TAPE.
266 		 * Have to do this before checking DATA. Even if DATA halted,
267 		 * MOVER may be holding unwritten data. Have to perform
268 		 * the tape change.
269 		 */
270 		if (ms == NDMP9_MOVER_STATE_PAUSED) {
271 			ndmp9_mover_pause_reason	pr;
272 
273 			pr = ca->mover_state.pause_reason;
274 
275 			if (!ca->pending_notify_mover_paused) {
276 				/* count=count */
277 				continue;		/* wait for notice */
278 			}
279 
280 			ca->pending_notify_mover_paused = 0;
281 
282 			ndmalogf (sess, 0, 3, "Mover paused, reason=%s",
283 					ndmp9_mover_pause_reason_to_str (pr));
284 
285 			/* backups are different than recoverys... When
286                          * we reach the end of a window, we signal EOW
287                          * except in V2 where we signal EOF. EOM occurs
288 			 * at EOT (or EOF does).
289 			 * This is based on reading comments in the email
290 			 * archives...
291 			 */
292 			if ((pr == NDMP9_MOVER_PAUSE_EOM) ||
293 			    (pr == NDMP9_MOVER_PAUSE_EOW)) {
294 				if (ndmca_monitor_load_next(sess) == 0) {
295 					/* count=count */
296 					continue;	/* Happy */
297 				}
298 				/* Something went wrong with tape change. */
299 			} else if ((sess->plumb.tape->protocol_version <= 2) &&
300 				   pr == NDMP9_MOVER_PAUSE_EOF) {
301 				if (ndmca_monitor_load_next(sess) == 0) {
302 					/* count=count */
303 					continue;	/* Happy */
304 				}
305 				/* Something went wrong with tape change. */
306 			} else {
307 				/* All other pause reasons
308 				 * are critically bogus. */
309 
310 			}
311 			ndmalogf (sess, 0, 0,
312 				"Operation paused w/o remedy, cancelling");
313 			ndmca_mover_abort (sess);
314 			return -1;
315 		}
316 
317 		/*
318 		 * If DATA has halted, the show is over.
319 		 */
320 		if (ds == NDMP9_DATA_STATE_HALTED) {
321 			if (ms != NDMP9_MOVER_STATE_HALTED) {
322 				ndmalogf (sess, 0, 3,
323 					"DATA halted, MOVER active");
324 				/*
325 				 * MOVER still occupied. It might be a
326 				 * heartbeat away from asking for another
327 				 * tape. Give it a chance.
328 				 */
329 				continue;
330 			}
331 
332 			ndmalogf (sess, 0, 2, "Operation done, cleaning up");
333 
334 			ndmca_monitor_get_post_backup_env (sess);
335 
336 			return 0;
337 		}
338 #if 1
339 		if (ms == NDMP9_MOVER_STATE_HALTED) {
340 			if (ds == NDMP9_DATA_STATE_ACTIVE) {
341 				ndmalogf (sess, 0, 3,
342 					"MOVER halted, DATA active");
343 				/*
344 				 * DATA still occupied.
345 				 */
346 				continue;
347 			}
348 		}
349 #endif
350 
351 		if (ms != NDMP9_MOVER_STATE_ACTIVE && count == 0) {
352 			/* Not active. Not paused. Something wrong */
353 			ndmalogf (sess, 0, 0,
354 				"Operation in unreasonable state, cancelling");
355 			return -1;
356 		}
357 	}
358 
359 	ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling");
360 	return -1;
361 }
362 
363 int
ndmca_monitor_backup_tape_tcp(struct ndm_session * sess)364 ndmca_monitor_backup_tape_tcp (struct ndm_session *sess)
365 {
366 	struct ndm_control_agent *ca = sess->control_acb;
367 	int			count;
368 	ndmp9_data_state	ds;
369 	char *estb;
370 
371 	ndmalogf (sess, 0, 3, "Monitoring backup");
372 
373 	for (count = 0; count < 10; count++) {
374 		ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10);
375 		if (ndmca_monitor_get_states(sess) < 0)
376 		    break;
377 
378 #if 0
379 		if (count > 2)
380 			ndmca_mon_show_states(sess);
381 #endif
382 
383 		ds = ca->data_state.state;
384 
385 		estb = ndmca_data_est(ca);
386 
387 		ndmalogf (sess, 0, 1,
388 			  "DATA: bytes %lldKB%s",
389 			  ca->data_state.bytes_processed/1024LL,
390 			  estb ? estb : "");
391 
392 		ca->job.bytes_written = ca->data_state.bytes_processed;
393 
394 		if (ds == NDMP9_DATA_STATE_ACTIVE) {
395 			count = 0;
396 			continue;
397 		}
398 
399 		/*
400 		 * If DATA has halted, the show is over.
401 		 */
402 		if (ds == NDMP9_DATA_STATE_HALTED) {
403 			ndmalogf (sess, 0, 2, "Operation done, cleaning up");
404 
405 			ndmca_monitor_get_post_backup_env (sess);
406 
407 			return 0;
408 		}
409 	}
410 
411 	ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling");
412 	return -1;
413 }
414 
415 int
ndmca_monitor_get_post_backup_env(struct ndm_session * sess)416 ndmca_monitor_get_post_backup_env (struct ndm_session *sess)
417 {
418 	struct ndm_control_agent *ca = sess->control_acb;
419 	struct ndmlog *		ixlog = &ca->job.index_log;
420 	struct ndm_env_entry *	entry;
421 	int			rc;
422 
423 	rc = ndmca_data_get_env (sess);
424 	if (rc && ca->data_state.error == NDMP9_ILLEGAL_STATE_ERR) {
425 		ndmalogf (sess, 0, 2, "fetch post backup env failed");
426 		return 0;
427 	}
428 	if (rc) {
429 		ndmalogf (sess, 0, 0, "fetch post backup env failed");
430 		return -1;
431 	}
432 
433 	/*
434 	 * Only print the data when a deliver function was defined.
435 	 */
436 	if (ixlog->deliver) {
437 		for (entry = ca->job.result_env_tab.head; entry; entry = entry->next) {
438 			ndmlogf (ixlog, "DE", 0, "%s=%s", entry->pval.name, entry->pval.value);
439 		}
440 	}
441 
442 	return 0;
443 }
444 
445 int
ndmca_monitor_recover(struct ndm_session * sess)446 ndmca_monitor_recover (struct ndm_session *sess)
447 {
448 	struct ndm_control_agent *ca = sess->control_acb;
449 	int			count, rc;
450 	ndmp9_data_state	ds;
451 	ndmp9_mover_state	ms;
452 	char *estb;
453 	int last_state_print = 0;
454 
455 	if (ca->job.tape_tcp) {
456 		return (ndmca_monitor_recover_tape_tcp(sess));
457 	}
458 
459 	ndmalogf (sess, 0, 3, "Monitoring recover");
460 
461 	for (count = 0; count < 10; count++) {
462 		if (ca->pending_notify_data_read) {
463 			ca->pending_notify_data_read = 0;
464 
465 			rc = ndmca_mover_read (sess,
466 				ca->last_notify_data_read.offset,
467 				ca->last_notify_data_read.length);
468 			if (rc) {
469 				ndmalogf (sess, 0, 0, "data-read failed");
470 				return -1;
471 			}
472 			if (count < 5)
473 				continue;
474 		}
475 
476 		ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10);
477 
478 		if (ndmca_monitor_get_states(sess) < 0)
479 		    break;
480 
481 #if 0
482 		if (count > 2)
483 			ndmca_mon_show_states(sess);
484 #endif
485 
486 		ds = ca->data_state.state;
487 		ms = ca->mover_state.state;
488 
489 		estb = ndmca_data_est(ca);
490 
491 		if ((ds != NDMP9_DATA_STATE_ACTIVE) ||
492 		    (ms != NDMP9_MOVER_STATE_ACTIVE) ||
493 		    ((time(0) - last_state_print) >= 5)) {
494 
495 		    ndmalogf (sess, 0, 1,
496 			      "DATA: bytes %lldKB%s  MOVER: read %lldKB record %d",
497 			      ca->data_state.bytes_processed/1024LL,
498 			      estb ? estb : "",
499 			      ca->mover_state.bytes_moved/1024LL,
500 			      ca->mover_state.record_num);
501 		    last_state_print = time(0);
502 		}
503 
504 		ca->job.bytes_read = ca->data_state.bytes_processed;
505 
506 		if (ds == NDMP9_DATA_STATE_ACTIVE
507 		 && ms == NDMP9_MOVER_STATE_ACTIVE) {
508 			count = 0;
509 			continue;
510 		}
511 
512 		/*
513 		 * Check MOVER for needed tape change during DATA_FLOW_TO_TAPE.
514 		 * Have to do this before checking DATA. Even if DATA halted,
515 		 * MOVER may be holding unwritten data. Have to perform
516 		 * the tape change.
517 		 */
518 		if (ms == NDMP9_MOVER_STATE_PAUSED) {
519 			ndmp9_mover_pause_reason	pr;
520 
521 			pr = ca->mover_state.pause_reason;
522 
523 			if (!ca->pending_notify_mover_paused) {
524 				/* count=count */
525 				continue;		/* wait for notice */
526 			}
527 
528 			ca->pending_notify_mover_paused = 0;
529 
530 			ndmalogf (sess, 0, 3, "Mover paused, reason=%s",
531 					ndmp9_mover_pause_reason_to_str (pr));
532 
533 			if (((pr == NDMP9_MOVER_PAUSE_EOF) ||
534 			     (pr == NDMP9_MOVER_PAUSE_SEEK))
535 			    && (ca->cur_media_ix == ca->job.media_tab.n_media)) {
536 				/*
537 				 * Last tape consumed by tape agent.
538 				 * The DATA agent may be just shy
539 				 * of done, but there is no way for
540 				 * us to tell. So, close the
541 				 * image stream from the TAPE
542 				 * agent side, thus indicating
543 				 * EOF to the DATA agent.
544 				 */
545 				ndmalogf (sess, 0, 2, "End of tapes");
546 				ndmca_mover_close (sess);
547 				/* count=count */
548 				continue;
549 			}
550 
551 			if (pr == NDMP9_MOVER_PAUSE_EOM
552 			 || pr == NDMP9_MOVER_PAUSE_EOF) {
553 				if (ndmca_monitor_load_next(sess) == 0) {
554 					/* count=count */
555 					continue;	/* Happy */
556 				}
557 				/* Something went wrong with tape change. */
558 			} else if (pr == NDMP9_MOVER_PAUSE_SEEK) {
559 				if (ndmca_monitor_seek_tape(sess) == 0) {
560 					/* count=count */
561 					continue;	/* Happy */
562 				}
563 				/* Something went wrong with tape change. */
564 			} else {
565 				/* All other pause reasons
566 				 * are critically bogus. */
567 			}
568 			ndmalogf (sess, 0, 0,
569 				"Operation paused w/o remedy, cancelling");
570 			ndmca_mover_abort (sess);
571 			return -1;
572 		}
573 
574 		/*
575 		 * If DATA has halted, the show is over.
576 		 */
577 		if (ds == NDMP9_DATA_STATE_HALTED) {
578 			if (ms != NDMP9_MOVER_STATE_HALTED) {
579 				ndmalogf (sess, 0, 3,
580 					"DATA halted, MOVER active");
581 				/*
582 				 * MOVER still occupied. It might
583 				 * figure it out. Then again, it might
584 				 * be awaiting a MOVER_READ. The NDMP
585 				 * design does not provide a state
586 				 * for awaiting MOVER_READ, so we have
587 				 * to guess.
588 				 */
589 				if (count > 0) {
590 					ndmca_mover_close(sess);
591 				}
592 				continue;
593 			}
594 
595 			ndmalogf (sess, 0, 2, "Operation done, cleaning up");
596 
597 			return 0;
598 		}
599 
600 		if (ms != NDMP9_MOVER_STATE_ACTIVE && count == 0) {
601 			/* Not active. Not paused. Something wrong */
602 			ndmalogf (sess, 0, 0,
603 				"Operation in unreasonable state, cancelling");
604 			return -1;
605 		}
606 	}
607 
608 	ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling");
609 	return -1;
610 }
611 
612 
613 int
ndmca_monitor_recover_tape_tcp(struct ndm_session * sess)614 ndmca_monitor_recover_tape_tcp (struct ndm_session *sess)
615 {
616 	struct ndm_control_agent *ca = sess->control_acb;
617 	int			count;
618 	ndmp9_data_state	ds;
619 	char *estb;
620 	int last_state_print = 0;
621 
622 	ndmalogf (sess, 0, 3, "Monitoring recover");
623 
624 	for (count = 0; count < 10; count++) {
625 
626 		ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10);
627 
628 		if (ndmca_monitor_get_states(sess) < 0)
629 		    break;
630 
631 #if 0
632 		if (count > 2)
633 			ndmca_mon_show_states(sess);
634 #endif
635 
636 		ds = ca->data_state.state;
637 
638 		estb = ndmca_data_est(ca);
639 
640 		if ((ds != NDMP9_DATA_STATE_ACTIVE) ||
641 		    ((time(0) - last_state_print) >= 5)) {
642 
643 		    ndmalogf (sess, 0, 1,
644 			      "DATA: bytes %lldKB%s  MOVER: read %lldKB record %d",
645 			      ca->data_state.bytes_processed/1024LL,
646 			      estb ? estb : "",
647 			      ca->mover_state.bytes_moved/1024LL,
648 			      ca->mover_state.record_num);
649 		    last_state_print = time(0);
650 		}
651 
652 		ca->job.bytes_read = ca->data_state.bytes_processed;
653 
654 		if (ds == NDMP9_DATA_STATE_ACTIVE) {
655 			count = 0;
656 			continue;
657 		}
658 
659 		/*
660 		 * If DATA has halted, the show is over.
661 		 */
662 		if (ds == NDMP9_DATA_STATE_HALTED) {
663 			ndmalogf (sess, 0, 2, "Operation done, cleaning up");
664 
665 			ndmca_monitor_get_post_backup_env (sess);
666 
667 			return 0;
668 		}
669 
670 	}
671 
672 	ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling");
673 	return -1;
674 }
675 
676 
677 int
ndmca_backreco_startup(struct ndm_session * sess)678 ndmca_backreco_startup (struct ndm_session *sess)
679 {
680 	struct ndm_control_agent *ca = sess->control_acb;
681 	int			rc = 0;
682 
683 	if (!ca->job.tape_tcp)
684 		rc = ndmca_op_robot_startup (sess, 1);
685 	if (rc) return rc;
686 
687 	rc = ndmca_connect_data_agent(sess);
688 	if (rc) {
689 		ndmconn_destruct (sess->plumb.data);
690 		sess->plumb.data = NULL;
691 		return rc;
692 	}
693 
694 	if (ca->job.tape_tcp) {
695 		return 0;
696 	}
697 
698 	rc = ndmca_connect_tape_agent(sess);
699 	if (rc) {
700 		ndmconn_destruct (sess->plumb.tape);
701 		sess->plumb.tape = NULL;
702 		return rc;
703 	}
704 
705 	rc = ndmca_mover_set_record_size (sess);
706 	if (rc) return rc;
707 
708 	rc = ndmca_media_load_first (sess);
709 	if (rc) return rc;
710 
711 	ndmca_media_calculate_offsets (sess);
712 
713 	if (sess->control_acb->swap_connect &&
714 	    (sess->plumb.tape->protocol_version >= 3)) {
715 	    if (sess->plumb.tape->protocol_version < 4) {
716 		rc = ndmca_data_listen (sess);
717 		if (rc) return rc;
718 
719 		rc = ndmca_media_set_window_current (sess);
720 		if (rc) return rc;
721 	    } else {
722 		rc = ndmca_media_set_window_current (sess);
723 		if (rc) return rc;
724 
725 		rc = ndmca_data_listen (sess);
726 		if (rc) return rc;
727 	    }
728 	} else {
729 	    if (sess->plumb.tape->protocol_version < 4) {
730 		rc = ndmca_mover_listen (sess);
731 		if (rc) return rc;
732 
733 		rc = ndmca_media_set_window_current (sess);
734 		if (rc) return rc;
735 	    } else {
736 		rc = ndmca_media_set_window_current (sess);
737 		if (rc) return rc;
738 
739 		rc = ndmca_mover_listen (sess);
740 		if (rc) return rc;
741 	    }
742 	}
743 
744 	return 0;
745 }
746 
747 int
ndmca_monitor_startup(struct ndm_session * sess)748 ndmca_monitor_startup (struct ndm_session *sess)
749 {
750 	struct ndm_control_agent *ca = sess->control_acb;
751 	ndmp9_data_state	ds;
752 	ndmp9_mover_state	ms;
753 	int			count;
754 
755 	ndmalogf (sess, 0, 3, "Waiting for operation to start");
756 
757 	if (ca->job.tape_tcp)
758 		return 0;
759 
760 	for (count = 0; count < 10; count++) {
761 		if (ndmca_monitor_get_states (sess) < 0)
762 		    break;
763 
764 		ds = ca->data_state.state;
765 		if (!ca->job.tape_tcp)
766 			ms = ca->mover_state.state;
767 		else
768 			ms = NDMP9_MOVER_STATE_ACTIVE;
769 
770 		if (ds == NDMP9_DATA_STATE_ACTIVE
771 		 && ms == NDMP9_MOVER_STATE_ACTIVE) {
772 			ndmalogf (sess, 0, 1, "Operation started");
773 			return 0;
774 		}
775 
776 		if (ds == NDMP9_DATA_STATE_HALTED
777 		    && ms == NDMP9_MOVER_STATE_HALTED) {
778 			/* operation finished immediately */
779 			return 0;
780 		}
781 
782 		if (ds != NDMP9_DATA_STATE_IDLE
783 		 && ms != NDMP9_MOVER_STATE_IDLE
784 		 && ms != NDMP9_MOVER_STATE_LISTEN) {
785 			ndmalogf (sess, 0, 1,
786 				  "Operation started in unusual fashion");
787 			return 0;
788 		}
789 
790 		ndmca_mon_wait_for_something (sess, 2);
791 	}
792 
793 	ndmalogf (sess, 0, 0, "Operation failed to start");
794 	return -1;
795 }
796 
797 /*
798  * Just make sure things get finished
799  */
800 int
ndmca_monitor_shutdown(struct ndm_session * sess)801 ndmca_monitor_shutdown (struct ndm_session *sess)
802 {
803 	struct ndm_control_agent *ca = sess->control_acb;
804 	ndmp9_data_state	ds;
805 	ndmp9_data_halt_reason	dhr;
806 	ndmp9_mover_state	ms;
807 	ndmp9_mover_halt_reason	mhr;
808 	int			count;
809 	int			finish;
810 
811 	if (ca->job.tape_tcp) {
812 		return ndmca_monitor_shutdown_tape_tcp(sess);
813 	}
814 	ndmalogf (sess, 0, 3, "Waiting for operation to halt");
815 
816 	for (count = 0; count < 10; count++) {
817 		ndmca_mon_wait_for_something (sess, 2);
818 
819 		if (ndmca_monitor_get_states (sess) < 0)
820 		    break;
821 
822 #if 0
823 		if (count > 2)
824 			ndmca_mon_show_states(sess);
825 #endif
826 
827 		ds = ca->data_state.state;
828 		ms = ca->mover_state.state;
829 
830 		if (ds == NDMP9_DATA_STATE_HALTED
831 		 && ms == NDMP9_MOVER_STATE_HALTED) {
832 		        dhr = ca->data_state.halt_reason;
833 			mhr = ca->mover_state.halt_reason;
834 			break;
835 		}
836 
837 		if (count > 2) {
838 			if (ds != NDMP9_DATA_STATE_HALTED)
839 				ndmca_data_abort(sess);
840 			if (ms != NDMP9_MOVER_STATE_HALTED)
841 				ndmca_mover_abort(sess);
842 		}
843 	}
844 
845 	if (ca->tape_state.error == NDMP9_NO_ERR) {
846 		ndmca_monitor_unload_last_tape (sess);
847 	}
848 
849 	if (count >= 10) {
850 		ndmalogf (sess, 0, 0,
851 			"Operation did not halt, something wrong");
852 	}
853 
854 	ndmalogf (sess, 0, 2, "Operation halted, stopping");
855 
856 	ds = ca->data_state.state;
857 	ms = ca->mover_state.state;
858 	dhr = ca->data_state.halt_reason;
859 	mhr = ca->mover_state.halt_reason;
860 
861 	if ((ds == NDMP9_DATA_STATE_HALTED)
862 	    && (ms == NDMP9_MOVER_STATE_HALTED)) {
863 	    if ((dhr == NDMP9_DATA_HALT_SUCCESSFUL) &&
864 		(mhr == NDMP9_MOVER_HALT_CONNECT_CLOSED)) {
865 		/* Successful operation */
866 		ndmalogf (sess, 0, 0, "Operation ended OKAY");
867 		finish = 0;
868 	    } else {
869 		/* Questionable success */
870 		ndmalogf (sess, 0, 0, "Operation ended questionably");
871 		finish = 1;
872 	    }
873 	} else {
874 	    ndmalogf (sess, 0, 0, "Operation ended in failure");
875 	    finish = -1;
876 	}
877 
878 	ndmca_data_stop (sess);
879 	ndmca_mover_stop (sess);
880 
881 	for (count = 0; count < 10; count++) {
882 		if (ndmca_monitor_get_states(sess) < 0)
883 		    break;
884 
885 #if 0
886 		if (count > 2)
887 			ndmca_mon_show_states(sess);
888 #endif
889 
890 		ds = ca->data_state.state;
891 		ms = ca->mover_state.state;
892 
893 		if (ds == NDMP9_DATA_STATE_IDLE
894 		 && ms == NDMP9_MOVER_STATE_IDLE) {
895 			break;
896 		}
897 	}
898 
899 	if (count >= 10) {
900 		ndmalogf (sess, 0, 0,
901 			"Operation did not stop, something wrong");
902 		return -1;
903 	}
904 
905 	ndmca_connect_close (sess);
906 
907 	return finish;
908 }
909 
910 int
ndmca_monitor_shutdown_tape_tcp(struct ndm_session * sess)911 ndmca_monitor_shutdown_tape_tcp (struct ndm_session *sess)
912 {
913 	struct ndm_control_agent *ca = sess->control_acb;
914 	ndmp9_data_state	ds;
915 	ndmp9_data_halt_reason	dhr;
916 	int			count;
917 	int			finish;
918 
919 	ndmalogf (sess, 0, 3, "Waiting for operation to halt");
920 
921 	for (count = 0; count < 10; count++) {
922 		ndmca_mon_wait_for_something (sess, 2);
923 
924 		if (ndmca_monitor_get_states (sess) < 0)
925 		    break;
926 
927 #if 0
928 		if (count > 2)
929 			ndmca_mon_show_states(sess);
930 #endif
931 
932 		ds = ca->data_state.state;
933 
934 		if (ds == NDMP9_DATA_STATE_HALTED) {
935 		        dhr = ca->data_state.halt_reason;
936 			break;
937 		}
938 
939 		if (count > 2) {
940 			if (ds != NDMP9_DATA_STATE_HALTED)
941 				ndmca_data_abort(sess);
942 		}
943 	}
944 
945 	if (count >= 10) {
946 		ndmalogf (sess, 0, 0,
947 			"Operation did not halt, something wrong");
948 	}
949 
950 	ndmalogf (sess, 0, 2, "Operation halted, stopping");
951 
952 	ds = ca->data_state.state;
953 	dhr = ca->data_state.halt_reason;
954 
955 	if (ds == NDMP9_DATA_STATE_HALTED) {
956 	    if (dhr == NDMP9_DATA_HALT_SUCCESSFUL) {
957 		/* Successful operation */
958 		ndmalogf (sess, 0, 0, "Operation ended OKAY");
959 		finish = 0;
960 	    } else {
961 		/* Questionable success */
962 		ndmalogf (sess, 0, 0, "Operation ended questionably");
963 		finish = 1;
964 	    }
965 	} else {
966 	    ndmalogf (sess, 0, 0, "Operation ended in failure");
967 	    finish = -1;
968 	}
969 
970 	ndmca_data_stop (sess);
971 
972 	for (count = 0; count < 10; count++) {
973 		if (ndmca_monitor_get_states(sess) < 0)
974 		    break;
975 
976 #if 0
977 		if (count > 2)
978 			ndmca_mon_show_states(sess);
979 #endif
980 
981 		ds = ca->data_state.state;
982 
983 		if (ds == NDMP9_DATA_STATE_IDLE) {
984 			break;
985 		}
986 	}
987 
988 	if (count >= 10) {
989 		ndmalogf (sess, 0, 0,
990 			"Operation did not stop, something wrong");
991 		return -1;
992 	}
993 
994 	return finish;
995 }
996 
997 int
ndmca_monitor_get_states(struct ndm_session * sess)998 ndmca_monitor_get_states (struct ndm_session *sess)
999 {
1000 	struct ndm_control_agent *ca = sess->control_acb;
1001 	int rc = 0;
1002 
1003 	if (ndmca_data_get_state (sess) < 0)
1004 	    rc = -1;
1005 	if (!ca->job.tape_tcp) {
1006 	    if (ndmca_mover_get_state (sess) < 0)
1007 		rc = -1;
1008 	    ndmca_tape_get_state_no_tattle (sess);
1009 	}
1010 
1011 	return rc;
1012 }
1013 
1014 int
ndmca_monitor_load_next(struct ndm_session * sess)1015 ndmca_monitor_load_next (struct ndm_session *sess)
1016 {
1017 	struct ndm_control_agent *ca = sess->control_acb;
1018 	int			rc;
1019 
1020 	ndmalogf (sess, 0, 1, "Operation requires next tape");
1021 
1022 	ndmca_media_capture_mover_window (sess);
1023 	ndmca_media_calculate_offsets (sess);
1024 
1025 	if (ca->tape_mode == NDMP9_TAPE_RDWR_MODE) {
1026 	    if (ca->mover_state.pause_reason != NDMP9_MOVER_PAUSE_EOM)
1027 		ndmca_media_write_filemarks (sess);
1028 	    else
1029 		ndmalogf (sess, 0, 1, "At EOM, not writing filemarks");
1030 	}
1031 
1032 	rc = ndmca_media_unload_current(sess);
1033 	if (rc) return rc;
1034 
1035 	rc = ndmca_media_load_next(sess);
1036 	if (rc) return rc;
1037 
1038 	rc = ndmca_media_set_window_current (sess);
1039 	if (rc) return rc;
1040 
1041 	rc = ndmca_mover_continue(sess);
1042 	if (rc) return rc;
1043 
1044 	ndmalogf (sess, 0, 1, "Operation resuming");
1045 
1046 	return 0;
1047 }
1048 
1049 /* VERY VERY HARD */
1050 int
ndmca_monitor_seek_tape(struct ndm_session * sess)1051 ndmca_monitor_seek_tape (struct ndm_session *sess)
1052 {
1053 	struct ndm_control_agent *ca = sess->control_acb;
1054 	int			rc;
1055 	uint64_t		pos;
1056 
1057 	pos = ca->last_notify_mover_paused.seek_position;
1058 
1059 	ndmalogf (sess, 0, 1, "Operation requires a different tape");
1060 
1061 /*	ndmca_media_capture_mover_window (sess);	// !!! */
1062 	ndmca_media_calculate_offsets (sess);
1063 
1064 	rc = ndmca_media_unload_current(sess);
1065 	if (rc) return rc;
1066 
1067 	rc = ndmca_media_load_seek (sess, pos);
1068 	if (rc) return rc;
1069 
1070 	rc = ndmca_media_set_window_current (sess);
1071 	if (rc) return rc;
1072 
1073 	rc = ndmca_mover_continue(sess);
1074 	if (rc) return rc;
1075 
1076 	ndmalogf (sess, 0, 1, "Operation resuming");
1077 
1078 	return 0;
1079 }
1080 
1081 int
ndmca_monitor_unload_last_tape(struct ndm_session * sess)1082 ndmca_monitor_unload_last_tape (struct ndm_session *sess)
1083 {
1084 	struct ndm_control_agent *ca = sess->control_acb;
1085 	int			rc;
1086 
1087 	if (!ca->media_is_loaded)
1088 		return 0;
1089 
1090 	ndmca_media_capture_mover_window (sess);
1091 	ndmca_media_calculate_offsets (sess);
1092 
1093 	if (ca->tape_mode == NDMP9_TAPE_RDWR_MODE) {
1094 		ndmca_media_write_filemarks (sess);
1095 	}
1096 
1097 	rc = ndmca_media_unload_current(sess);
1098 	if (rc) return rc;
1099 
1100 	return 0;
1101 }
1102 
1103 int
ndmca_mon_wait_for_something(struct ndm_session * sess,int max_delay_secs)1104 ndmca_mon_wait_for_something (struct ndm_session *sess, int max_delay_secs)
1105 {
1106 	struct ndm_control_agent *ca = sess->control_acb;
1107 	int			delta, notices;
1108 	int			time_ref = time(0) + max_delay_secs;
1109 
1110 	ndmalogf (sess, 0, 5, "mon_wait_for_something() entered");
1111 
1112 	for (;;) {
1113 		delta = time_ref - time(0);
1114 		if (delta <= 0)
1115 			break;
1116 
1117 		notices = 0;
1118 		if (ca->pending_notify_data_read) {
1119 			/* leave visible */
1120 			notices++;
1121 		}
1122 		if (ca->pending_notify_data_halted) {
1123 			/* just used to "wake up" */
1124 			ca->pending_notify_data_halted = 0;
1125 			notices++;
1126 		}
1127 		if (ca->pending_notify_mover_paused) {
1128 			/* leave visible */
1129 			notices++;
1130 		}
1131 		if (ca->pending_notify_mover_halted) {
1132 			/* just used to "wake up" */
1133 			ca->pending_notify_mover_halted = 0;
1134 			notices++;
1135 		}
1136 
1137 		ndma_session_quantum (sess, notices ? 0 : delta);
1138 
1139 		if (notices)
1140 			break;
1141 	}
1142 
1143 	ndmalogf (sess, 0, 5, "mon_wait_for_something() happened, resid=%d",
1144 			delta);
1145 
1146 	return 0;
1147 }
1148 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
1149