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