X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=ndmp-src%2Fndma_cops_backreco.c;fp=ndmp-src%2Fndma_cops_backreco.c;h=095c378454de3112812c886bd3fa37e60e9f63e0;hb=fd48f3e498442f0cbff5f3606c7c403d0566150e;hp=0000000000000000000000000000000000000000;hpb=96f35b20267e8b1a1c846d476f27fcd330e0b018;p=debian%2Famanda diff --git a/ndmp-src/ndma_cops_backreco.c b/ndmp-src/ndma_cops_backreco.c new file mode 100644 index 0000000..095c378 --- /dev/null +++ b/ndmp-src/ndma_cops_backreco.c @@ -0,0 +1,1103 @@ +/* + * Copyright (c) 1998,1999,2000 + * Traakan, Inc., Los Altos, CA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Project: NDMJOB + * Ident: $Id: $ + * + * Description: + * + */ + + +#include "ndmagents.h" +#include "util.h" + + +#ifndef NDMOS_OPTION_NO_CONTROL_AGENT + +int ndmca_monitor_backup_tape_tcp (struct ndm_session *sess); +int ndmca_monitor_recover_tape_tcp (struct ndm_session *sess); +int ndmca_monitor_shutdown_tape_tcp (struct ndm_session *sess); + +int +ndmca_op_create_backup (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int rc; + + ca->tape_mode = NDMP9_TAPE_RDWR_MODE; + ca->mover_mode = NDMP9_MOVER_MODE_READ; + ca->is_label_op = 0; + + rc = ndmca_backreco_startup (sess); + if (rc) return rc; + + rc = ndmca_data_start_backup (sess); + if (rc == 0) { + rc = ndmca_monitor_startup (sess); + if (rc == 0) { + rc = ndmca_monitor_backup (sess); + } + } + + if (rc == 0) + rc = ndmca_monitor_shutdown (sess); + else + ndmca_monitor_shutdown (sess); + + ndmca_media_tattle (sess); + + return rc; +} + +int +ndmca_op_recover_files (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int rc; + + ca->tape_mode = NDMP9_TAPE_READ_MODE; + ca->mover_mode = NDMP9_MOVER_MODE_WRITE; + ca->is_label_op = 0; + + rc = ndmca_backreco_startup (sess); + if (rc) return rc; + + rc = ndmca_data_start_recover (sess); + if (rc == 0) { + rc = ndmca_monitor_startup (sess); + if (rc == 0) { + rc = ndmca_monitor_recover (sess); + } + } + + if (rc == 0) + rc = ndmca_monitor_shutdown (sess); + else + ndmca_monitor_shutdown (sess); + + if (rc == 0) { + if (ca->recover_log_file_count > 0) { + struct ndm_control_agent *ca = &sess->control_acb; + int n_nlist = ca->job.nlist_tab.n_nlist; + + ndmalogf (sess, 0, 0, + "LOG_FILE messages: %d OK, %d ERROR, total %d of %d", + ca->recover_log_file_ok, + ca->recover_log_file_error, + ca->recover_log_file_count, + n_nlist); + if (ca->recover_log_file_ok < n_nlist) { + rc = 1; + } + } else { + ndmalogf (sess, 0, 1, + "DATA did not report any LOG_FILE messages"); + } + } + + if(!ca->job.tape_tcp) + ndmca_media_tattle (sess); + + return rc; +} + +int +ndmca_op_recover_fh (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int rc; + + ca->tape_mode = NDMP9_TAPE_READ_MODE; + ca->mover_mode = NDMP9_MOVER_MODE_WRITE; + ca->is_label_op = 0; + + rc = ndmca_backreco_startup (sess); + if (rc) return rc; + + rc = ndmca_data_start_recover_filehist (sess); + if (rc == 0) { + rc = ndmca_monitor_startup (sess); + if (rc == 0) { + rc = ndmca_monitor_recover (sess); + } + } + + if (rc == 0) + rc = ndmca_monitor_shutdown (sess); + else + ndmca_monitor_shutdown (sess); + + ndmca_media_tattle (sess); + + return rc; +} + +char *ndmca_data_est(struct ndm_control_agent *ca) +{ + char *estb; + static char estb_buf[64]; + + estb = 0; + if (ca->data_state.est_bytes_remain.valid && + (ca->data_state.est_bytes_remain.value >= 1024)) { + snprintf(estb_buf, + sizeof (estb_buf), + " left %lldKB", + ca->data_state.est_bytes_remain.value/1024LL); + estb = estb_buf; + } + + return estb; +} + +int +ndmca_monitor_backup (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int count; + ndmp9_data_state ds; + ndmp9_mover_state ms; + char *estb; + + if (ca->job.tape_tcp) { + return ndmca_monitor_backup_tape_tcp(sess); + } + + ndmalogf (sess, 0, 3, "Monitoring backup"); + + for (count = 0; count < 10; count++) { + ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10); + if (ndmca_monitor_get_states(sess) < 0) + break; + +#if 0 + if (count > 2) + ndmca_mon_show_states(sess); +#endif + + ds = ca->data_state.state; + ms = ca->mover_state.state; + + estb = ndmca_data_est(ca); + + ndmalogf (sess, 0, 1, + "DATA: bytes %lldKB%s MOVER: written %lldKB record %d", + ca->data_state.bytes_processed/1024LL, + estb ? estb : "", + ca->mover_state.bytes_moved/1024LL, + ca->mover_state.record_num); + + if (ds == NDMP9_DATA_STATE_ACTIVE + && ms == NDMP9_MOVER_STATE_ACTIVE) { + count = 0; + continue; + } + + /* + * Check MOVER for needed tape change during DATA_FLOW_TO_TAPE. + * Have to do this before checking DATA. Even if DATA halted, + * MOVER may be holding unwritten data. Have to perform + * the tape change. + */ + if (ms == NDMP9_MOVER_STATE_PAUSED) { + ndmp9_mover_pause_reason pr; + + pr = ca->mover_state.pause_reason; + + if (!ca->pending_notify_mover_paused) { + /* count=count */ + continue; /* wait for notice */ + } + + ca->pending_notify_mover_paused = 0; + + ndmalogf (sess, 0, 3, "Mover paused, reason=%s", + ndmp9_mover_pause_reason_to_str (pr)); + + /* backups are different then recoverys... When + * we reach the end of a window, we signal EOW + * except in V2 where we signal EOF. EOM occurs + * at EOT (or EOF does). + * This is based on reading comments in the email + * archives... + */ + if ((pr == NDMP9_MOVER_PAUSE_EOM) || + (pr == NDMP9_MOVER_PAUSE_EOW)) { + if (ndmca_monitor_load_next(sess) == 0) { + /* count=count */ + continue; /* Happy */ + } + /* Something went wrong with tape change. */ + } else if ((sess->plumb.tape->protocol_version <= 2) && + pr == NDMP9_MOVER_PAUSE_EOF) { + if (ndmca_monitor_load_next(sess) == 0) { + /* count=count */ + continue; /* Happy */ + } + /* Something went wrong with tape change. */ + } else { + /* All other pause reasons + * are critically bogus. */ + + } + ndmalogf (sess, 0, 0, + "Operation paused w/o remedy, cancelling"); + ndmca_mover_abort (sess); + return -1; + } + + /* + * If DATA has halted, the show is over. + */ + if (ds == NDMP9_DATA_STATE_HALTED) { + if (ms != NDMP9_MOVER_STATE_HALTED) { + ndmalogf (sess, 0, 3, + "DATA halted, MOVER active"); + /* + * MOVER still occupied. It might be a + * heartbeat away from asking for another + * tape. Give it a chance. + */ + continue; + } + + ndmalogf (sess, 0, 2, "Operation done, cleaning up"); + + ndmca_monitor_get_post_backup_env (sess); + + return 0; + } +#if 1 + if (ms == NDMP9_MOVER_STATE_HALTED) { + if (ds == NDMP9_DATA_STATE_ACTIVE) { + ndmalogf (sess, 0, 3, + "MOVER halted, DATA active"); + /* + * DATA still occupied. + */ + continue; + } + } +#endif + + if (ms != NDMP9_MOVER_STATE_ACTIVE && count == 0) { + /* Not active. Not paused. Something wrong */ + ndmalogf (sess, 0, 0, + "Operation in unreasonable state, cancelling"); + return -1; + } + } + + ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling"); + return -1; +} + +int +ndmca_monitor_backup_tape_tcp (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int count; + ndmp9_data_state ds; + char *estb; + struct ndmlog * ixlog = &ca->job.index_log; + char * pname = get_pname(); + + ndmalogf (sess, 0, 3, "Monitoring backup"); + + for (count = 0; count < 10; count++) { + ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10); + if (ndmca_monitor_get_states(sess) < 0) + break; + +#if 0 + if (count > 2) + ndmca_mon_show_states(sess); +#endif + + ds = ca->data_state.state; + + estb = ndmca_data_est(ca); + + ndmalogf (sess, 0, 1, + "DATA: bytes %lldKB%s", + ca->data_state.bytes_processed/1024LL, + estb ? estb : ""); + + if (strcmp(pname, "amndmjob") == 0) { + ndmlogf (ixlog, "DATA SIZE", 0, "%lldKB", + ca->data_state.bytes_processed/1024LL); + } + + if (ds == NDMP9_DATA_STATE_ACTIVE) { + count = 0; + continue; + } + + /* + * If DATA has halted, the show is over. + */ + if (ds == NDMP9_DATA_STATE_HALTED) { + ndmalogf (sess, 0, 2, "Operation done, cleaning up"); + + ndmca_monitor_get_post_backup_env (sess); + + return 0; + } + } + + ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling"); + return -1; +} + +int +ndmca_monitor_get_post_backup_env (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + struct ndmlog * ixlog = &ca->job.index_log; + int rc, i; + ndmp9_pval * pv; + + rc = ndmca_data_get_env (sess); + if (rc && ca->data_state.error == NDMP9_ILLEGAL_STATE_ERR) { + ndmalogf (sess, 0, 2, "fetch post backup env failed"); + return 0; + } + if (rc) { + ndmalogf (sess, 0, 0, "fetch post backup env failed"); + return -1; + } + + for (i = 0; i < ca->job.result_env_tab.n_env; i++) { + pv = &ca->job.result_env_tab.env[i]; + + ndmlogf (ixlog, "DE", 0, "%s=%s", pv->name, pv->value); + } + + return 0; +} + +int +ndmca_monitor_recover (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int count, rc; + ndmp9_data_state ds; + ndmp9_mover_state ms; + char *estb; + int last_state_print = 0; + + if (ca->job.tape_tcp) { + return (ndmca_monitor_recover_tape_tcp(sess)); + } + + ndmalogf (sess, 0, 3, "Monitoring recover"); + + for (count = 0; count < 10; count++) { + if (ca->pending_notify_data_read) { + ca->pending_notify_data_read = 0; + + rc = ndmca_mover_read (sess, + ca->last_notify_data_read.offset, + ca->last_notify_data_read.length); + if (rc) { + ndmalogf (sess, 0, 0, "data-read failed"); + return -1; + } + if (count < 5) + continue; + } + + ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10); + + if (ndmca_monitor_get_states(sess) < 0) + break; + +#if 0 + if (count > 2) + ndmca_mon_show_states(sess); +#endif + + ds = ca->data_state.state; + ms = ca->mover_state.state; + + estb = ndmca_data_est(ca); + + if ((ds != NDMP9_DATA_STATE_ACTIVE) || + (ms != NDMP9_MOVER_STATE_ACTIVE) || + ((time(0) - last_state_print) >= 5)) { + + ndmalogf (sess, 0, 1, + "DATA: bytes %lldKB%s MOVER: read %lldKB record %d", + ca->data_state.bytes_processed/1024LL, + estb ? estb : "", + ca->mover_state.bytes_moved/1024LL, + ca->mover_state.record_num); + last_state_print = time(0); + } + + if (ds == NDMP9_DATA_STATE_ACTIVE + && ms == NDMP9_MOVER_STATE_ACTIVE) { + count = 0; + continue; + } + + /* + * Check MOVER for needed tape change during DATA_FLOW_TO_TAPE. + * Have to do this before checking DATA. Even if DATA halted, + * MOVER may be holding unwritten data. Have to perform + * the tape change. + */ + if (ms == NDMP9_MOVER_STATE_PAUSED) { + ndmp9_mover_pause_reason pr; + + pr = ca->mover_state.pause_reason; + + if (!ca->pending_notify_mover_paused) { + /* count=count */ + continue; /* wait for notice */ + } + + ca->pending_notify_mover_paused = 0; + + ndmalogf (sess, 0, 3, "Mover paused, reason=%s", + ndmp9_mover_pause_reason_to_str (pr)); + + if (((pr == NDMP9_MOVER_PAUSE_EOF) || + (pr == NDMP9_MOVER_PAUSE_SEEK)) + && (ca->cur_media_ix+1 == ca->job.media_tab.n_media)) { + /* + * Last tape consumed by tape agent. + * The DATA agent may be just shy + * of done, but there is no way for + * us to tell. So, close the + * image stream from the TAPE + * agent side, thus indicating + * EOF to the DATA agent. + */ + ndmalogf (sess, 0, 2, "End of tapes"); + ndmca_mover_close (sess); + /* count=count */ + continue; + } + + if (pr == NDMP9_MOVER_PAUSE_EOM + || pr == NDMP9_MOVER_PAUSE_EOF) { + if (ndmca_monitor_load_next(sess) == 0) { + /* count=count */ + continue; /* Happy */ + } + /* Something went wrong with tape change. */ + } else if (pr == NDMP9_MOVER_PAUSE_SEEK) { + if (ndmca_monitor_seek_tape(sess) == 0) { + /* count=count */ + continue; /* Happy */ + } + /* Something went wrong with tape change. */ + } else { + /* All other pause reasons + * are critically bogus. */ + } + ndmalogf (sess, 0, 0, + "Operation paused w/o remedy, cancelling"); + ndmca_mover_abort (sess); + return -1; + } + + /* + * If DATA has halted, the show is over. + */ + if (ds == NDMP9_DATA_STATE_HALTED) { + if (ms != NDMP9_MOVER_STATE_HALTED) { + ndmalogf (sess, 0, 3, + "DATA halted, MOVER active"); + /* + * MOVER still occupied. It might + * figure it out. Then again, it might + * be awaiting a MOVER_READ. The NDMP + * design does not provide a state + * for awaiting MOVER_READ, so we have + * to guess. + */ + if (count > 0) { + ndmca_mover_close(sess); + } + continue; + } + + ndmalogf (sess, 0, 2, "Operation done, cleaning up"); + + ndmca_monitor_get_post_backup_env (sess); + + return 0; + } + + if (ms != NDMP9_MOVER_STATE_ACTIVE && count == 0) { + /* Not active. Not paused. Something wrong */ + ndmalogf (sess, 0, 0, + "Operation in unreasonable state, cancelling"); + return -1; + } + } + + ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling"); + return -1; +} + + +int +ndmca_monitor_recover_tape_tcp (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int count; + ndmp9_data_state ds; + char *estb; + int last_state_print = 0; + + ndmalogf (sess, 0, 3, "Monitoring recover"); + + for (count = 0; count < 10; count++) { + + ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10); + + if (ndmca_monitor_get_states(sess) < 0) + break; + +#if 0 + if (count > 2) + ndmca_mon_show_states(sess); +#endif + + ds = ca->data_state.state; + + estb = ndmca_data_est(ca); + + if ((ds != NDMP9_DATA_STATE_ACTIVE) || + ((time(0) - last_state_print) >= 5)) { + + ndmalogf (sess, 0, 1, + "DATA: bytes %lldKB%s MOVER: read %lldKB record %d", + ca->data_state.bytes_processed/1024LL, + estb ? estb : "", + ca->mover_state.bytes_moved/1024LL, + ca->mover_state.record_num); + last_state_print = time(0); + } + + if (ds == NDMP9_DATA_STATE_ACTIVE) { + count = 0; + continue; + } + + /* + * If DATA has halted, the show is over. + */ + if (ds == NDMP9_DATA_STATE_HALTED) { + ndmalogf (sess, 0, 2, "Operation done, cleaning up"); + + ndmca_monitor_get_post_backup_env (sess); + + return 0; + } + + } + + ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling"); + return -1; +} + + +int +ndmca_backreco_startup (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int rc = 0; + + if (!ca->job.tape_tcp) + rc = ndmca_op_robot_startup (sess, 1); + if (rc) return rc; + + rc = ndmca_connect_data_agent(sess); + if (rc) { + ndmconn_destruct (sess->plumb.data); + return rc; + } + + if (ca->job.tape_tcp) { + return 0; + } + + rc = ndmca_connect_tape_agent(sess); + if (rc) { + ndmconn_destruct (sess->plumb.tape); + return rc; + } + + rc = ndmca_mover_set_record_size (sess); + if (rc) return rc; + + rc = ndmca_media_load_first (sess); + if (rc) return rc; + + ndmca_media_calculate_offsets (sess); + + if (sess->control_acb.swap_connect && + (sess->plumb.tape->protocol_version >= 3)) { + if (sess->plumb.tape->protocol_version < 4) { + rc = ndmca_data_listen (sess); + if (rc) return rc; + + rc = ndmca_media_set_window_current (sess); + if (rc) return rc; + } else { + rc = ndmca_media_set_window_current (sess); + if (rc) return rc; + + rc = ndmca_data_listen (sess); + if (rc) return rc; + } + } else { + if (sess->plumb.tape->protocol_version < 4) { + rc = ndmca_mover_listen (sess); + if (rc) return rc; + + rc = ndmca_media_set_window_current (sess); + if (rc) return rc; + } else { + rc = ndmca_media_set_window_current (sess); + if (rc) return rc; + + rc = ndmca_mover_listen (sess); + if (rc) return rc; + } + } + + return 0; +} + +int +ndmca_monitor_startup (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + ndmp9_data_state ds; + ndmp9_mover_state ms; + int count; + + ndmalogf (sess, 0, 3, "Waiting for operation to start"); + + if (ca->job.tape_tcp) + return 0; + + for (count = 0; count < 10; count++) { + if (ndmca_monitor_get_states (sess) < 0) + break; + + ds = ca->data_state.state; + if (!ca->job.tape_tcp) + ms = ca->mover_state.state; + else + ms = NDMP9_MOVER_STATE_ACTIVE; + + if (ds == NDMP9_DATA_STATE_ACTIVE + && ms == NDMP9_MOVER_STATE_ACTIVE) { + ndmalogf (sess, 0, 1, "Operation started"); + return 0; + } + + if (ds == NDMP9_DATA_STATE_HALTED + && ms == NDMP9_MOVER_STATE_HALTED) { + /* operation finished immediately */ + return 0; + } + + if (ds != NDMP9_DATA_STATE_IDLE + && ms != NDMP9_MOVER_STATE_IDLE + && ms != NDMP9_MOVER_STATE_LISTEN) { + ndmalogf (sess, 0, 1, + "Operation started in unusual fashion"); + return 0; + } + + ndmca_mon_wait_for_something (sess, 2); + } + + ndmalogf (sess, 0, 0, "Operation failed to start"); + return -1; +} + +/* + * Just make sure things get finished + */ +int +ndmca_monitor_shutdown (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + ndmp9_data_state ds; + ndmp9_data_halt_reason dhr; + ndmp9_mover_state ms; + ndmp9_mover_halt_reason mhr; + int count; + int finish; + + if (ca->job.tape_tcp) { + return ndmca_monitor_shutdown_tape_tcp(sess); + } + ndmalogf (sess, 0, 3, "Waiting for operation to halt"); + + for (count = 0; count < 10; count++) { + ndmca_mon_wait_for_something (sess, 2); + + if (ndmca_monitor_get_states (sess) < 0) + break; + +#if 0 + if (count > 2) + ndmca_mon_show_states(sess); +#endif + + ds = ca->data_state.state; + ms = ca->mover_state.state; + + if (ds == NDMP9_DATA_STATE_HALTED + && ms == NDMP9_MOVER_STATE_HALTED) { + dhr = ca->data_state.halt_reason; + mhr = ca->mover_state.halt_reason; + break; + } + + if (count > 2) { + if (ds != NDMP9_DATA_STATE_HALTED) + ndmca_data_abort(sess); + if (ms != NDMP9_MOVER_STATE_HALTED) + ndmca_mover_abort(sess); + } + } + + if (ca->tape_state.error == NDMP9_NO_ERR) { + ndmca_monitor_unload_last_tape (sess); + } + + if (count >= 10) { + ndmalogf (sess, 0, 0, + "Operation did not halt, something wrong"); + } + + ndmalogf (sess, 0, 2, "Operation halted, stopping"); + + ds = ca->data_state.state; + ms = ca->mover_state.state; + dhr = ca->data_state.halt_reason; + mhr = ca->mover_state.halt_reason; + + if ((ds == NDMP9_DATA_STATE_HALTED) + && (ms == NDMP9_MOVER_STATE_HALTED)) { + if ((dhr == NDMP9_DATA_HALT_SUCCESSFUL) && + (mhr == NDMP9_MOVER_HALT_CONNECT_CLOSED)) { + /* Successful operation */ + ndmalogf (sess, 0, 0, "Operation ended OKAY"); + finish = 0; + } else { + /* Questionable success */ + ndmalogf (sess, 0, 0, "Operation ended questionably"); + finish = 1; + } + } else { + ndmalogf (sess, 0, 0, "Operation ended in failure"); + finish = -1; + } + + ndmca_data_stop (sess); + ndmca_mover_stop (sess); + + for (count = 0; count < 10; count++) { + if (ndmca_monitor_get_states(sess) < 0) + break; + +#if 0 + if (count > 2) + ndmca_mon_show_states(sess); +#endif + + ds = ca->data_state.state; + ms = ca->mover_state.state; + + if (ds == NDMP9_DATA_STATE_IDLE + && ms == NDMP9_MOVER_STATE_IDLE) { + break; + } + } + + if (count >= 10) { + ndmalogf (sess, 0, 0, + "Operation did not stop, something wrong"); + return -1; + } + + return finish; +} + +int +ndmca_monitor_shutdown_tape_tcp (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + ndmp9_data_state ds; + ndmp9_data_halt_reason dhr; + int count; + int finish; + + ndmalogf (sess, 0, 3, "Waiting for operation to halt"); + + for (count = 0; count < 10; count++) { + ndmca_mon_wait_for_something (sess, 2); + + if (ndmca_monitor_get_states (sess) < 0) + break; + +#if 0 + if (count > 2) + ndmca_mon_show_states(sess); +#endif + + ds = ca->data_state.state; + + if (ds == NDMP9_DATA_STATE_HALTED) { + dhr = ca->data_state.halt_reason; + break; + } + + if (count > 2) { + if (ds != NDMP9_DATA_STATE_HALTED) + ndmca_data_abort(sess); + } + } + + if (count >= 10) { + ndmalogf (sess, 0, 0, + "Operation did not halt, something wrong"); + } + + ndmalogf (sess, 0, 2, "Operation halted, stopping"); + + ds = ca->data_state.state; + dhr = ca->data_state.halt_reason; + + if (ds == NDMP9_DATA_STATE_HALTED) { + if (dhr == NDMP9_DATA_HALT_SUCCESSFUL) { + /* Successful operation */ + ndmalogf (sess, 0, 0, "Operation ended OKAY"); + finish = 0; + } else { + /* Questionable success */ + ndmalogf (sess, 0, 0, "Operation ended questionably"); + finish = 1; + } + } else { + ndmalogf (sess, 0, 0, "Operation ended in failure"); + finish = -1; + } + + ndmca_data_stop (sess); + + for (count = 0; count < 10; count++) { + if (ndmca_monitor_get_states(sess) < 0) + break; + +#if 0 + if (count > 2) + ndmca_mon_show_states(sess); +#endif + + ds = ca->data_state.state; + + if (ds == NDMP9_DATA_STATE_IDLE) { + break; + } + } + + if (count >= 10) { + ndmalogf (sess, 0, 0, + "Operation did not stop, something wrong"); + return -1; + } + + return finish; +} + +int +ndmca_monitor_get_states (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int rc = 0; + + if (ndmca_data_get_state (sess) < 0) + rc = -1; + if (!ca->job.tape_tcp) { + if (ndmca_mover_get_state (sess) < 0) + rc = -1; + ndmca_tape_get_state_no_tattle (sess); + } + + return rc; +} + +int +ndmca_monitor_load_next (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int rc; + + ndmalogf (sess, 0, 1, "Operation requires next tape"); + + ndmca_media_capture_mover_window (sess); + ndmca_media_calculate_offsets (sess); + + if (ca->tape_mode == NDMP9_TAPE_RDWR_MODE) { + if (ca->mover_state.pause_reason != NDMP9_MOVER_PAUSE_EOM) + ndmca_media_write_filemarks (sess); + else + ndmalogf (sess, 0, 1, "At EOM, not writing filemarks"); + } + + rc = ndmca_media_unload_current(sess); + if (rc) return rc; + + rc = ndmca_media_load_next(sess); + if (rc) return rc; + + rc = ndmca_media_set_window_current (sess); + if (rc) return rc; + + rc = ndmca_mover_continue(sess); + if (rc) return rc; + + ndmalogf (sess, 0, 1, "Operation resuming"); + + return 0; +} + +/* VERY VERY HARD */ +int +ndmca_monitor_seek_tape (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int rc; + unsigned long long pos; + + pos = ca->last_notify_mover_paused.seek_position; + + ndmalogf (sess, 0, 1, "Operation requires a different tape"); + +/* ndmca_media_capture_mover_window (sess); // !!! */ + ndmca_media_calculate_offsets (sess); + + rc = ndmca_media_unload_current(sess); + if (rc) return rc; + + rc = ndmca_media_load_seek (sess, pos); + if (rc) return rc; + + rc = ndmca_media_set_window_current (sess); + if (rc) return rc; + + rc = ndmca_mover_continue(sess); + if (rc) return rc; + + ndmalogf (sess, 0, 1, "Operation resuming"); + + return 0; +} + +int +ndmca_monitor_unload_last_tape (struct ndm_session *sess) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int rc; + + if (!ca->media_is_loaded) + return 0; + + ndmca_media_capture_mover_window (sess); + ndmca_media_calculate_offsets (sess); + + if (ca->tape_mode == NDMP9_TAPE_RDWR_MODE) { + ndmca_media_write_filemarks (sess); + } + + rc = ndmca_media_unload_current(sess); + if (rc) return rc; + + return 0; +} + +int +ndmca_mon_wait_for_something (struct ndm_session *sess, int max_delay_secs) +{ + struct ndm_control_agent *ca = &sess->control_acb; + int delta, notices; + int time_ref = time(0) + max_delay_secs; + + ndmalogf (sess, 0, 5, "mon_wait_for_something() entered"); + + for (;;) { + delta = time_ref - time(0); + if (delta <= 0) + break; + + notices = 0; + if (ca->pending_notify_data_read) { + /* leave visible */ + notices++; + } + if (ca->pending_notify_data_halted) { + /* just used to "wake up" */ + ca->pending_notify_data_halted = 0; + notices++; + } + if (ca->pending_notify_mover_paused) { + /* leave visible */ + notices++; + } + if (ca->pending_notify_mover_halted) { + /* just used to "wake up" */ + ca->pending_notify_mover_halted = 0; + notices++; + } + + ndma_session_quantum (sess, notices ? 0 : delta); + + if (notices) + break; + } + + ndmalogf (sess, 0, 5, "mon_wait_for_something() happened, resid=%d", + delta); + + return 0; +} +#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */