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