xref: /onnv-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c (revision 8800:dbcc21c0ec0f)
17917SReza.Sabdar@Sun.COM /*
2*8800SReza.Sabdar@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37917SReza.Sabdar@Sun.COM  * Use is subject to license terms.
47917SReza.Sabdar@Sun.COM  */
57917SReza.Sabdar@Sun.COM 
67917SReza.Sabdar@Sun.COM /*
77917SReza.Sabdar@Sun.COM  * BSD 3 Clause License
87917SReza.Sabdar@Sun.COM  *
97917SReza.Sabdar@Sun.COM  * Copyright (c) 2007, The Storage Networking Industry Association.
107917SReza.Sabdar@Sun.COM  *
117917SReza.Sabdar@Sun.COM  * Redistribution and use in source and binary forms, with or without
127917SReza.Sabdar@Sun.COM  * modification, are permitted provided that the following conditions
137917SReza.Sabdar@Sun.COM  * are met:
147917SReza.Sabdar@Sun.COM  * 	- Redistributions of source code must retain the above copyright
157917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer.
167917SReza.Sabdar@Sun.COM  *
177917SReza.Sabdar@Sun.COM  * 	- Redistributions in binary form must reproduce the above copyright
187917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer in
197917SReza.Sabdar@Sun.COM  *	  the documentation and/or other materials provided with the
207917SReza.Sabdar@Sun.COM  *	  distribution.
217917SReza.Sabdar@Sun.COM  *
227917SReza.Sabdar@Sun.COM  *	- Neither the name of The Storage Networking Industry Association (SNIA)
237917SReza.Sabdar@Sun.COM  *	  nor the names of its contributors may be used to endorse or promote
247917SReza.Sabdar@Sun.COM  *	  products derived from this software without specific prior written
257917SReza.Sabdar@Sun.COM  *	  permission.
267917SReza.Sabdar@Sun.COM  *
277917SReza.Sabdar@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
287917SReza.Sabdar@Sun.COM  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
297917SReza.Sabdar@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
307917SReza.Sabdar@Sun.COM  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
317917SReza.Sabdar@Sun.COM  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
327917SReza.Sabdar@Sun.COM  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
337917SReza.Sabdar@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
347917SReza.Sabdar@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
357917SReza.Sabdar@Sun.COM  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
367917SReza.Sabdar@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
377917SReza.Sabdar@Sun.COM  * POSSIBILITY OF SUCH DAMAGE.
387917SReza.Sabdar@Sun.COM  */
397917SReza.Sabdar@Sun.COM /* Copyright (c) 2007, The Storage Networking Industry Association. */
407917SReza.Sabdar@Sun.COM /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
417917SReza.Sabdar@Sun.COM 
427917SReza.Sabdar@Sun.COM #include <sys/ioctl.h>
437917SReza.Sabdar@Sun.COM #include <sys/types.h>
447917SReza.Sabdar@Sun.COM #include <sys/socket.h>
457917SReza.Sabdar@Sun.COM #include <sys/socketvar.h>
467917SReza.Sabdar@Sun.COM #include <netinet/in.h>
477917SReza.Sabdar@Sun.COM #include <arpa/inet.h>
487917SReza.Sabdar@Sun.COM #include <net/if.h>
497917SReza.Sabdar@Sun.COM #include <errno.h>
507917SReza.Sabdar@Sun.COM #include <fcntl.h>
517917SReza.Sabdar@Sun.COM #include <netdb.h>
527917SReza.Sabdar@Sun.COM #include <stdlib.h>
537917SReza.Sabdar@Sun.COM #include <unistd.h>
547917SReza.Sabdar@Sun.COM #include <string.h>
557917SReza.Sabdar@Sun.COM #include "ndmpd_common.h"
567917SReza.Sabdar@Sun.COM #include "ndmpd.h"
577917SReza.Sabdar@Sun.COM #include <sys/mtio.h>
587917SReza.Sabdar@Sun.COM 
597917SReza.Sabdar@Sun.COM /*
607917SReza.Sabdar@Sun.COM  * Maximum mover record size
617917SReza.Sabdar@Sun.COM  */
627917SReza.Sabdar@Sun.COM #define	MAX_MOVER_RECSIZE	(512*KILOBYTE)
637917SReza.Sabdar@Sun.COM 
647917SReza.Sabdar@Sun.COM static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
657917SReza.Sabdar@Sun.COM     ushort_t *port);
667917SReza.Sabdar@Sun.COM static int tape_write(ndmpd_session_t *session, char *data, ssize_t length);
677917SReza.Sabdar@Sun.COM static int tape_read(ndmpd_session_t *session, char *data);
687917SReza.Sabdar@Sun.COM static int change_tape(ndmpd_session_t *session);
697917SReza.Sabdar@Sun.COM static int discard_data(ndmpd_session_t *session, ulong_t length);
707917SReza.Sabdar@Sun.COM static int mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf);
717917SReza.Sabdar@Sun.COM static int mover_socket_write_one_buf(ndmpd_session_t *session,
727917SReza.Sabdar@Sun.COM     tlm_buffer_t *buf);
737917SReza.Sabdar@Sun.COM static int start_mover_for_restore(ndmpd_session_t *session);
747917SReza.Sabdar@Sun.COM static int mover_socket_read_one_buf(ndmpd_session_t *session,
757917SReza.Sabdar@Sun.COM     tlm_buffer_t *buf, long read_size);
767917SReza.Sabdar@Sun.COM static int mover_tape_write_one_buf(ndmpd_session_t *session,
777917SReza.Sabdar@Sun.COM     tlm_buffer_t *buf);
787917SReza.Sabdar@Sun.COM static int start_mover_for_backup(ndmpd_session_t *session);
797917SReza.Sabdar@Sun.COM static boolean_t is_writer_running_v3(ndmpd_session_t *session);
807917SReza.Sabdar@Sun.COM static int mover_pause_v3(ndmpd_session_t *session,
817917SReza.Sabdar@Sun.COM     ndmp_mover_pause_reason reason);
827917SReza.Sabdar@Sun.COM static int mover_tape_write_v3(ndmpd_session_t *session, char *data,
837917SReza.Sabdar@Sun.COM     ssize_t length);
847917SReza.Sabdar@Sun.COM static int mover_tape_flush_v3(ndmpd_session_t *session);
857917SReza.Sabdar@Sun.COM static int mover_tape_read_v3(ndmpd_session_t *session, char *data);
867917SReza.Sabdar@Sun.COM static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
877917SReza.Sabdar@Sun.COM     ushort_t *port);
887917SReza.Sabdar@Sun.COM static void mover_data_read_v3(void *cookie, int fd, ulong_t mode);
897917SReza.Sabdar@Sun.COM static void accept_connection(void *cookie, int fd, ulong_t mode);
907917SReza.Sabdar@Sun.COM static void mover_data_write_v3(void *cookie, int fd, ulong_t mode);
917917SReza.Sabdar@Sun.COM static void accept_connection_v3(void *cookie, int fd, ulong_t mode);
927917SReza.Sabdar@Sun.COM static ndmp_error mover_connect_sock_v3(ndmpd_session_t *session,
937917SReza.Sabdar@Sun.COM     ndmp_mover_mode mode, ulong_t addr, ushort_t port);
947917SReza.Sabdar@Sun.COM static boolean_t is_writer_running(ndmpd_session_t *session);
957917SReza.Sabdar@Sun.COM 
967917SReza.Sabdar@Sun.COM 
977917SReza.Sabdar@Sun.COM int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
987917SReza.Sabdar@Sun.COM 
997917SReza.Sabdar@Sun.COM #define	TAPE_READ_ERR		-1
1007917SReza.Sabdar@Sun.COM #define	TAPE_NO_WRITER_ERR	-2
1017917SReza.Sabdar@Sun.COM 
1027917SReza.Sabdar@Sun.COM #define	NDMP_APILOG(s, t, m, ...) \
1037917SReza.Sabdar@Sun.COM { \
1047917SReza.Sabdar@Sun.COM 	if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV4) \
1057917SReza.Sabdar@Sun.COM 		(void) ndmpd_api_log_v4(s, t, m, __VA_ARGS__); \
1067917SReza.Sabdar@Sun.COM 	else if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV3) \
1077917SReza.Sabdar@Sun.COM 		(void) ndmpd_api_log_v3(s, t, m, __VA_ARGS__); \
1087917SReza.Sabdar@Sun.COM 	else \
1097917SReza.Sabdar@Sun.COM 		(void) ndmpd_api_log_v2(s, __VA_ARGS__); \
1107917SReza.Sabdar@Sun.COM }
1117917SReza.Sabdar@Sun.COM 
1127917SReza.Sabdar@Sun.COM /*
1137917SReza.Sabdar@Sun.COM  * ************************************************************************
1147917SReza.Sabdar@Sun.COM  * NDMP V2 HANDLERS
1157917SReza.Sabdar@Sun.COM  * ************************************************************************
1167917SReza.Sabdar@Sun.COM  */
1177917SReza.Sabdar@Sun.COM 
1187917SReza.Sabdar@Sun.COM /*
1197917SReza.Sabdar@Sun.COM  * ndmpd_mover_get_state_v2
1207917SReza.Sabdar@Sun.COM  *
1217917SReza.Sabdar@Sun.COM  * This handler handles the mover_get_state request.
1227917SReza.Sabdar@Sun.COM  * Status information for the mover state machine is returned.
1237917SReza.Sabdar@Sun.COM  *
1247917SReza.Sabdar@Sun.COM  * Parameters:
1257917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
1267917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
1277917SReza.Sabdar@Sun.COM  *
1287917SReza.Sabdar@Sun.COM  * Returns:
1297917SReza.Sabdar@Sun.COM  *   void
1307917SReza.Sabdar@Sun.COM  */
1317917SReza.Sabdar@Sun.COM /*ARGSUSED*/
1327917SReza.Sabdar@Sun.COM void
1337917SReza.Sabdar@Sun.COM ndmpd_mover_get_state_v2(ndmp_connection_t *connection, void *body)
1347917SReza.Sabdar@Sun.COM {
1357917SReza.Sabdar@Sun.COM 	ndmp_mover_get_state_reply_v2 reply;
1367917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1377917SReza.Sabdar@Sun.COM 
1387917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
1397917SReza.Sabdar@Sun.COM 	reply.state = session->ns_mover.md_state;
1407917SReza.Sabdar@Sun.COM 	reply.pause_reason = session->ns_mover.md_pause_reason;
1417917SReza.Sabdar@Sun.COM 	reply.halt_reason = session->ns_mover.md_halt_reason;
1427917SReza.Sabdar@Sun.COM 	reply.record_size = session->ns_mover.md_record_size;
1437917SReza.Sabdar@Sun.COM 	reply.record_num = session->ns_mover.md_record_num;
1447917SReza.Sabdar@Sun.COM 	reply.data_written =
1457917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_data_written);
1467917SReza.Sabdar@Sun.COM 	reply.seek_position =
1477917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_seek_position);
1487917SReza.Sabdar@Sun.COM 	reply.bytes_left_to_read =
1497917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
1507917SReza.Sabdar@Sun.COM 	reply.window_offset =
1517917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_window_offset);
1527917SReza.Sabdar@Sun.COM 	reply.window_length =
1537917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_window_length);
1547917SReza.Sabdar@Sun.COM 
1557917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
1567917SReza.Sabdar@Sun.COM 	    "sending tape_get_state reply");
1577917SReza.Sabdar@Sun.COM }
1587917SReza.Sabdar@Sun.COM 
1597917SReza.Sabdar@Sun.COM 
1607917SReza.Sabdar@Sun.COM /*
1617917SReza.Sabdar@Sun.COM  * ndmpd_mover_listen_v2
1627917SReza.Sabdar@Sun.COM  *
1637917SReza.Sabdar@Sun.COM  * This handler handles mover_listen requests.
1647917SReza.Sabdar@Sun.COM  *
1657917SReza.Sabdar@Sun.COM  * Parameters:
1667917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
1677917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
1687917SReza.Sabdar@Sun.COM  *
1697917SReza.Sabdar@Sun.COM  * Returns:
1707917SReza.Sabdar@Sun.COM  *   void
1717917SReza.Sabdar@Sun.COM  */
1727917SReza.Sabdar@Sun.COM void
1737917SReza.Sabdar@Sun.COM ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
1747917SReza.Sabdar@Sun.COM {
1757917SReza.Sabdar@Sun.COM 	ndmp_mover_listen_request_v2 *request;
1767917SReza.Sabdar@Sun.COM 	ndmp_mover_listen_reply_v2 reply;
1777917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1787917SReza.Sabdar@Sun.COM 	ulong_t addr;
1797917SReza.Sabdar@Sun.COM 	ushort_t port;
1807917SReza.Sabdar@Sun.COM 
1817917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_listen_request_v2 *)body;
1827917SReza.Sabdar@Sun.COM 
1837917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
1847917SReza.Sabdar@Sun.COM 	    session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1857917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
1867917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1877917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
1887917SReza.Sabdar@Sun.COM 		    "sending mover_listen reply");
1897917SReza.Sabdar@Sun.COM 		return;
1907917SReza.Sabdar@Sun.COM 	}
1917917SReza.Sabdar@Sun.COM 	session->ns_mover.md_mode = request->mode;
1927917SReza.Sabdar@Sun.COM 
1937917SReza.Sabdar@Sun.COM 	if (request->addr_type == NDMP_ADDR_LOCAL) {
1947917SReza.Sabdar@Sun.COM 		reply.mover.addr_type = NDMP_ADDR_LOCAL;
1957917SReza.Sabdar@Sun.COM 	} else {
1967917SReza.Sabdar@Sun.COM 		if (create_listen_socket_v2(session, &addr, &port) < 0) {
1977917SReza.Sabdar@Sun.COM 			reply.error = NDMP_IO_ERR;
1987917SReza.Sabdar@Sun.COM 			ndmp_send_reply(connection, (void *) &reply,
1997917SReza.Sabdar@Sun.COM 			    "sending mover_listen reply");
2007917SReza.Sabdar@Sun.COM 			return;
2017917SReza.Sabdar@Sun.COM 		}
2027917SReza.Sabdar@Sun.COM 		reply.mover.addr_type = NDMP_ADDR_TCP;
2037917SReza.Sabdar@Sun.COM 		reply.mover.ndmp_mover_addr_u.addr.ip_addr = htonl(addr);
2047917SReza.Sabdar@Sun.COM 		reply.mover.ndmp_mover_addr_u.addr.port = htons(port);
2057917SReza.Sabdar@Sun.COM 	}
2067917SReza.Sabdar@Sun.COM 
2077917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
2087917SReza.Sabdar@Sun.COM 
2097917SReza.Sabdar@Sun.COM 	/*
2107917SReza.Sabdar@Sun.COM 	 * ndmp window should always set by client during restore
2117917SReza.Sabdar@Sun.COM 	 */
2127917SReza.Sabdar@Sun.COM 
2137917SReza.Sabdar@Sun.COM 	/* Set the default window. */
2147917SReza.Sabdar@Sun.COM 	session->ns_mover.md_window_offset = 0;
2157917SReza.Sabdar@Sun.COM 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
2167917SReza.Sabdar@Sun.COM 	session->ns_mover.md_position = 0;
2177917SReza.Sabdar@Sun.COM 
2187917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
2197917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
2207917SReza.Sabdar@Sun.COM 	    "sending mover_listen reply");
2217917SReza.Sabdar@Sun.COM }
2227917SReza.Sabdar@Sun.COM 
2237917SReza.Sabdar@Sun.COM 
2247917SReza.Sabdar@Sun.COM /*
2257917SReza.Sabdar@Sun.COM  * ndmpd_mover_continue_v2
2267917SReza.Sabdar@Sun.COM  *
2277917SReza.Sabdar@Sun.COM  * This handler handles mover_continue requests.
2287917SReza.Sabdar@Sun.COM  *
2297917SReza.Sabdar@Sun.COM  * Parameters:
2307917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
2317917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
2327917SReza.Sabdar@Sun.COM  *
2337917SReza.Sabdar@Sun.COM  * Returns:
2347917SReza.Sabdar@Sun.COM  *   void
2357917SReza.Sabdar@Sun.COM  */
2367917SReza.Sabdar@Sun.COM /*ARGSUSED*/
2377917SReza.Sabdar@Sun.COM void
2387917SReza.Sabdar@Sun.COM ndmpd_mover_continue_v2(ndmp_connection_t *connection, void *body)
2397917SReza.Sabdar@Sun.COM {
2407917SReza.Sabdar@Sun.COM 	ndmp_mover_continue_reply reply;
2417917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
2427917SReza.Sabdar@Sun.COM 
2437917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
2447917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
2457917SReza.Sabdar@Sun.COM 
2467917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
2477917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
2487917SReza.Sabdar@Sun.COM 		    "sending mover_continue reply");
2497917SReza.Sabdar@Sun.COM 		return;
2507917SReza.Sabdar@Sun.COM 	}
2517917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2527917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
2537917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
2547917SReza.Sabdar@Sun.COM 	    "sending mover_continue reply");
2557917SReza.Sabdar@Sun.COM }
2567917SReza.Sabdar@Sun.COM 
2577917SReza.Sabdar@Sun.COM 
2587917SReza.Sabdar@Sun.COM /*
2597917SReza.Sabdar@Sun.COM  * ndmpd_mover_abort_v2
2607917SReza.Sabdar@Sun.COM  *
2617917SReza.Sabdar@Sun.COM  * This handler handles mover_abort requests.
2627917SReza.Sabdar@Sun.COM  *
2637917SReza.Sabdar@Sun.COM  * Parameters:
2647917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
2657917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
2667917SReza.Sabdar@Sun.COM  *
2677917SReza.Sabdar@Sun.COM  * Returns:
2687917SReza.Sabdar@Sun.COM  *   void
2697917SReza.Sabdar@Sun.COM  */
2707917SReza.Sabdar@Sun.COM /*ARGSUSED*/
2717917SReza.Sabdar@Sun.COM void
2727917SReza.Sabdar@Sun.COM ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
2737917SReza.Sabdar@Sun.COM {
2747917SReza.Sabdar@Sun.COM 	ndmp_mover_abort_reply reply;
2757917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
2767917SReza.Sabdar@Sun.COM 
2777917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
2787917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
2797917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
2807917SReza.Sabdar@Sun.COM 
2817917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
2827917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
2837917SReza.Sabdar@Sun.COM 		    "sending mover_abort reply");
2847917SReza.Sabdar@Sun.COM 		return;
2857917SReza.Sabdar@Sun.COM 	}
2867917SReza.Sabdar@Sun.COM 
2877917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
2887917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
2897917SReza.Sabdar@Sun.COM 	    "sending mover_abort reply");
2907917SReza.Sabdar@Sun.COM 
2917917SReza.Sabdar@Sun.COM 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
2927917SReza.Sabdar@Sun.COM 
2937917SReza.Sabdar@Sun.COM 	nlp_event_nw(session);
2947917SReza.Sabdar@Sun.COM 	ndmp_stop_buffer_worker(session);
2957917SReza.Sabdar@Sun.COM }
2967917SReza.Sabdar@Sun.COM 
2977917SReza.Sabdar@Sun.COM 
2987917SReza.Sabdar@Sun.COM /*
2997917SReza.Sabdar@Sun.COM  * ndmpd_mover_stop_v2
3007917SReza.Sabdar@Sun.COM  *
3017917SReza.Sabdar@Sun.COM  * This handler handles mover_stop requests.
3027917SReza.Sabdar@Sun.COM  *
3037917SReza.Sabdar@Sun.COM  * Parameters:
3047917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
3057917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
3067917SReza.Sabdar@Sun.COM  *
3077917SReza.Sabdar@Sun.COM  * Returns:
3087917SReza.Sabdar@Sun.COM  *   void
3097917SReza.Sabdar@Sun.COM  */
3107917SReza.Sabdar@Sun.COM /*ARGSUSED*/
3117917SReza.Sabdar@Sun.COM void
3127917SReza.Sabdar@Sun.COM ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
3137917SReza.Sabdar@Sun.COM {
3147917SReza.Sabdar@Sun.COM 	ndmp_mover_stop_reply reply;
3157917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
3167917SReza.Sabdar@Sun.COM 
3177917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {
3187917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
3197917SReza.Sabdar@Sun.COM 
3207917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
3217917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
3227917SReza.Sabdar@Sun.COM 		    "sending mover_stop reply");
3237917SReza.Sabdar@Sun.COM 		return;
3247917SReza.Sabdar@Sun.COM 	}
3257917SReza.Sabdar@Sun.COM 
3267917SReza.Sabdar@Sun.COM 	ndmp_waitfor_op(session);
3277917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
3287917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
3297917SReza.Sabdar@Sun.COM 	    "sending mover_stop reply");
3307917SReza.Sabdar@Sun.COM 
3317917SReza.Sabdar@Sun.COM 	ndmp_lbr_cleanup(session);
3327917SReza.Sabdar@Sun.COM 	ndmpd_mover_cleanup(session);
3337917SReza.Sabdar@Sun.COM 	(void) ndmpd_mover_init(session);
3347917SReza.Sabdar@Sun.COM 	(void) ndmp_lbr_init(session);
3357917SReza.Sabdar@Sun.COM }
3367917SReza.Sabdar@Sun.COM 
3377917SReza.Sabdar@Sun.COM 
3387917SReza.Sabdar@Sun.COM /*
3397917SReza.Sabdar@Sun.COM  * ndmpd_mover_set_window_v2
3407917SReza.Sabdar@Sun.COM  *
3417917SReza.Sabdar@Sun.COM  * This handler handles mover_set_window requests.
3427917SReza.Sabdar@Sun.COM  *
3437917SReza.Sabdar@Sun.COM  *
3447917SReza.Sabdar@Sun.COM  * Parameters:
3457917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
3467917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
3477917SReza.Sabdar@Sun.COM  *
3487917SReza.Sabdar@Sun.COM  * Returns:
3497917SReza.Sabdar@Sun.COM  *   void
3507917SReza.Sabdar@Sun.COM  */
3517917SReza.Sabdar@Sun.COM void
3527917SReza.Sabdar@Sun.COM ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
3537917SReza.Sabdar@Sun.COM {
3547917SReza.Sabdar@Sun.COM 	ndmp_mover_set_window_request *request;
3557917SReza.Sabdar@Sun.COM 	ndmp_mover_set_window_reply reply;
3567917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
3577917SReza.Sabdar@Sun.COM 
3587917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_set_window_request *) body;
3597917SReza.Sabdar@Sun.COM 
3607917SReza.Sabdar@Sun.COM 	/*
3617917SReza.Sabdar@Sun.COM 	 * The NDMPv2 specification states that "a window can be set only
3627917SReza.Sabdar@Sun.COM 	 * when in the listen or paused state."
3637917SReza.Sabdar@Sun.COM 	 *
3647917SReza.Sabdar@Sun.COM 	 * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
3657917SReza.Sabdar@Sun.COM 	 * allowing it in the idle state as well.
3667917SReza.Sabdar@Sun.COM 	 */
3677917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
3687917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
3697917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
3707917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
3717917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
3727917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_state);
3737917SReza.Sabdar@Sun.COM 	} else {
3747917SReza.Sabdar@Sun.COM 		if (quad_to_long_long(request->length) == 0) {
3757917SReza.Sabdar@Sun.COM 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
3767917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
3777917SReza.Sabdar@Sun.COM 			    quad_to_long_long(request->length));
3787917SReza.Sabdar@Sun.COM 		} else {
3797917SReza.Sabdar@Sun.COM 			reply.error = NDMP_NO_ERR;
3807917SReza.Sabdar@Sun.COM 			session->ns_mover.md_window_offset =
3817917SReza.Sabdar@Sun.COM 			    quad_to_long_long(request->offset);
3827917SReza.Sabdar@Sun.COM 			session->ns_mover.md_window_length =
3837917SReza.Sabdar@Sun.COM 			    quad_to_long_long(request->length);
3847917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position =
3857917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_window_offset;
3867917SReza.Sabdar@Sun.COM 		}
3877917SReza.Sabdar@Sun.COM 	}
3887917SReza.Sabdar@Sun.COM 
3897917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
3907917SReza.Sabdar@Sun.COM 	    "sending mover_set_window reply");
3917917SReza.Sabdar@Sun.COM }
3927917SReza.Sabdar@Sun.COM 
3937917SReza.Sabdar@Sun.COM 
3947917SReza.Sabdar@Sun.COM /*
3957917SReza.Sabdar@Sun.COM  * ndmpd_mover_read_v2
3967917SReza.Sabdar@Sun.COM  *
3977917SReza.Sabdar@Sun.COM  * This handler handles mover_read requests. If the requested offset is
3987917SReza.Sabdar@Sun.COM  * outside of the current window, the mover is paused and a notify_mover_paused
3997917SReza.Sabdar@Sun.COM  * request is sent notifying the client that a seek is required. If the
4007917SReza.Sabdar@Sun.COM  * requested offest is within the window but not within the current record,
4017917SReza.Sabdar@Sun.COM  * then the tape is positioned to the record containing the requested offest.
4027917SReza.Sabdar@Sun.COM  * The requested amount of data is then read from the tape device and written
4037917SReza.Sabdar@Sun.COM  * to the data connection.
4047917SReza.Sabdar@Sun.COM  *
4057917SReza.Sabdar@Sun.COM  * Parameters:
4067917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
4077917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
4087917SReza.Sabdar@Sun.COM  *
4097917SReza.Sabdar@Sun.COM  * Returns:
4107917SReza.Sabdar@Sun.COM  *   void
4117917SReza.Sabdar@Sun.COM  */
4127917SReza.Sabdar@Sun.COM void
4137917SReza.Sabdar@Sun.COM ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
4147917SReza.Sabdar@Sun.COM {
4157917SReza.Sabdar@Sun.COM 	ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
4167917SReza.Sabdar@Sun.COM 	ndmp_mover_read_reply reply;
4177917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
4187917SReza.Sabdar@Sun.COM 	int err;
4197917SReza.Sabdar@Sun.COM 
4207917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
4217917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_bytes_left_to_read != 0 ||
4227917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
4237917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
4247917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
4257917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, &reply,
4267917SReza.Sabdar@Sun.COM 		    "sending mover_read reply");
4277917SReza.Sabdar@Sun.COM 		return;
4287917SReza.Sabdar@Sun.COM 	}
4297917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
4307917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
4317917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
4327917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, &reply,
4337917SReza.Sabdar@Sun.COM 		    "sending mover_read reply");
4347917SReza.Sabdar@Sun.COM 		return;
4357917SReza.Sabdar@Sun.COM 	}
4367917SReza.Sabdar@Sun.COM 
4377917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
4387917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, &reply, "sending mover_read reply");
4397917SReza.Sabdar@Sun.COM 
4407917SReza.Sabdar@Sun.COM 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
4417917SReza.Sabdar@Sun.COM 	    quad_to_long_long(request->length));
4427917SReza.Sabdar@Sun.COM 	if (err < 0) {
4437917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4447917SReza.Sabdar@Sun.COM 		return;
4457917SReza.Sabdar@Sun.COM 	}
4467917SReza.Sabdar@Sun.COM 	/*
4477917SReza.Sabdar@Sun.COM 	 * Just return if we are waiting for the NDMP client to
4487917SReza.Sabdar@Sun.COM 	 * complete the seek.
4497917SReza.Sabdar@Sun.COM 	 */
4507917SReza.Sabdar@Sun.COM 	if (err == 1)
4517917SReza.Sabdar@Sun.COM 		return;
4527917SReza.Sabdar@Sun.COM 
4537917SReza.Sabdar@Sun.COM 	/*
4547917SReza.Sabdar@Sun.COM 	 * Start the mover for restore in the 3-way backups.
4557917SReza.Sabdar@Sun.COM 	 */
4567917SReza.Sabdar@Sun.COM 	if (start_mover_for_restore(session) < 0)
4577917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4587917SReza.Sabdar@Sun.COM }
4597917SReza.Sabdar@Sun.COM 
4607917SReza.Sabdar@Sun.COM 
4617917SReza.Sabdar@Sun.COM /*
4627917SReza.Sabdar@Sun.COM  * ndmpd_mover_close_v2
4637917SReza.Sabdar@Sun.COM  *
4647917SReza.Sabdar@Sun.COM  * This handler handles mover_close requests.
4657917SReza.Sabdar@Sun.COM  *
4667917SReza.Sabdar@Sun.COM  * Parameters:
4677917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
4687917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
4697917SReza.Sabdar@Sun.COM  *
4707917SReza.Sabdar@Sun.COM  * Returns:
4717917SReza.Sabdar@Sun.COM  *   void
4727917SReza.Sabdar@Sun.COM  */
4737917SReza.Sabdar@Sun.COM /*ARGSUSED*/
4747917SReza.Sabdar@Sun.COM void
4757917SReza.Sabdar@Sun.COM ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
4767917SReza.Sabdar@Sun.COM {
4777917SReza.Sabdar@Sun.COM 	ndmp_mover_close_reply reply;
4787917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
4797917SReza.Sabdar@Sun.COM 
4807917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
4817917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
4827917SReza.Sabdar@Sun.COM 
4837917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
4847917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, &reply,
4857917SReza.Sabdar@Sun.COM 		    "sending mover_close reply");
4867917SReza.Sabdar@Sun.COM 		return;
4877917SReza.Sabdar@Sun.COM 	}
4887917SReza.Sabdar@Sun.COM 	free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
4897917SReza.Sabdar@Sun.COM 
4907917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
4917917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, &reply, "sending mover_close reply");
4927917SReza.Sabdar@Sun.COM 
4937917SReza.Sabdar@Sun.COM 	ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
4947917SReza.Sabdar@Sun.COM }
4957917SReza.Sabdar@Sun.COM 
4967917SReza.Sabdar@Sun.COM 
4977917SReza.Sabdar@Sun.COM /*
4987917SReza.Sabdar@Sun.COM  * ndmpd_mover_set_record_size_v2
4997917SReza.Sabdar@Sun.COM  *
5007917SReza.Sabdar@Sun.COM  * This handler handles mover_set_record_size requests.
5017917SReza.Sabdar@Sun.COM  *
5027917SReza.Sabdar@Sun.COM  * Parameters:
5037917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
5047917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
5057917SReza.Sabdar@Sun.COM  *
5067917SReza.Sabdar@Sun.COM  * Returns:
5077917SReza.Sabdar@Sun.COM  *   void
5087917SReza.Sabdar@Sun.COM  */
5097917SReza.Sabdar@Sun.COM void
5107917SReza.Sabdar@Sun.COM ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
5117917SReza.Sabdar@Sun.COM {
5127917SReza.Sabdar@Sun.COM 	ndmp_mover_set_record_size_request *request;
5137917SReza.Sabdar@Sun.COM 	ndmp_mover_set_record_size_reply reply;
5147917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
5157917SReza.Sabdar@Sun.COM 
5167917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_set_record_size_request *) body;
5177917SReza.Sabdar@Sun.COM 
5187917SReza.Sabdar@Sun.COM 	session->ns_mover.md_record_size = request->len;
5197917SReza.Sabdar@Sun.COM 	session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
5207917SReza.Sabdar@Sun.COM 	    request->len);
5217917SReza.Sabdar@Sun.COM 
5227917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
5237917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, &reply,
5247917SReza.Sabdar@Sun.COM 	    "sending mover_set_record_size reply");
5257917SReza.Sabdar@Sun.COM }
5267917SReza.Sabdar@Sun.COM 
5277917SReza.Sabdar@Sun.COM 
5287917SReza.Sabdar@Sun.COM /*
5297917SReza.Sabdar@Sun.COM  * ************************************************************************
5307917SReza.Sabdar@Sun.COM  * NDMP V3 HANDLERS
5317917SReza.Sabdar@Sun.COM  * ************************************************************************
5327917SReza.Sabdar@Sun.COM  */
5337917SReza.Sabdar@Sun.COM 
5347917SReza.Sabdar@Sun.COM /*
5357917SReza.Sabdar@Sun.COM  * ndmpd_mover_get_state_v3
5367917SReza.Sabdar@Sun.COM  *
5377917SReza.Sabdar@Sun.COM  * This handler handles the ndmp_mover_get_state_request.
5387917SReza.Sabdar@Sun.COM  * Status information for the mover state machine is returned.
5397917SReza.Sabdar@Sun.COM  *
5407917SReza.Sabdar@Sun.COM  * Parameters:
5417917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
5427917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
5437917SReza.Sabdar@Sun.COM  *
5447917SReza.Sabdar@Sun.COM  * Returns:
5457917SReza.Sabdar@Sun.COM  *   void
5467917SReza.Sabdar@Sun.COM  */
5477917SReza.Sabdar@Sun.COM /*ARGSUSED*/
5487917SReza.Sabdar@Sun.COM void
5497917SReza.Sabdar@Sun.COM ndmpd_mover_get_state_v3(ndmp_connection_t *connection, void *body)
5507917SReza.Sabdar@Sun.COM {
5517917SReza.Sabdar@Sun.COM 	ndmp_mover_get_state_reply_v3 reply;
5527917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
5537917SReza.Sabdar@Sun.COM 
5547917SReza.Sabdar@Sun.COM 	(void) memset((void*)&reply, 0, sizeof (reply));
5557917SReza.Sabdar@Sun.COM 
5567917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
5577917SReza.Sabdar@Sun.COM 	reply.state = session->ns_mover.md_state;
5587917SReza.Sabdar@Sun.COM 	reply.pause_reason = session->ns_mover.md_pause_reason;
5597917SReza.Sabdar@Sun.COM 	reply.halt_reason = session->ns_mover.md_halt_reason;
5607917SReza.Sabdar@Sun.COM 	reply.record_size = session->ns_mover.md_record_size;
5617917SReza.Sabdar@Sun.COM 	reply.record_num = session->ns_mover.md_record_num;
5627917SReza.Sabdar@Sun.COM 	reply.data_written =
5637917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_data_written);
5647917SReza.Sabdar@Sun.COM 	reply.seek_position =
5657917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_seek_position);
5667917SReza.Sabdar@Sun.COM 	reply.bytes_left_to_read =
5677917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
5687917SReza.Sabdar@Sun.COM 	reply.window_offset =
5697917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_window_offset);
5707917SReza.Sabdar@Sun.COM 	reply.window_length =
5717917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_window_length);
5727917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
5737917SReza.Sabdar@Sun.COM 		ndmp_copy_addr_v3(&reply.data_connection_addr,
5747917SReza.Sabdar@Sun.COM 		    &session->ns_mover.md_data_addr);
5757917SReza.Sabdar@Sun.COM 
5767917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, &reply,
5777917SReza.Sabdar@Sun.COM 	    "sending ndmp_mover_get_state reply");
5787917SReza.Sabdar@Sun.COM }
5797917SReza.Sabdar@Sun.COM 
5807917SReza.Sabdar@Sun.COM 
5817917SReza.Sabdar@Sun.COM /*
5827917SReza.Sabdar@Sun.COM  * ndmpd_mover_listen_v3
5837917SReza.Sabdar@Sun.COM  *
5847917SReza.Sabdar@Sun.COM  * This handler handles ndmp_mover_listen_requests.
5857917SReza.Sabdar@Sun.COM  * A TCP/IP socket is created that is used to listen for
5867917SReza.Sabdar@Sun.COM  * and accept data connections initiated by a remote
5877917SReza.Sabdar@Sun.COM  * data server.
5887917SReza.Sabdar@Sun.COM  *
5897917SReza.Sabdar@Sun.COM  * Parameters:
5907917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
5917917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
5927917SReza.Sabdar@Sun.COM  *
5937917SReza.Sabdar@Sun.COM  * Returns:
5947917SReza.Sabdar@Sun.COM  *   void
5957917SReza.Sabdar@Sun.COM  */
5967917SReza.Sabdar@Sun.COM void
5977917SReza.Sabdar@Sun.COM ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
5987917SReza.Sabdar@Sun.COM {
5997917SReza.Sabdar@Sun.COM 	ndmp_mover_listen_request_v3 *request;
6007917SReza.Sabdar@Sun.COM 	ndmp_mover_listen_reply_v3 reply;
6017917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
6027917SReza.Sabdar@Sun.COM 	ulong_t addr;
6037917SReza.Sabdar@Sun.COM 	ushort_t port;
6047917SReza.Sabdar@Sun.COM 
6057917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_listen_request_v3 *)body;
6067917SReza.Sabdar@Sun.COM 
6077917SReza.Sabdar@Sun.COM 	(void) memset((void*)&reply, 0, sizeof (reply));
6087917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
6097917SReza.Sabdar@Sun.COM 
6107917SReza.Sabdar@Sun.COM 	if (request->mode != NDMP_MOVER_MODE_READ &&
6117917SReza.Sabdar@Sun.COM 	    request->mode != NDMP_MOVER_MODE_WRITE) {
6127917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6137917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
6147917SReza.Sabdar@Sun.COM 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
6157917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6167917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
6177917SReza.Sabdar@Sun.COM 		    request->addr_type);
6187917SReza.Sabdar@Sun.COM 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
6197917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
6207917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
6217917SReza.Sabdar@Sun.COM 		    "Invalid mover state to process listen request");
6227917SReza.Sabdar@Sun.COM 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
6237917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
6247917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
6257917SReza.Sabdar@Sun.COM 		    "Invalid data state to process listen request");
6267917SReza.Sabdar@Sun.COM 	} else if (session->ns_tape.td_fd == -1) {
6277917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
6287917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "No tape device open");
6297917SReza.Sabdar@Sun.COM 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
6307917SReza.Sabdar@Sun.COM 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
6317917SReza.Sabdar@Sun.COM 		reply.error = NDMP_PERMISSION_ERR;
6327917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Write protected device.");
6337917SReza.Sabdar@Sun.COM 	}
6347917SReza.Sabdar@Sun.COM 
6357917SReza.Sabdar@Sun.COM 	if (reply.error != NDMP_NO_ERR) {
6367917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, &reply,
6377917SReza.Sabdar@Sun.COM 		    "error sending ndmp_mover_listen reply");
6387917SReza.Sabdar@Sun.COM 		return;
6397917SReza.Sabdar@Sun.COM 	}
6407917SReza.Sabdar@Sun.COM 
6417917SReza.Sabdar@Sun.COM 	switch (request->addr_type) {
6427917SReza.Sabdar@Sun.COM 	case NDMP_ADDR_LOCAL:
6437917SReza.Sabdar@Sun.COM 		reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
6447917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
6457917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
6467917SReza.Sabdar@Sun.COM 		break;
6477917SReza.Sabdar@Sun.COM 	case NDMP_ADDR_TCP:
6487917SReza.Sabdar@Sun.COM 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
6497917SReza.Sabdar@Sun.COM 			reply.error = NDMP_IO_ERR;
6507917SReza.Sabdar@Sun.COM 			break;
6517917SReza.Sabdar@Sun.COM 		}
6527917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
6537917SReza.Sabdar@Sun.COM 		reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
6547917SReza.Sabdar@Sun.COM 		reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
6557917SReza.Sabdar@Sun.COM 		reply.data_connection_addr.tcp_port_v3 = htons(port);
6567917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
6577917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
6587917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
6597917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
6607917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_listen_sock);
6617917SReza.Sabdar@Sun.COM 		break;
6627917SReza.Sabdar@Sun.COM 	default:
6637917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6647917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
6657917SReza.Sabdar@Sun.COM 		    request->addr_type);
6667917SReza.Sabdar@Sun.COM 	}
6677917SReza.Sabdar@Sun.COM 
6687917SReza.Sabdar@Sun.COM 	if (reply.error == NDMP_NO_ERR) {
6697917SReza.Sabdar@Sun.COM 		session->ns_mover.md_mode = request->mode;
6707917SReza.Sabdar@Sun.COM 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
6717917SReza.Sabdar@Sun.COM 	}
6727917SReza.Sabdar@Sun.COM 
6737917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, &reply,
6747917SReza.Sabdar@Sun.COM 	    "error sending ndmp_mover_listen reply");
6757917SReza.Sabdar@Sun.COM }
6767917SReza.Sabdar@Sun.COM 
6777917SReza.Sabdar@Sun.COM 
6787917SReza.Sabdar@Sun.COM /*
6797917SReza.Sabdar@Sun.COM  * ndmpd_mover_continue_v3
6807917SReza.Sabdar@Sun.COM  *
6817917SReza.Sabdar@Sun.COM  * This handler handles ndmp_mover_continue_requests.
6827917SReza.Sabdar@Sun.COM  *
6837917SReza.Sabdar@Sun.COM  * Parameters:
6847917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
6857917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
6867917SReza.Sabdar@Sun.COM  *
6877917SReza.Sabdar@Sun.COM  * Returns:
6887917SReza.Sabdar@Sun.COM  *   void
6897917SReza.Sabdar@Sun.COM  */
6907917SReza.Sabdar@Sun.COM /*ARGSUSED*/
6917917SReza.Sabdar@Sun.COM void
6927917SReza.Sabdar@Sun.COM ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
6937917SReza.Sabdar@Sun.COM {
6947917SReza.Sabdar@Sun.COM 	ndmp_mover_continue_reply reply;
6957917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
6967917SReza.Sabdar@Sun.COM 	int ret;
6977917SReza.Sabdar@Sun.COM 
6987917SReza.Sabdar@Sun.COM 	(void) memset((void*)&reply, 0, sizeof (reply));
6997917SReza.Sabdar@Sun.COM 
7007917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
7017917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
7027917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
7037917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
7047917SReza.Sabdar@Sun.COM 		    "sending mover_continue reply");
7057917SReza.Sabdar@Sun.COM 		return;
7067917SReza.Sabdar@Sun.COM 	}
7077917SReza.Sabdar@Sun.COM 
7087917SReza.Sabdar@Sun.COM 	if (session->ns_protocol_version == NDMPV4 &&
7097917SReza.Sabdar@Sun.COM 	    !session->ns_mover.md_pre_cond) {
7107917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Precondition check");
7117917SReza.Sabdar@Sun.COM 		reply.error = NDMP_PRECONDITION_ERR;
7127917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
7137917SReza.Sabdar@Sun.COM 		    "sending mover_continue reply");
7147917SReza.Sabdar@Sun.COM 		return;
7157917SReza.Sabdar@Sun.COM 	}
7167917SReza.Sabdar@Sun.COM 	/*
7177917SReza.Sabdar@Sun.COM 	 * Restore the file handler if the mover is remote to the data
7187917SReza.Sabdar@Sun.COM 	 * server and the handler was removed pending the continuation of a
7197917SReza.Sabdar@Sun.COM 	 * seek request. The handler is removed in mover_data_write().
7207917SReza.Sabdar@Sun.COM 	 */
7217917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
7227917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_sock != -1) {
7237917SReza.Sabdar@Sun.COM 		/*
7247917SReza.Sabdar@Sun.COM 		 * If we are here, it means that we needed DMA interference
7257917SReza.Sabdar@Sun.COM 		 * for seek. We should be on the right window, so we do not
7267917SReza.Sabdar@Sun.COM 		 * need the DMA interference anymore.
7277917SReza.Sabdar@Sun.COM 		 * We do another seek inside the Window to move to the
7287917SReza.Sabdar@Sun.COM 		 * exact position on the tape.
7297917SReza.Sabdar@Sun.COM 		 * If the resore is running without DAR the pause reason should
7307917SReza.Sabdar@Sun.COM 		 * not be seek.
7317917SReza.Sabdar@Sun.COM 		 */
7327917SReza.Sabdar@Sun.COM 		ret = ndmpd_mover_seek(session,
7337917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_seek_position,
7347917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_bytes_left_to_read);
7357917SReza.Sabdar@Sun.COM 		if (ret < 0) {
7367917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
7377917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
7387917SReza.Sabdar@Sun.COM 			return;
7397917SReza.Sabdar@Sun.COM 		}
7407917SReza.Sabdar@Sun.COM 
7417917SReza.Sabdar@Sun.COM 		if (!ret) {
7427917SReza.Sabdar@Sun.COM 			if (ndmpd_add_file_handler(session, (void*) session,
7437917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
7447917SReza.Sabdar@Sun.COM 			    HC_MOVER, mover_data_write_v3) < 0)
7457917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
7467917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
7477917SReza.Sabdar@Sun.COM 		} else {
7487917SReza.Sabdar@Sun.COM 			/*
7497917SReza.Sabdar@Sun.COM 			 * This should not happen because we should be in the
7507917SReza.Sabdar@Sun.COM 			 * right window. This means that DMA does not follow
7517917SReza.Sabdar@Sun.COM 			 * the V3 spec.
7527917SReza.Sabdar@Sun.COM 			 */
7537917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "DMA Error.");
7547917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
7557917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
7567917SReza.Sabdar@Sun.COM 			return;
7577917SReza.Sabdar@Sun.COM 		}
7587917SReza.Sabdar@Sun.COM 	}
7597917SReza.Sabdar@Sun.COM 
7607917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
7617917SReza.Sabdar@Sun.COM 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
7627917SReza.Sabdar@Sun.COM 
7637917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
7647917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
7657917SReza.Sabdar@Sun.COM 	    "sending mover_continue reply");
7667917SReza.Sabdar@Sun.COM }
7677917SReza.Sabdar@Sun.COM 
7687917SReza.Sabdar@Sun.COM 
7697917SReza.Sabdar@Sun.COM /*
7707917SReza.Sabdar@Sun.COM  * ndmpd_mover_abort_v3
7717917SReza.Sabdar@Sun.COM  *
7727917SReza.Sabdar@Sun.COM  * This handler handles mover_abort requests.
7737917SReza.Sabdar@Sun.COM  *
7747917SReza.Sabdar@Sun.COM  * Parameters:
7757917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
7767917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
7777917SReza.Sabdar@Sun.COM  *
7787917SReza.Sabdar@Sun.COM  * Returns:
7797917SReza.Sabdar@Sun.COM  *   void
7807917SReza.Sabdar@Sun.COM  */
7817917SReza.Sabdar@Sun.COM /*ARGSUSED*/
7827917SReza.Sabdar@Sun.COM void
7837917SReza.Sabdar@Sun.COM ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
7847917SReza.Sabdar@Sun.COM {
7857917SReza.Sabdar@Sun.COM 	ndmp_mover_abort_reply reply;
7867917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
7877917SReza.Sabdar@Sun.COM 
7887917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
7897917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
7907917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
7917917SReza.Sabdar@Sun.COM 
7927917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
7937917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
7947917SReza.Sabdar@Sun.COM 		    "sending mover_abort reply");
7957917SReza.Sabdar@Sun.COM 		return;
7967917SReza.Sabdar@Sun.COM 	}
7977917SReza.Sabdar@Sun.COM 
7987917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
7997917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
8007917SReza.Sabdar@Sun.COM 	    "sending mover_abort reply");
8017917SReza.Sabdar@Sun.COM 
8027917SReza.Sabdar@Sun.COM 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
8037917SReza.Sabdar@Sun.COM }
8047917SReza.Sabdar@Sun.COM 
8057917SReza.Sabdar@Sun.COM 
8067917SReza.Sabdar@Sun.COM /*
8077917SReza.Sabdar@Sun.COM  * ndmpd_mover_set_window_v3
8087917SReza.Sabdar@Sun.COM  *
8097917SReza.Sabdar@Sun.COM  * This handler handles mover_set_window requests.
8107917SReza.Sabdar@Sun.COM  *
8117917SReza.Sabdar@Sun.COM  *
8127917SReza.Sabdar@Sun.COM  * Parameters:
8137917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
8147917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
8157917SReza.Sabdar@Sun.COM  *
8167917SReza.Sabdar@Sun.COM  * Returns:
8177917SReza.Sabdar@Sun.COM  *   void
8187917SReza.Sabdar@Sun.COM  */
8197917SReza.Sabdar@Sun.COM void
8207917SReza.Sabdar@Sun.COM ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
8217917SReza.Sabdar@Sun.COM {
8227917SReza.Sabdar@Sun.COM 	ndmp_mover_set_window_request *request;
8237917SReza.Sabdar@Sun.COM 	ndmp_mover_set_window_reply reply;
8247917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
8257917SReza.Sabdar@Sun.COM 
8267917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_set_window_request *) body;
8277917SReza.Sabdar@Sun.COM 
8287917SReza.Sabdar@Sun.COM 	/*
8297917SReza.Sabdar@Sun.COM 	 * Note: The spec says that the window can be set only in the listen
8307917SReza.Sabdar@Sun.COM 	 * and paused states.  We let this happen when mover is in the idle
8317917SReza.Sabdar@Sun.COM 	 * state as well.  I can't rememebr which NDMP client (net_backup 4.5
8327917SReza.Sabdar@Sun.COM 	 * or net_worker 6.1.1) forced us to do this!
8337917SReza.Sabdar@Sun.COM 	 */
8347917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
8357917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
8367917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
8377917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
8387917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
8397917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_state);
8407917SReza.Sabdar@Sun.COM 	} else if (session->ns_mover.md_record_size == 0) {
8417917SReza.Sabdar@Sun.COM 		if (session->ns_protocol_version == NDMPV4)
8427917SReza.Sabdar@Sun.COM 			reply.error = NDMP_PRECONDITION_ERR;
8437917SReza.Sabdar@Sun.COM 		else
8447917SReza.Sabdar@Sun.COM 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
8457917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
8467917SReza.Sabdar@Sun.COM 	} else
8477917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
8487917SReza.Sabdar@Sun.COM 
8497917SReza.Sabdar@Sun.COM 	if (quad_to_long_long(request->length) == 0) {
8507917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
8517917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
8527917SReza.Sabdar@Sun.COM 		    quad_to_long_long(request->length));
8537917SReza.Sabdar@Sun.COM 	}
8547917SReza.Sabdar@Sun.COM 
8557917SReza.Sabdar@Sun.COM 	if (reply.error != NDMP_NO_ERR) {
8567917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
8577917SReza.Sabdar@Sun.COM 		    "sending mover_set_window_v3 reply");
8587917SReza.Sabdar@Sun.COM 		return;
8597917SReza.Sabdar@Sun.COM 	}
8607917SReza.Sabdar@Sun.COM 
8617917SReza.Sabdar@Sun.COM 	session->ns_mover.md_pre_cond = TRUE;
8627917SReza.Sabdar@Sun.COM 	session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
8637917SReza.Sabdar@Sun.COM 	session->ns_mover.md_window_length = quad_to_long_long(request->length);
8647917SReza.Sabdar@Sun.COM 
8657917SReza.Sabdar@Sun.COM 	/*
8667917SReza.Sabdar@Sun.COM 	 * We have to update the position for DAR. DAR needs this
8677917SReza.Sabdar@Sun.COM 	 * information to position to the right index on tape,
8687917SReza.Sabdar@Sun.COM 	 * especially when we span the tapes.
8697917SReza.Sabdar@Sun.COM 	 */
8707917SReza.Sabdar@Sun.COM #ifdef	NO_POSITION_CHANGE
8717917SReza.Sabdar@Sun.COM 	/*
8727917SReza.Sabdar@Sun.COM 	 * Do not change the mover position if we are reading from
8737917SReza.Sabdar@Sun.COM 	 * the tape.  In this way, we can use the position+window_length
8747917SReza.Sabdar@Sun.COM 	 * to know how much we can write to a tape before pausing with
8757917SReza.Sabdar@Sun.COM 	 * EOW reason.
8767917SReza.Sabdar@Sun.COM 	 */
8777917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE)
8787917SReza.Sabdar@Sun.COM #endif	/* NO_POSITION_CHANGE */
8797917SReza.Sabdar@Sun.COM 		session->ns_mover.md_position =
8807917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_offset;
8817917SReza.Sabdar@Sun.COM 
8827917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
8837917SReza.Sabdar@Sun.COM 	    "sending mover_set_window_v3 reply");
8847917SReza.Sabdar@Sun.COM }
8857917SReza.Sabdar@Sun.COM 
8867917SReza.Sabdar@Sun.COM 
8877917SReza.Sabdar@Sun.COM /*
8887917SReza.Sabdar@Sun.COM  * ndmpd_mover_read_v3
8897917SReza.Sabdar@Sun.COM  *
8907917SReza.Sabdar@Sun.COM  * This handler handles ndmp_mover_read_requests.
8917917SReza.Sabdar@Sun.COM  * If the requested offset is outside of the current window, the mover
8927917SReza.Sabdar@Sun.COM  * is paused and a notify_mover_paused request is sent notifying the
8937917SReza.Sabdar@Sun.COM  * client that a seek is required. If the requested offest is within
8947917SReza.Sabdar@Sun.COM  * the window but not within the current record, then the tape is
8957917SReza.Sabdar@Sun.COM  * positioned to the record containing the requested offest. The requested
8967917SReza.Sabdar@Sun.COM  * amount of data is then read from the tape device and written to the
8977917SReza.Sabdar@Sun.COM  * data connection.
8987917SReza.Sabdar@Sun.COM  *
8997917SReza.Sabdar@Sun.COM  * Parameters:
9007917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
9017917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
9027917SReza.Sabdar@Sun.COM  *
9037917SReza.Sabdar@Sun.COM  * Returns:
9047917SReza.Sabdar@Sun.COM  *   void
9057917SReza.Sabdar@Sun.COM  */
9067917SReza.Sabdar@Sun.COM void
9077917SReza.Sabdar@Sun.COM ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
9087917SReza.Sabdar@Sun.COM {
9097917SReza.Sabdar@Sun.COM 	ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
9107917SReza.Sabdar@Sun.COM 	ndmp_mover_read_reply reply;
9117917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
9127917SReza.Sabdar@Sun.COM 	int err;
9137917SReza.Sabdar@Sun.COM 
9147917SReza.Sabdar@Sun.COM 	(void) memset((void*)&reply, 0, sizeof (reply));
9157917SReza.Sabdar@Sun.COM 
9167917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
9177917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
9187917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
9197917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state");
9207917SReza.Sabdar@Sun.COM 	} else if (session->ns_mover.md_bytes_left_to_read != 0) {
9217917SReza.Sabdar@Sun.COM 		reply.error = NDMP_READ_IN_PROGRESS_ERR;
9227917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "In progress");
9237917SReza.Sabdar@Sun.COM 	} else if (session->ns_tape.td_fd == -1) {
9247917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
9257917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
9267917SReza.Sabdar@Sun.COM 	} else if (quad_to_long_long(request->length) == 0 ||
9277917SReza.Sabdar@Sun.COM 	    (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
9287917SReza.Sabdar@Sun.COM 	    quad_to_long_long(request->offset) != 0)) {
9297917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
9307917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Illegal args");
9317917SReza.Sabdar@Sun.COM 	} else {
9327917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
9337917SReza.Sabdar@Sun.COM 	}
9347917SReza.Sabdar@Sun.COM 
9357917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
9367917SReza.Sabdar@Sun.COM 	    "sending ndmp_mover_read_reply");
9377917SReza.Sabdar@Sun.COM 	if (reply.error != NDMP_NO_ERR)
9387917SReza.Sabdar@Sun.COM 		return;
9397917SReza.Sabdar@Sun.COM 
9407917SReza.Sabdar@Sun.COM 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
9417917SReza.Sabdar@Sun.COM 	    quad_to_long_long(request->length));
9427917SReza.Sabdar@Sun.COM 	if (err < 0) {
9437917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
9447917SReza.Sabdar@Sun.COM 		return;
9457917SReza.Sabdar@Sun.COM 	}
9467917SReza.Sabdar@Sun.COM 
9477917SReza.Sabdar@Sun.COM 	/*
9487917SReza.Sabdar@Sun.COM 	 * Just return if we are waiting for the DMA to complete the seek.
9497917SReza.Sabdar@Sun.COM 	 */
9507917SReza.Sabdar@Sun.COM 	if (err == 1)
9517917SReza.Sabdar@Sun.COM 		return;
9527917SReza.Sabdar@Sun.COM 
9537917SReza.Sabdar@Sun.COM 	/*
9547917SReza.Sabdar@Sun.COM 	 * Setup a handler function that will be called when
9557917SReza.Sabdar@Sun.COM 	 * data can be written to the data connection without blocking.
9567917SReza.Sabdar@Sun.COM 	 */
9577917SReza.Sabdar@Sun.COM 	if (ndmpd_add_file_handler(session, (void*)session,
9587917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE, HC_MOVER,
9597917SReza.Sabdar@Sun.COM 	    mover_data_write_v3) < 0) {
9607917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
9617917SReza.Sabdar@Sun.COM 		return;
9627917SReza.Sabdar@Sun.COM 	}
9637917SReza.Sabdar@Sun.COM }
9647917SReza.Sabdar@Sun.COM 
9657917SReza.Sabdar@Sun.COM 
9667917SReza.Sabdar@Sun.COM /*
9677917SReza.Sabdar@Sun.COM  * ndmpd_mover_set_record_size_v3
9687917SReza.Sabdar@Sun.COM  *
9697917SReza.Sabdar@Sun.COM  * This handler handles mover_set_record_size requests.
9707917SReza.Sabdar@Sun.COM  *
9717917SReza.Sabdar@Sun.COM  * Parameters:
9727917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
9737917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
9747917SReza.Sabdar@Sun.COM  *
9757917SReza.Sabdar@Sun.COM  * Returns:
9767917SReza.Sabdar@Sun.COM  *   void
9777917SReza.Sabdar@Sun.COM  */
9787917SReza.Sabdar@Sun.COM void
9797917SReza.Sabdar@Sun.COM ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
9807917SReza.Sabdar@Sun.COM {
9817917SReza.Sabdar@Sun.COM 	ndmp_mover_set_record_size_request *request;
9827917SReza.Sabdar@Sun.COM 	ndmp_mover_set_record_size_reply reply;
9837917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
9847917SReza.Sabdar@Sun.COM 	char *cp;
9857917SReza.Sabdar@Sun.COM 
9867917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_set_record_size_request *) body;
9877917SReza.Sabdar@Sun.COM 
9887917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
9897917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
9907917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid mover state %d",
9917917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_state);
9927917SReza.Sabdar@Sun.COM 	} else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
9937917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
9947917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
9957917SReza.Sabdar@Sun.COM 		    "Invalid argument %d, should be > 0 and <= %d",
9967917SReza.Sabdar@Sun.COM 		    request->len, ndmp_max_mover_recsize);
9977917SReza.Sabdar@Sun.COM 	} else if (request->len == session->ns_mover.md_record_size)
9987917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
9997917SReza.Sabdar@Sun.COM 	else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
10007917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_MEM_ERR;
10017917SReza.Sabdar@Sun.COM 	} else {
10027917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
10037917SReza.Sabdar@Sun.COM 		session->ns_mover.md_buf = cp;
10047917SReza.Sabdar@Sun.COM 		session->ns_mover.md_record_size = request->len;
10057917SReza.Sabdar@Sun.COM 		session->ns_mover.md_window_offset = 0;
10067917SReza.Sabdar@Sun.COM 		session->ns_mover.md_window_length = 0;
10077917SReza.Sabdar@Sun.COM 	}
10087917SReza.Sabdar@Sun.COM 
10097917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
10107917SReza.Sabdar@Sun.COM 	    "sending mover_set_record_size reply");
10117917SReza.Sabdar@Sun.COM }
10127917SReza.Sabdar@Sun.COM 
10137917SReza.Sabdar@Sun.COM 
10147917SReza.Sabdar@Sun.COM /*
10157917SReza.Sabdar@Sun.COM  * ndmpd_mover_connect_v3
10167917SReza.Sabdar@Sun.COM  *   Request handler. Connects the mover to either a local
10177917SReza.Sabdar@Sun.COM  *   or remote data server.
10187917SReza.Sabdar@Sun.COM  *
10197917SReza.Sabdar@Sun.COM  * Parameters:
10207917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
10217917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
10227917SReza.Sabdar@Sun.COM  *
10237917SReza.Sabdar@Sun.COM  * Returns:
10247917SReza.Sabdar@Sun.COM  *   void
10257917SReza.Sabdar@Sun.COM  */
10267917SReza.Sabdar@Sun.COM void
10277917SReza.Sabdar@Sun.COM ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
10287917SReza.Sabdar@Sun.COM {
10297917SReza.Sabdar@Sun.COM 	ndmp_mover_connect_request_v3 *request;
10307917SReza.Sabdar@Sun.COM 	ndmp_mover_connect_reply_v3 reply;
10317917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
10327917SReza.Sabdar@Sun.COM 
10337917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_connect_request_v3*)body;
10347917SReza.Sabdar@Sun.COM 
10357917SReza.Sabdar@Sun.COM 	(void) memset((void*)&reply, 0, sizeof (reply));
10367917SReza.Sabdar@Sun.COM 
10377917SReza.Sabdar@Sun.COM 	if (request->mode != NDMP_MOVER_MODE_READ &&
10387917SReza.Sabdar@Sun.COM 	    request->mode != NDMP_MOVER_MODE_WRITE) {
10397917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10407917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
10417917SReza.Sabdar@Sun.COM 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
10427917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10437917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
10447917SReza.Sabdar@Sun.COM 		    request->addr.addr_type);
10457917SReza.Sabdar@Sun.COM 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
10467917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
10477917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
10487917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_state);
10497917SReza.Sabdar@Sun.COM 	} else if (session->ns_tape.td_fd == -1) {
10507917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
10517917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "No tape device open");
10527917SReza.Sabdar@Sun.COM 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
10537917SReza.Sabdar@Sun.COM 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
10547917SReza.Sabdar@Sun.COM 		reply.error = NDMP_WRITE_PROTECT_ERR;
10557917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Write protected device.");
10567917SReza.Sabdar@Sun.COM 	} else
10577917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
10587917SReza.Sabdar@Sun.COM 
10597917SReza.Sabdar@Sun.COM 	if (reply.error != NDMP_NO_ERR) {
10607917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
10617917SReza.Sabdar@Sun.COM 		    "sending ndmp_mover_connect reply");
10627917SReza.Sabdar@Sun.COM 		return;
10637917SReza.Sabdar@Sun.COM 	}
10647917SReza.Sabdar@Sun.COM 
10657917SReza.Sabdar@Sun.COM 	switch (request->addr.addr_type) {
10667917SReza.Sabdar@Sun.COM 	case NDMP_ADDR_LOCAL:
10677917SReza.Sabdar@Sun.COM 		/*
10687917SReza.Sabdar@Sun.COM 		 * Verify that the data server is listening for a
10697917SReza.Sabdar@Sun.COM 		 * local connection.
10707917SReza.Sabdar@Sun.COM 		 */
10717917SReza.Sabdar@Sun.COM 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
10727917SReza.Sabdar@Sun.COM 		    session->ns_data.dd_listen_sock != -1) {
10737917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
10747917SReza.Sabdar@Sun.COM 			    "Data server is not in local listen state");
10757917SReza.Sabdar@Sun.COM 			reply.error = NDMP_ILLEGAL_STATE_ERR;
10767917SReza.Sabdar@Sun.COM 		} else
10777917SReza.Sabdar@Sun.COM 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
10787917SReza.Sabdar@Sun.COM 		break;
10797917SReza.Sabdar@Sun.COM 
10807917SReza.Sabdar@Sun.COM 	case NDMP_ADDR_TCP:
10817917SReza.Sabdar@Sun.COM 		reply.error = mover_connect_sock_v3(session, request->mode,
10827917SReza.Sabdar@Sun.COM 		    request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
10837917SReza.Sabdar@Sun.COM 		break;
10847917SReza.Sabdar@Sun.COM 
10857917SReza.Sabdar@Sun.COM 	default:
10867917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10877917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
10887917SReza.Sabdar@Sun.COM 		    request->addr.addr_type);
10897917SReza.Sabdar@Sun.COM 	}
10907917SReza.Sabdar@Sun.COM 
10917917SReza.Sabdar@Sun.COM 	if (reply.error == NDMP_NO_ERR) {
10927917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.addr_type =
10937917SReza.Sabdar@Sun.COM 		    request->addr.addr_type;
10947917SReza.Sabdar@Sun.COM 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
10957917SReza.Sabdar@Sun.COM 		session->ns_mover.md_mode = request->mode;
10967917SReza.Sabdar@Sun.COM 	}
10977917SReza.Sabdar@Sun.COM 
10987917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
10997917SReza.Sabdar@Sun.COM 	    "sending ndmp_mover_connect reply");
11007917SReza.Sabdar@Sun.COM }
11017917SReza.Sabdar@Sun.COM 
11027917SReza.Sabdar@Sun.COM 
11037917SReza.Sabdar@Sun.COM /*
11047917SReza.Sabdar@Sun.COM  * ************************************************************************
11057917SReza.Sabdar@Sun.COM  * NDMP V4 HANDLERS
11067917SReza.Sabdar@Sun.COM  * ************************************************************************
11077917SReza.Sabdar@Sun.COM  */
11087917SReza.Sabdar@Sun.COM 
11097917SReza.Sabdar@Sun.COM /*
11107917SReza.Sabdar@Sun.COM  * ndmpd_mover_get_state_v4
11117917SReza.Sabdar@Sun.COM  *
11127917SReza.Sabdar@Sun.COM  * This handler handles the ndmp_mover_get_state_request.
11137917SReza.Sabdar@Sun.COM  * Status information for the mover state machine is returned.
11147917SReza.Sabdar@Sun.COM  *
11157917SReza.Sabdar@Sun.COM  * Parameters:
11167917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
11177917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
11187917SReza.Sabdar@Sun.COM  *
11197917SReza.Sabdar@Sun.COM  * Returns:
11207917SReza.Sabdar@Sun.COM  *   void
11217917SReza.Sabdar@Sun.COM  */
11227917SReza.Sabdar@Sun.COM /*ARGSUSED*/
11237917SReza.Sabdar@Sun.COM void
11247917SReza.Sabdar@Sun.COM ndmpd_mover_get_state_v4(ndmp_connection_t *connection, void *body)
11257917SReza.Sabdar@Sun.COM {
11267917SReza.Sabdar@Sun.COM 	ndmp_mover_get_state_reply_v4 reply;
11277917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
11287917SReza.Sabdar@Sun.COM 
11297917SReza.Sabdar@Sun.COM 	(void) memset((void*)&reply, 0, sizeof (reply));
11307917SReza.Sabdar@Sun.COM 
11317917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
11327917SReza.Sabdar@Sun.COM 	reply.state = session->ns_mover.md_state;
11337917SReza.Sabdar@Sun.COM 	reply.mode = session->ns_mover.md_mode;
11347917SReza.Sabdar@Sun.COM 	reply.pause_reason = session->ns_mover.md_pause_reason;
11357917SReza.Sabdar@Sun.COM 	reply.halt_reason = session->ns_mover.md_halt_reason;
11367917SReza.Sabdar@Sun.COM 	reply.record_size = session->ns_mover.md_record_size;
11377917SReza.Sabdar@Sun.COM 	reply.record_num = session->ns_mover.md_record_num;
11387917SReza.Sabdar@Sun.COM 	reply.bytes_moved =
11397917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_data_written);
11407917SReza.Sabdar@Sun.COM 	reply.seek_position =
11417917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_seek_position);
11427917SReza.Sabdar@Sun.COM 	reply.bytes_left_to_read =
11437917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
11447917SReza.Sabdar@Sun.COM 	reply.window_offset =
11457917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_window_offset);
11467917SReza.Sabdar@Sun.COM 	reply.window_length =
11477917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_window_length);
11487917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
11497917SReza.Sabdar@Sun.COM 		ndmp_copy_addr_v4(&reply.data_connection_addr,
11507917SReza.Sabdar@Sun.COM 		    &session->ns_mover.md_data_addr_v4);
11517917SReza.Sabdar@Sun.COM 
11527917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
11537917SReza.Sabdar@Sun.COM 	    "sending ndmp_mover_get_state reply");
11547917SReza.Sabdar@Sun.COM 	free(reply.data_connection_addr.tcp_addr_v4);
11557917SReza.Sabdar@Sun.COM }
11567917SReza.Sabdar@Sun.COM 
11577917SReza.Sabdar@Sun.COM 
11587917SReza.Sabdar@Sun.COM /*
11597917SReza.Sabdar@Sun.COM  * ndmpd_mover_listen_v4
11607917SReza.Sabdar@Sun.COM  *
11617917SReza.Sabdar@Sun.COM  * This handler handles ndmp_mover_listen_requests.
11627917SReza.Sabdar@Sun.COM  * A TCP/IP socket is created that is used to listen for
11637917SReza.Sabdar@Sun.COM  * and accept data connections initiated by a remote
11647917SReza.Sabdar@Sun.COM  * data server.
11657917SReza.Sabdar@Sun.COM  *
11667917SReza.Sabdar@Sun.COM  * Parameters:
11677917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
11687917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
11697917SReza.Sabdar@Sun.COM  *
11707917SReza.Sabdar@Sun.COM  * Returns:
11717917SReza.Sabdar@Sun.COM  *   void
11727917SReza.Sabdar@Sun.COM  */
11737917SReza.Sabdar@Sun.COM void
11747917SReza.Sabdar@Sun.COM ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
11757917SReza.Sabdar@Sun.COM {
11767917SReza.Sabdar@Sun.COM 	ndmp_mover_listen_request_v4 *request;
11777917SReza.Sabdar@Sun.COM 
11787917SReza.Sabdar@Sun.COM 	ndmp_mover_listen_reply_v4 reply;
11797917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
11807917SReza.Sabdar@Sun.COM 	ulong_t addr;
11817917SReza.Sabdar@Sun.COM 	ushort_t port;
11827917SReza.Sabdar@Sun.COM 
11837917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_listen_request_v4 *)body;
11847917SReza.Sabdar@Sun.COM 
11857917SReza.Sabdar@Sun.COM 	(void) memset((void*)&reply, 0, sizeof (reply));
11867917SReza.Sabdar@Sun.COM 	reply.error = NDMP_NO_ERR;
11877917SReza.Sabdar@Sun.COM 
11887917SReza.Sabdar@Sun.COM 	if (request->mode != NDMP_MOVER_MODE_READ &&
11897917SReza.Sabdar@Sun.COM 	    request->mode != NDMP_MOVER_MODE_WRITE) {
11907917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
11917917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
11927917SReza.Sabdar@Sun.COM 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
11937917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
11947917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
11957917SReza.Sabdar@Sun.COM 		    request->addr_type);
11967917SReza.Sabdar@Sun.COM 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
11977917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
11987917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
11997917SReza.Sabdar@Sun.COM 		    "Invalid mover state to process listen request");
12007917SReza.Sabdar@Sun.COM 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
12017917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
12027917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
12037917SReza.Sabdar@Sun.COM 		    "Invalid data state to process listen request");
12047917SReza.Sabdar@Sun.COM 	} else if (session->ns_tape.td_fd == -1) {
12057917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
12067917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "No tape device open");
12077917SReza.Sabdar@Sun.COM 	} else if (session->ns_mover.md_record_size == 0) {
12087917SReza.Sabdar@Sun.COM 		reply.error = NDMP_PRECONDITION_ERR;
12097917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
12107917SReza.Sabdar@Sun.COM 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
12117917SReza.Sabdar@Sun.COM 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
12127917SReza.Sabdar@Sun.COM 		reply.error = NDMP_PERMISSION_ERR;
12137917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Write protected device.");
12147917SReza.Sabdar@Sun.COM 	}
12157917SReza.Sabdar@Sun.COM 
12167917SReza.Sabdar@Sun.COM 	if (reply.error != NDMP_NO_ERR) {
12177917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
12187917SReza.Sabdar@Sun.COM 		    "error sending ndmp_mover_listen reply");
12197917SReza.Sabdar@Sun.COM 		return;
12207917SReza.Sabdar@Sun.COM 	}
12217917SReza.Sabdar@Sun.COM 
12227917SReza.Sabdar@Sun.COM 	switch (request->addr_type) {
12237917SReza.Sabdar@Sun.COM 	case NDMP_ADDR_LOCAL:
12247917SReza.Sabdar@Sun.COM 		reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
12257917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
12267917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
12277917SReza.Sabdar@Sun.COM 		break;
12287917SReza.Sabdar@Sun.COM 	case NDMP_ADDR_TCP:
12297917SReza.Sabdar@Sun.COM 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
12307917SReza.Sabdar@Sun.COM 			reply.error = NDMP_IO_ERR;
12317917SReza.Sabdar@Sun.COM 			break;
12327917SReza.Sabdar@Sun.COM 		}
12337917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
12347917SReza.Sabdar@Sun.COM 
12357917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
12367917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
12377917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
12387917SReza.Sabdar@Sun.COM 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
12397917SReza.Sabdar@Sun.COM 
12407917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
12417917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
12427917SReza.Sabdar@Sun.COM 
12437917SReza.Sabdar@Sun.COM 		ndmp_copy_addr_v4(&reply.connect_addr,
12447917SReza.Sabdar@Sun.COM 		    &session->ns_mover.md_data_addr_v4);
12457917SReza.Sabdar@Sun.COM 
12467917SReza.Sabdar@Sun.COM 		/* For compatibility with V3 */
12477917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
12487917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
12497917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
12507917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
12517917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_listen_sock);
12527917SReza.Sabdar@Sun.COM 		break;
12537917SReza.Sabdar@Sun.COM 	default:
12547917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
12557917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
12567917SReza.Sabdar@Sun.COM 		    request->addr_type);
12577917SReza.Sabdar@Sun.COM 	}
12587917SReza.Sabdar@Sun.COM 
12597917SReza.Sabdar@Sun.COM 	if (reply.error == NDMP_NO_ERR) {
12607917SReza.Sabdar@Sun.COM 		session->ns_mover.md_mode = request->mode;
12617917SReza.Sabdar@Sun.COM 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
12627917SReza.Sabdar@Sun.COM 	}
12637917SReza.Sabdar@Sun.COM 
12647917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
12657917SReza.Sabdar@Sun.COM 	    "error sending ndmp_mover_listen reply");
12667917SReza.Sabdar@Sun.COM 	free(reply.connect_addr.tcp_addr_v4);
12677917SReza.Sabdar@Sun.COM }
12687917SReza.Sabdar@Sun.COM 
12697917SReza.Sabdar@Sun.COM /*
12707917SReza.Sabdar@Sun.COM  * ndmpd_mover_connect_v4
12717917SReza.Sabdar@Sun.COM  *   Request handler. Connects the mover to either a local
12727917SReza.Sabdar@Sun.COM  *   or remote data server.
12737917SReza.Sabdar@Sun.COM  *
12747917SReza.Sabdar@Sun.COM  * Parameters:
12757917SReza.Sabdar@Sun.COM  *   connection (input) - connection handle.
12767917SReza.Sabdar@Sun.COM  *   body       (input) - request message body.
12777917SReza.Sabdar@Sun.COM  *
12787917SReza.Sabdar@Sun.COM  * Returns:
12797917SReza.Sabdar@Sun.COM  *   void
12807917SReza.Sabdar@Sun.COM  */
12817917SReza.Sabdar@Sun.COM void
12827917SReza.Sabdar@Sun.COM ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
12837917SReza.Sabdar@Sun.COM {
12847917SReza.Sabdar@Sun.COM 	ndmp_mover_connect_request_v4 *request;
12857917SReza.Sabdar@Sun.COM 	ndmp_mover_connect_reply_v4 reply;
12867917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = ndmp_get_client_data(connection);
12877917SReza.Sabdar@Sun.COM 
12887917SReza.Sabdar@Sun.COM 	request = (ndmp_mover_connect_request_v4 *)body;
12897917SReza.Sabdar@Sun.COM 	(void) memset((void*)&reply, 0, sizeof (reply));
12907917SReza.Sabdar@Sun.COM 
12917917SReza.Sabdar@Sun.COM 	if (request->mode != NDMP_MOVER_MODE_READ &&
12927917SReza.Sabdar@Sun.COM 	    request->mode != NDMP_MOVER_MODE_WRITE) {
12937917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
12947917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
12957917SReza.Sabdar@Sun.COM 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
12967917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
12977917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
12987917SReza.Sabdar@Sun.COM 		    request->addr.addr_type);
12997917SReza.Sabdar@Sun.COM 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
13007917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_STATE_ERR;
13017917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
13027917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_state);
13037917SReza.Sabdar@Sun.COM 	} else if (session->ns_tape.td_fd == -1) {
13047917SReza.Sabdar@Sun.COM 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
13057917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "No tape device open");
13067917SReza.Sabdar@Sun.COM 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
13077917SReza.Sabdar@Sun.COM 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
13087917SReza.Sabdar@Sun.COM 		reply.error = NDMP_PERMISSION_ERR;
13097917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Write protected device.");
13107917SReza.Sabdar@Sun.COM 	} else if (session->ns_mover.md_record_size == 0) {
13117917SReza.Sabdar@Sun.COM 		reply.error = NDMP_PRECONDITION_ERR;
13127917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
13137917SReza.Sabdar@Sun.COM 	} else
13147917SReza.Sabdar@Sun.COM 		reply.error = NDMP_NO_ERR;
13157917SReza.Sabdar@Sun.COM 
13167917SReza.Sabdar@Sun.COM 	if (reply.error != NDMP_NO_ERR) {
13177917SReza.Sabdar@Sun.COM 		ndmp_send_reply(connection, (void *) &reply,
13187917SReza.Sabdar@Sun.COM 		    "sending ndmp_mover_connect reply");
13197917SReza.Sabdar@Sun.COM 		return;
13207917SReza.Sabdar@Sun.COM 	}
13217917SReza.Sabdar@Sun.COM 
13227917SReza.Sabdar@Sun.COM 	switch (request->addr.addr_type) {
13237917SReza.Sabdar@Sun.COM 	case NDMP_ADDR_LOCAL:
13247917SReza.Sabdar@Sun.COM 		/*
13257917SReza.Sabdar@Sun.COM 		 * Verify that the data server is listening for a
13267917SReza.Sabdar@Sun.COM 		 * local connection.
13277917SReza.Sabdar@Sun.COM 		 */
13287917SReza.Sabdar@Sun.COM 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
13297917SReza.Sabdar@Sun.COM 		    session->ns_data.dd_listen_sock != -1) {
13307917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
13317917SReza.Sabdar@Sun.COM 			    "Data server is not in local listen state");
13327917SReza.Sabdar@Sun.COM 			reply.error = NDMP_ILLEGAL_STATE_ERR;
13337917SReza.Sabdar@Sun.COM 		} else
13347917SReza.Sabdar@Sun.COM 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
13357917SReza.Sabdar@Sun.COM 		break;
13367917SReza.Sabdar@Sun.COM 
13377917SReza.Sabdar@Sun.COM 	case NDMP_ADDR_TCP:
13387917SReza.Sabdar@Sun.COM 		reply.error = mover_connect_sock_v3(session, request->mode,
13397917SReza.Sabdar@Sun.COM 		    request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
13407917SReza.Sabdar@Sun.COM 		break;
13417917SReza.Sabdar@Sun.COM 
13427917SReza.Sabdar@Sun.COM 	default:
13437917SReza.Sabdar@Sun.COM 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
13447917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
13457917SReza.Sabdar@Sun.COM 		    request->addr.addr_type);
13467917SReza.Sabdar@Sun.COM 	}
13477917SReza.Sabdar@Sun.COM 
13487917SReza.Sabdar@Sun.COM 	if (reply.error == NDMP_NO_ERR) {
13497917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_addr.addr_type =
13507917SReza.Sabdar@Sun.COM 		    request->addr.addr_type;
13517917SReza.Sabdar@Sun.COM 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
13527917SReza.Sabdar@Sun.COM 		session->ns_mover.md_mode = request->mode;
13537917SReza.Sabdar@Sun.COM 	}
13547917SReza.Sabdar@Sun.COM 
13557917SReza.Sabdar@Sun.COM 	ndmp_send_reply(connection, (void *) &reply,
13567917SReza.Sabdar@Sun.COM 	    "sending ndmp_mover_connect reply");
13577917SReza.Sabdar@Sun.COM }
13587917SReza.Sabdar@Sun.COM 
13597917SReza.Sabdar@Sun.COM 
13607917SReza.Sabdar@Sun.COM 
13617917SReza.Sabdar@Sun.COM /*
13627917SReza.Sabdar@Sun.COM  * ************************************************************************
13637917SReza.Sabdar@Sun.COM  * LOCALS
13647917SReza.Sabdar@Sun.COM  * ************************************************************************
13657917SReza.Sabdar@Sun.COM  */
13667917SReza.Sabdar@Sun.COM 
13677917SReza.Sabdar@Sun.COM /*
13687917SReza.Sabdar@Sun.COM  * ndmpd_write_eom
13697917SReza.Sabdar@Sun.COM  *
13707917SReza.Sabdar@Sun.COM  * Write end-of-media magic string.  This is called after hitting the LEOT.
13717917SReza.Sabdar@Sun.COM  */
13727917SReza.Sabdar@Sun.COM void
13737917SReza.Sabdar@Sun.COM ndmpd_write_eom(int fd)
13747917SReza.Sabdar@Sun.COM {
13757917SReza.Sabdar@Sun.COM 	int n;
13767917SReza.Sabdar@Sun.COM 
13777917SReza.Sabdar@Sun.COM 	(void) ndmp_mtioctl(fd, MTWEOF, 1);
13787917SReza.Sabdar@Sun.COM 	n = write(fd, NDMP_EOM_MAGIC, strlen(NDMP_EOM_MAGIC));
13797917SReza.Sabdar@Sun.COM 
13807917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "%d EOM bytes wrote", n);
13817917SReza.Sabdar@Sun.COM 	(void) ndmp_mtioctl(fd, MTWEOF, 1);
13827917SReza.Sabdar@Sun.COM 
13837917SReza.Sabdar@Sun.COM 	/*
13847917SReza.Sabdar@Sun.COM 	 * Rewind to the previous file since the last two files are used
13857917SReza.Sabdar@Sun.COM 	 * as the indicator for logical EOM.
13867917SReza.Sabdar@Sun.COM 	 */
13877917SReza.Sabdar@Sun.COM 	(void) ndmp_mtioctl(fd, MTBSF, 2);
13887917SReza.Sabdar@Sun.COM }
13897917SReza.Sabdar@Sun.COM 
13907917SReza.Sabdar@Sun.COM 
13917917SReza.Sabdar@Sun.COM /*
13927917SReza.Sabdar@Sun.COM  * ndmpd_local_write
13937917SReza.Sabdar@Sun.COM  *
13947917SReza.Sabdar@Sun.COM  * Writes data to the mover.
13957917SReza.Sabdar@Sun.COM  * Buffers and write data to the tape device.
13967917SReza.Sabdar@Sun.COM  * A full tape record is buffered before being written.
13977917SReza.Sabdar@Sun.COM  *
13987917SReza.Sabdar@Sun.COM  * Parameters:
13997917SReza.Sabdar@Sun.COM  *   session    (input) - session pointer.
14007917SReza.Sabdar@Sun.COM  *   data       (input) - data to be written.
14017917SReza.Sabdar@Sun.COM  *   length     (input) - data length.
14027917SReza.Sabdar@Sun.COM  *
14037917SReza.Sabdar@Sun.COM  * Returns:
14047917SReza.Sabdar@Sun.COM  *   0 - data successfully written.
14057917SReza.Sabdar@Sun.COM  *  -1 - error.
14067917SReza.Sabdar@Sun.COM  */
14077917SReza.Sabdar@Sun.COM int
14087917SReza.Sabdar@Sun.COM ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
14097917SReza.Sabdar@Sun.COM {
14107917SReza.Sabdar@Sun.COM 	ulong_t count = 0;
14117917SReza.Sabdar@Sun.COM 	ssize_t n;
14127917SReza.Sabdar@Sun.COM 	ulong_t len;
14137917SReza.Sabdar@Sun.COM 
14147917SReza.Sabdar@Sun.COM 	/*
14157917SReza.Sabdar@Sun.COM 	 * A length of 0 indicates that any buffered data should be
14167917SReza.Sabdar@Sun.COM 	 * flushed to tape.
14177917SReza.Sabdar@Sun.COM 	 */
14187917SReza.Sabdar@Sun.COM 	if (length == 0) {
14197917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_w_index == 0)
14207917SReza.Sabdar@Sun.COM 			return (0);
14217917SReza.Sabdar@Sun.COM 
14227917SReza.Sabdar@Sun.COM 		(void) memset(
14237917SReza.Sabdar@Sun.COM 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
14247917SReza.Sabdar@Sun.COM 		    0, session->ns_mover.md_record_size -
14257917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_w_index);
14267917SReza.Sabdar@Sun.COM 
14277917SReza.Sabdar@Sun.COM 		n = tape_write(session, session->ns_mover.md_buf,
14287917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_record_size);
14297917SReza.Sabdar@Sun.COM 		if (n <= 0) {
14307917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
14317917SReza.Sabdar@Sun.COM 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14327917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
14337917SReza.Sabdar@Sun.COM 			return (-1);
14347917SReza.Sabdar@Sun.COM 		}
14357917SReza.Sabdar@Sun.COM 		session->ns_mover.md_position += n;
14367917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_written +=
14377917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_w_index;
14387917SReza.Sabdar@Sun.COM 		session->ns_mover.md_record_num++;
14397917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = 0;
14407917SReza.Sabdar@Sun.COM 		return (0);
14417917SReza.Sabdar@Sun.COM 	}
14427917SReza.Sabdar@Sun.COM 	/* Break the data into records. */
14437917SReza.Sabdar@Sun.COM 	while (count < length) {
14447917SReza.Sabdar@Sun.COM 		/*
14457917SReza.Sabdar@Sun.COM 		 * Determine if data needs to be buffered or
14467917SReza.Sabdar@Sun.COM 		 * can be written directly from user supplied location.
14477917SReza.Sabdar@Sun.COM 		 * We can fast path the write if there is no pending
14487917SReza.Sabdar@Sun.COM 		 * buffered data and there is at least a full record's worth
14497917SReza.Sabdar@Sun.COM 		 * of data to be written.
14507917SReza.Sabdar@Sun.COM 		 */
14517917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_w_index == 0 &&
14527917SReza.Sabdar@Sun.COM 		    length - count >= session->ns_mover.md_record_size) {
14537917SReza.Sabdar@Sun.COM 			n = tape_write(session, &data[count],
14547917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_record_size);
14557917SReza.Sabdar@Sun.COM 			if (n <= 0) {
14567917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
14577917SReza.Sabdar@Sun.COM 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14587917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
14597917SReza.Sabdar@Sun.COM 				return (-1);
14607917SReza.Sabdar@Sun.COM 			}
14617917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position += n;
14627917SReza.Sabdar@Sun.COM 			session->ns_mover.md_data_written += n;
14637917SReza.Sabdar@Sun.COM 			session->ns_mover.md_record_num++;
14647917SReza.Sabdar@Sun.COM 			count += n;
14657917SReza.Sabdar@Sun.COM 			continue;
14667917SReza.Sabdar@Sun.COM 		}
14677917SReza.Sabdar@Sun.COM 		/* Buffer the data */
14687917SReza.Sabdar@Sun.COM 		len = length - count;
14697917SReza.Sabdar@Sun.COM 		if (len > session->ns_mover.md_record_size -
14707917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_w_index)
14717917SReza.Sabdar@Sun.COM 			len = session->ns_mover.md_record_size -
14727917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_w_index;
14737917SReza.Sabdar@Sun.COM 
14747917SReza.Sabdar@Sun.COM 		(void) memcpy(
14757917SReza.Sabdar@Sun.COM 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
14767917SReza.Sabdar@Sun.COM 		    &data[count], len);
14777917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index += len;
14787917SReza.Sabdar@Sun.COM 		count += len;
14797917SReza.Sabdar@Sun.COM 
14807917SReza.Sabdar@Sun.COM 		/* Write the buffer if its full */
14817917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_w_index ==
14827917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_record_size) {
14837917SReza.Sabdar@Sun.COM 			n = tape_write(session, session->ns_mover.md_buf,
14847917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_record_size);
14857917SReza.Sabdar@Sun.COM 			if (n < 0) {
14867917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
14877917SReza.Sabdar@Sun.COM 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14887917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
14897917SReza.Sabdar@Sun.COM 				return (-1);
14907917SReza.Sabdar@Sun.COM 			}
14917917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position += n;
14927917SReza.Sabdar@Sun.COM 			session->ns_mover.md_data_written += n;
14937917SReza.Sabdar@Sun.COM 			session->ns_mover.md_record_num++;
14947917SReza.Sabdar@Sun.COM 			session->ns_mover.md_w_index = 0;
14957917SReza.Sabdar@Sun.COM 		}
14967917SReza.Sabdar@Sun.COM 	}
14977917SReza.Sabdar@Sun.COM 
14987917SReza.Sabdar@Sun.COM 	return (0);
14997917SReza.Sabdar@Sun.COM }
15007917SReza.Sabdar@Sun.COM 
15017917SReza.Sabdar@Sun.COM 
15027917SReza.Sabdar@Sun.COM /*
15037917SReza.Sabdar@Sun.COM  * ndmpd_remote_write
15047917SReza.Sabdar@Sun.COM  *
15057917SReza.Sabdar@Sun.COM  * Writes data to the remote mover.
15067917SReza.Sabdar@Sun.COM  *
15077917SReza.Sabdar@Sun.COM  * Parameters:
15087917SReza.Sabdar@Sun.COM  *   session    (input) - session pointer.
15097917SReza.Sabdar@Sun.COM  *   data       (input) - data to be written.
15107917SReza.Sabdar@Sun.COM  *   length     (input) - data length.
15117917SReza.Sabdar@Sun.COM  *
15127917SReza.Sabdar@Sun.COM  * Returns:
15137917SReza.Sabdar@Sun.COM  *   0 - data successfully written.
15147917SReza.Sabdar@Sun.COM  *  -1 - error.
15157917SReza.Sabdar@Sun.COM  */
15167917SReza.Sabdar@Sun.COM int
15177917SReza.Sabdar@Sun.COM ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
15187917SReza.Sabdar@Sun.COM {
15197917SReza.Sabdar@Sun.COM 	ssize_t n;
15207917SReza.Sabdar@Sun.COM 	ulong_t count = 0;
15217917SReza.Sabdar@Sun.COM 
15227917SReza.Sabdar@Sun.COM 	while (count < length) {
15237917SReza.Sabdar@Sun.COM 		if (session->ns_eof == TRUE ||
15247917SReza.Sabdar@Sun.COM 		    session->ns_data.dd_abort == TRUE)
15257917SReza.Sabdar@Sun.COM 			return (-1);
15267917SReza.Sabdar@Sun.COM 
15277917SReza.Sabdar@Sun.COM 		if ((n = write(session->ns_data.dd_sock, &data[count],
15287917SReza.Sabdar@Sun.COM 		    length - count)) < 0) {
15297917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Socket write error: %m.");
15307917SReza.Sabdar@Sun.COM 			return (-1);
15317917SReza.Sabdar@Sun.COM 		}
15327917SReza.Sabdar@Sun.COM 		count += n;
15337917SReza.Sabdar@Sun.COM 	}
15347917SReza.Sabdar@Sun.COM 
15357917SReza.Sabdar@Sun.COM 	return (0);
15367917SReza.Sabdar@Sun.COM }
15377917SReza.Sabdar@Sun.COM 
15387917SReza.Sabdar@Sun.COM /*
15397917SReza.Sabdar@Sun.COM  * ndmpd_local_read
15407917SReza.Sabdar@Sun.COM  *
15417917SReza.Sabdar@Sun.COM  * Reads data from the local tape device.
15427917SReza.Sabdar@Sun.COM  * Full tape records are read and buffered.
15437917SReza.Sabdar@Sun.COM  *
15447917SReza.Sabdar@Sun.COM  * Parameters:
15457917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
15467917SReza.Sabdar@Sun.COM  *   data    (input) - location to store data.
15477917SReza.Sabdar@Sun.COM  *   length  (input) - data length.
15487917SReza.Sabdar@Sun.COM  *
15497917SReza.Sabdar@Sun.COM  * Returns:
15507917SReza.Sabdar@Sun.COM  *   0 - data successfully read.
15517917SReza.Sabdar@Sun.COM  *  -1 - error.
15527917SReza.Sabdar@Sun.COM  *   1 - session terminated or operation aborted.
15537917SReza.Sabdar@Sun.COM  */
15547917SReza.Sabdar@Sun.COM int
15557917SReza.Sabdar@Sun.COM ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
15567917SReza.Sabdar@Sun.COM {
15577917SReza.Sabdar@Sun.COM 	ulong_t count = 0;
15587917SReza.Sabdar@Sun.COM 	ssize_t n;
15597917SReza.Sabdar@Sun.COM 	ulong_t len;
15607917SReza.Sabdar@Sun.COM 	ndmp_notify_mover_paused_request pause_request;
15617917SReza.Sabdar@Sun.COM 
15627917SReza.Sabdar@Sun.COM 	/*
15637917SReza.Sabdar@Sun.COM 	 * Automatically increase the seek window if necessary.
15647917SReza.Sabdar@Sun.COM 	 * This is needed in the event the module attempts to read
15657917SReza.Sabdar@Sun.COM 	 * past a seek window set via a prior call to ndmpd_seek() or
15667917SReza.Sabdar@Sun.COM 	 * the module has not issued a seek. If no seek was issued then
15677917SReza.Sabdar@Sun.COM 	 * pretend that a seek was issued to read the entire tape.
15687917SReza.Sabdar@Sun.COM 	 */
15697917SReza.Sabdar@Sun.COM 	if (length > session->ns_mover.md_bytes_left_to_read) {
15707917SReza.Sabdar@Sun.COM 		/* ndmpd_seek() never called? */
15717917SReza.Sabdar@Sun.COM 		if (session->ns_data.dd_read_length == 0) {
15727917SReza.Sabdar@Sun.COM 			session->ns_mover.md_bytes_left_to_read = ~0LL;
15737917SReza.Sabdar@Sun.COM 			session->ns_data.dd_read_offset = 0LL;
15747917SReza.Sabdar@Sun.COM 			session->ns_data.dd_read_length = ~0LL;
15757917SReza.Sabdar@Sun.COM 		} else {
15767917SReza.Sabdar@Sun.COM 			session->ns_mover.md_bytes_left_to_read = length;
15777917SReza.Sabdar@Sun.COM 			session->ns_data.dd_read_offset =
15787917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_position;
15797917SReza.Sabdar@Sun.COM 			session->ns_data.dd_read_length = length;
15807917SReza.Sabdar@Sun.COM 		}
15817917SReza.Sabdar@Sun.COM 	}
15827917SReza.Sabdar@Sun.COM 	/*
15837917SReza.Sabdar@Sun.COM 	 * Read as many records as necessary to satisfy the request.
15847917SReza.Sabdar@Sun.COM 	 */
15857917SReza.Sabdar@Sun.COM 	while (count < length) {
15867917SReza.Sabdar@Sun.COM 		/*
15877917SReza.Sabdar@Sun.COM 		 * If the end of the mover window has been reached,
15887917SReza.Sabdar@Sun.COM 		 * then notify the client that a new data window is needed.
15897917SReza.Sabdar@Sun.COM 		 */
15907917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_position >=
15917917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_offset +
15927917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_length) {
15937917SReza.Sabdar@Sun.COM 
15947917SReza.Sabdar@Sun.COM 			session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
15957917SReza.Sabdar@Sun.COM 			session->ns_mover.md_pause_reason =
15967917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_PAUSE_SEEK;
15977917SReza.Sabdar@Sun.COM 			pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
15987917SReza.Sabdar@Sun.COM 			pause_request.seek_position =
15997917SReza.Sabdar@Sun.COM 			    long_long_to_quad(session->ns_mover.md_position);
16007917SReza.Sabdar@Sun.COM 
16017917SReza.Sabdar@Sun.COM 			if (ndmp_send_request(session->ns_connection,
16027917SReza.Sabdar@Sun.COM 			    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
16037917SReza.Sabdar@Sun.COM 			    (void *) &pause_request, 0) < 0) {
16047917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
16057917SReza.Sabdar@Sun.COM 				    "Sending notify_mover_paused request");
16067917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
16077917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
16087917SReza.Sabdar@Sun.COM 				return (-1);
16097917SReza.Sabdar@Sun.COM 			}
16107917SReza.Sabdar@Sun.COM 			/*
16117917SReza.Sabdar@Sun.COM 			 * Wait for until the state is changed by
16127917SReza.Sabdar@Sun.COM 			 * an abort or continue request.
16137917SReza.Sabdar@Sun.COM 			 */
16147917SReza.Sabdar@Sun.COM 			nlp_ref_nw(session);
16157917SReza.Sabdar@Sun.COM 			for (; ; ) {
16167917SReza.Sabdar@Sun.COM 				nlp_wait_nw(session);
16177917SReza.Sabdar@Sun.COM 
16187917SReza.Sabdar@Sun.COM 				if (session->ns_eof == TRUE) {
16197917SReza.Sabdar@Sun.COM 					nlp_unref_nw(session);
16207917SReza.Sabdar@Sun.COM 					return (1);
16217917SReza.Sabdar@Sun.COM 				}
16227917SReza.Sabdar@Sun.COM 
16237917SReza.Sabdar@Sun.COM 				switch (session->ns_mover.md_state) {
16247917SReza.Sabdar@Sun.COM 				case NDMP_MOVER_STATE_ACTIVE:
16257917SReza.Sabdar@Sun.COM 					break;
16267917SReza.Sabdar@Sun.COM 
16277917SReza.Sabdar@Sun.COM 				case NDMP_MOVER_STATE_PAUSED:
16287917SReza.Sabdar@Sun.COM 					continue;
16297917SReza.Sabdar@Sun.COM 
16307917SReza.Sabdar@Sun.COM 				default:
16317917SReza.Sabdar@Sun.COM 					nlp_unref_nw(session);
16327917SReza.Sabdar@Sun.COM 					return (-1);
16337917SReza.Sabdar@Sun.COM 				}
16347917SReza.Sabdar@Sun.COM 			}
16357917SReza.Sabdar@Sun.COM 		}
16367917SReza.Sabdar@Sun.COM 		len = length - count;
16377917SReza.Sabdar@Sun.COM 
16387917SReza.Sabdar@Sun.COM 		/*
16397917SReza.Sabdar@Sun.COM 		 * Prevent reading past the end of the window.
16407917SReza.Sabdar@Sun.COM 		 */
16417917SReza.Sabdar@Sun.COM 		if (len >
16427917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_offset +
16437917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_length -
16447917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_position)
16457917SReza.Sabdar@Sun.COM 			len = session->ns_mover.md_window_offset +
16467917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_window_length -
16477917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_position;
16487917SReza.Sabdar@Sun.COM 
16497917SReza.Sabdar@Sun.COM 		/*
16507917SReza.Sabdar@Sun.COM 		 * Copy from the data buffer first.
16517917SReza.Sabdar@Sun.COM 		 */
16527917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_w_index -
16537917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_r_index != 0) {
16547917SReza.Sabdar@Sun.COM 			/*
16557917SReza.Sabdar@Sun.COM 			 * Limit the copy to the amount of data in the buffer.
16567917SReza.Sabdar@Sun.COM 			 */
16577917SReza.Sabdar@Sun.COM 			if (len > session->ns_mover.md_w_index -
16587917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_r_index)
16597917SReza.Sabdar@Sun.COM 				len = session->ns_mover.md_w_index
16607917SReza.Sabdar@Sun.COM 				    - session->ns_mover.md_r_index;
16617917SReza.Sabdar@Sun.COM 
16627917SReza.Sabdar@Sun.COM 			(void) memcpy((void *) &data[count],
16637917SReza.Sabdar@Sun.COM 			    &session->ns_mover.md_buf[session->
16647917SReza.Sabdar@Sun.COM 			    ns_mover.md_r_index], len);
16657917SReza.Sabdar@Sun.COM 			count += len;
16667917SReza.Sabdar@Sun.COM 			session->ns_mover.md_r_index += len;
16677917SReza.Sabdar@Sun.COM 			session->ns_mover.md_bytes_left_to_read -= len;
16687917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position += len;
16697917SReza.Sabdar@Sun.COM 			continue;
16707917SReza.Sabdar@Sun.COM 		}
16717917SReza.Sabdar@Sun.COM 		/*
16727917SReza.Sabdar@Sun.COM 		 * Determine if data needs to be buffered or
16737917SReza.Sabdar@Sun.COM 		 * can be read directly to user supplied location.
16747917SReza.Sabdar@Sun.COM 		 * We can fast path the read if at least a full record
16757917SReza.Sabdar@Sun.COM 		 * needs to be read and there is no seek pending.
16767917SReza.Sabdar@Sun.COM 		 * This is done to eliminate a buffer copy.
16777917SReza.Sabdar@Sun.COM 		 */
16787917SReza.Sabdar@Sun.COM 		if (len >= session->ns_mover.md_record_size &&
16797917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_position >=
16807917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_seek_position) {
16817917SReza.Sabdar@Sun.COM 			n = tape_read(session, &data[count]);
16827917SReza.Sabdar@Sun.COM 			if (n <= 0) {
16837917SReza.Sabdar@Sun.COM 				if (n == TAPE_NO_WRITER_ERR)
16847917SReza.Sabdar@Sun.COM 					return (1);
16857917SReza.Sabdar@Sun.COM 
16867917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
16877917SReza.Sabdar@Sun.COM 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
16887917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
16897917SReza.Sabdar@Sun.COM 				return (n == 0) ? (1) : (-1);
16907917SReza.Sabdar@Sun.COM 			}
16917917SReza.Sabdar@Sun.COM 			count += n;
16927917SReza.Sabdar@Sun.COM 			session->ns_mover.md_bytes_left_to_read -= n;
16937917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position += n;
16947917SReza.Sabdar@Sun.COM 			continue;
16957917SReza.Sabdar@Sun.COM 		}
16967917SReza.Sabdar@Sun.COM 		/* Read the next record into the buffer. */
16977917SReza.Sabdar@Sun.COM 		n = tape_read(session, session->ns_mover.md_buf);
16987917SReza.Sabdar@Sun.COM 		if (n <= 0) {
16997917SReza.Sabdar@Sun.COM 			if (n == TAPE_NO_WRITER_ERR)
17007917SReza.Sabdar@Sun.COM 				return (1);
17017917SReza.Sabdar@Sun.COM 
17027917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
17037917SReza.Sabdar@Sun.COM 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
17047917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
17057917SReza.Sabdar@Sun.COM 			return (n == 0) ? (1) : (-1);
17067917SReza.Sabdar@Sun.COM 		}
17077917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = n;
17087917SReza.Sabdar@Sun.COM 		session->ns_mover.md_r_index = 0;
17097917SReza.Sabdar@Sun.COM 
17107917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
17117917SReza.Sabdar@Sun.COM 
17127917SReza.Sabdar@Sun.COM 		/*
17137917SReza.Sabdar@Sun.COM 		 * Discard data if the current data stream position is
17147917SReza.Sabdar@Sun.COM 		 * prior to the seek position. This is necessary if a seek
17157917SReza.Sabdar@Sun.COM 		 * request set the seek pointer to a position that is not a
17167917SReza.Sabdar@Sun.COM 		 * record boundary. The seek request handler can only position
17177917SReza.Sabdar@Sun.COM 		 * to the start of a record.
17187917SReza.Sabdar@Sun.COM 		 */
17197917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_position <
17207917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_seek_position) {
17217917SReza.Sabdar@Sun.COM 			session->ns_mover.md_r_index =
17227917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_seek_position -
17237917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_position;
17247917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position =
17257917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_seek_position;
17267917SReza.Sabdar@Sun.COM 		}
17277917SReza.Sabdar@Sun.COM 	}
17287917SReza.Sabdar@Sun.COM 
17297917SReza.Sabdar@Sun.COM 	return (0);
17307917SReza.Sabdar@Sun.COM }
17317917SReza.Sabdar@Sun.COM 
17327917SReza.Sabdar@Sun.COM 
17337917SReza.Sabdar@Sun.COM /*
17347917SReza.Sabdar@Sun.COM  * ndmpd_remote_read
17357917SReza.Sabdar@Sun.COM  *
17367917SReza.Sabdar@Sun.COM  * Reads data from the remote mover.
17377917SReza.Sabdar@Sun.COM  *
17387917SReza.Sabdar@Sun.COM  * Parameters:
17397917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
17407917SReza.Sabdar@Sun.COM  *   data    (input) - data to be written.
17417917SReza.Sabdar@Sun.COM  *   length  (input) - data length.
17427917SReza.Sabdar@Sun.COM  *
17437917SReza.Sabdar@Sun.COM  * Returns:
17447917SReza.Sabdar@Sun.COM  *   0 - data successfully read.
17457917SReza.Sabdar@Sun.COM  *  -1 - error.
17467917SReza.Sabdar@Sun.COM  *   1 - session terminated or operation aborted.
17477917SReza.Sabdar@Sun.COM  */
17487917SReza.Sabdar@Sun.COM int
17497917SReza.Sabdar@Sun.COM ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
17507917SReza.Sabdar@Sun.COM {
17517917SReza.Sabdar@Sun.COM 	ulong_t count = 0;
17527917SReza.Sabdar@Sun.COM 	ssize_t n;
17537917SReza.Sabdar@Sun.COM 	ulong_t len;
17547917SReza.Sabdar@Sun.COM 	ndmp_notify_data_read_request request;
17557917SReza.Sabdar@Sun.COM 
17567917SReza.Sabdar@Sun.COM 	while (count < length) {
17577917SReza.Sabdar@Sun.COM 		len = length - count;
17587917SReza.Sabdar@Sun.COM 
17597917SReza.Sabdar@Sun.COM 		/*
17607917SReza.Sabdar@Sun.COM 		 * If the end of the seek window has been reached then
17617917SReza.Sabdar@Sun.COM 		 * send an ndmp_read request to the client.
17627917SReza.Sabdar@Sun.COM 		 * The NDMP client will then send a mover_data_read request to
17637917SReza.Sabdar@Sun.COM 		 * the remote mover and the mover will send more data.
17647917SReza.Sabdar@Sun.COM 		 * This condition can occur if the module attempts to read past
17657917SReza.Sabdar@Sun.COM 		 * a seek window set via a prior call to ndmpd_seek() or
17667917SReza.Sabdar@Sun.COM 		 * the module has not issued a seek. If no seek was issued then
17677917SReza.Sabdar@Sun.COM 		 * pretend that a seek was issued to read the entire tape.
17687917SReza.Sabdar@Sun.COM 		 */
17697917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_bytes_left_to_read == 0) {
17707917SReza.Sabdar@Sun.COM 			/* ndmpd_seek() never called? */
17717917SReza.Sabdar@Sun.COM 			if (session->ns_data.dd_read_length == 0) {
17727917SReza.Sabdar@Sun.COM 				session->ns_mover.md_bytes_left_to_read = ~0LL;
17737917SReza.Sabdar@Sun.COM 				session->ns_data.dd_read_offset = 0LL;
17747917SReza.Sabdar@Sun.COM 				session->ns_data.dd_read_length = ~0LL;
17757917SReza.Sabdar@Sun.COM 			} else {
17767917SReza.Sabdar@Sun.COM 				session->ns_mover.md_bytes_left_to_read = len;
17777917SReza.Sabdar@Sun.COM 				session->ns_data.dd_read_offset =
17787917SReza.Sabdar@Sun.COM 				    session->ns_mover.md_position;
17797917SReza.Sabdar@Sun.COM 				session->ns_data.dd_read_length = len;
17807917SReza.Sabdar@Sun.COM 			}
17817917SReza.Sabdar@Sun.COM 
17827917SReza.Sabdar@Sun.COM 			request.offset =
17837917SReza.Sabdar@Sun.COM 			    long_long_to_quad(session->ns_data.dd_read_offset);
17847917SReza.Sabdar@Sun.COM 			request.length =
17857917SReza.Sabdar@Sun.COM 			    long_long_to_quad(session->ns_data.dd_read_length);
17867917SReza.Sabdar@Sun.COM 
17878193SReza.Sabdar@Sun.COM 			if (ndmp_send_request_lock(session->ns_connection,
17887917SReza.Sabdar@Sun.COM 			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
17897917SReza.Sabdar@Sun.COM 			    (void *) &request, 0) < 0) {
17907917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
17917917SReza.Sabdar@Sun.COM 				    "Sending notify_data_read request");
17927917SReza.Sabdar@Sun.COM 				return (-1);
17937917SReza.Sabdar@Sun.COM 			}
17947917SReza.Sabdar@Sun.COM 		}
17957917SReza.Sabdar@Sun.COM 		if (session->ns_eof == TRUE ||
17967917SReza.Sabdar@Sun.COM 		    session->ns_data.dd_abort == TRUE)
17977917SReza.Sabdar@Sun.COM 			return (1);
17987917SReza.Sabdar@Sun.COM 
17997917SReza.Sabdar@Sun.COM 		/*
18007917SReza.Sabdar@Sun.COM 		 * If the module called ndmpd_seek() prior to reading all of the
18017917SReza.Sabdar@Sun.COM 		 * data that the remote mover was requested to send, then the
18027917SReza.Sabdar@Sun.COM 		 * excess data from the seek has to be discardd.
18037917SReza.Sabdar@Sun.COM 		 */
18047917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_discard_length != 0) {
18057917SReza.Sabdar@Sun.COM 			n = discard_data(session,
18067917SReza.Sabdar@Sun.COM 			    (ulong_t)session->ns_mover.md_discard_length);
18077917SReza.Sabdar@Sun.COM 			if (n < 0)
18087917SReza.Sabdar@Sun.COM 				return (-1);
18097917SReza.Sabdar@Sun.COM 			session->ns_mover.md_discard_length -= n;
18107917SReza.Sabdar@Sun.COM 			continue;
18117917SReza.Sabdar@Sun.COM 		}
18127917SReza.Sabdar@Sun.COM 		/*
18137917SReza.Sabdar@Sun.COM 		 * Don't attempt to read more data than the remote is sending.
18147917SReza.Sabdar@Sun.COM 		 */
18157917SReza.Sabdar@Sun.COM 		if (len > session->ns_mover.md_bytes_left_to_read)
18167917SReza.Sabdar@Sun.COM 			len = session->ns_mover.md_bytes_left_to_read;
18177917SReza.Sabdar@Sun.COM 
18187917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "len: %u", len);
18197917SReza.Sabdar@Sun.COM 
18207917SReza.Sabdar@Sun.COM 		if ((n = read(session->ns_data.dd_sock, &data[count],
18217917SReza.Sabdar@Sun.COM 		    len)) < 0) {
18227917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
18237917SReza.Sabdar@Sun.COM 			return (-1);
18247917SReza.Sabdar@Sun.COM 		}
18257917SReza.Sabdar@Sun.COM 		/* read returns 0 if the connection was closed */
18267917SReza.Sabdar@Sun.COM 		if (n == 0)
18277917SReza.Sabdar@Sun.COM 			return (-1);
18287917SReza.Sabdar@Sun.COM 
18297917SReza.Sabdar@Sun.COM 		count += n;
18307917SReza.Sabdar@Sun.COM 		session->ns_mover.md_bytes_left_to_read -= n;
18317917SReza.Sabdar@Sun.COM 		session->ns_mover.md_position += n;
18327917SReza.Sabdar@Sun.COM 	}
18337917SReza.Sabdar@Sun.COM 
18347917SReza.Sabdar@Sun.COM 	return (0);
18357917SReza.Sabdar@Sun.COM }
18367917SReza.Sabdar@Sun.COM 
18377917SReza.Sabdar@Sun.COM /* *** ndmpd internal functions ***************************************** */
18387917SReza.Sabdar@Sun.COM 
18397917SReza.Sabdar@Sun.COM /*
18407917SReza.Sabdar@Sun.COM  * ndmpd_mover_init
18417917SReza.Sabdar@Sun.COM  *
18427917SReza.Sabdar@Sun.COM  * Initialize mover specific session variables.
18437917SReza.Sabdar@Sun.COM  * Don't initialize variables such as record_size that need to
18447917SReza.Sabdar@Sun.COM  * persist across data operations. A client may open a connection and
18457917SReza.Sabdar@Sun.COM  * do multiple backups after setting the record_size.
18467917SReza.Sabdar@Sun.COM  *
18477917SReza.Sabdar@Sun.COM  * Parameters:
18487917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
18497917SReza.Sabdar@Sun.COM  *
18507917SReza.Sabdar@Sun.COM  * Returns:
18517917SReza.Sabdar@Sun.COM  *   0 - success.
18527917SReza.Sabdar@Sun.COM  *  -1 - error.
18537917SReza.Sabdar@Sun.COM  */
18547917SReza.Sabdar@Sun.COM int
18557917SReza.Sabdar@Sun.COM ndmpd_mover_init(ndmpd_session_t *session)
18567917SReza.Sabdar@Sun.COM {
18577917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
18587917SReza.Sabdar@Sun.COM 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
18597917SReza.Sabdar@Sun.COM 	session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
18607917SReza.Sabdar@Sun.COM 	session->ns_mover.md_data_written = 0LL;
18617917SReza.Sabdar@Sun.COM 	session->ns_mover.md_seek_position = 0LL;
18627917SReza.Sabdar@Sun.COM 	session->ns_mover.md_bytes_left_to_read = 0LL;
18637917SReza.Sabdar@Sun.COM 	session->ns_mover.md_window_offset = 0LL;
18647917SReza.Sabdar@Sun.COM 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
18657917SReza.Sabdar@Sun.COM 	session->ns_mover.md_position = 0LL;
18667917SReza.Sabdar@Sun.COM 	session->ns_mover.md_discard_length = 0;
18677917SReza.Sabdar@Sun.COM 	session->ns_mover.md_record_num = 0;
18687917SReza.Sabdar@Sun.COM 	session->ns_mover.md_record_size = 0;
18697917SReza.Sabdar@Sun.COM 	session->ns_mover.md_listen_sock = -1;
18707917SReza.Sabdar@Sun.COM 	session->ns_mover.md_pre_cond = FALSE;
18717917SReza.Sabdar@Sun.COM 	session->ns_mover.md_sock = -1;
18727917SReza.Sabdar@Sun.COM 	session->ns_mover.md_r_index = 0;
18737917SReza.Sabdar@Sun.COM 	session->ns_mover.md_w_index = 0;
18747917SReza.Sabdar@Sun.COM 	session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
18757917SReza.Sabdar@Sun.COM 	if (!session->ns_mover.md_buf)
18767917SReza.Sabdar@Sun.COM 		return (-1);
18777917SReza.Sabdar@Sun.COM 
18787917SReza.Sabdar@Sun.COM 	if (ndmp_get_version(session->ns_connection) == NDMPV3) {
18797917SReza.Sabdar@Sun.COM 		session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
18807917SReza.Sabdar@Sun.COM 		(void) memset(&session->ns_mover.md_data_addr, 0,
18817917SReza.Sabdar@Sun.COM 		    sizeof (ndmp_addr_v3));
18827917SReza.Sabdar@Sun.COM 	}
18837917SReza.Sabdar@Sun.COM 	return (0);
18847917SReza.Sabdar@Sun.COM }
18857917SReza.Sabdar@Sun.COM 
18867917SReza.Sabdar@Sun.COM 
18877917SReza.Sabdar@Sun.COM /*
18887917SReza.Sabdar@Sun.COM  * ndmpd_mover_shut_down
18897917SReza.Sabdar@Sun.COM  *
18907917SReza.Sabdar@Sun.COM  * Shutdown the mover. It closes all the sockets.
18917917SReza.Sabdar@Sun.COM  *
18927917SReza.Sabdar@Sun.COM  * Parameters:
18937917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
18947917SReza.Sabdar@Sun.COM  *
18957917SReza.Sabdar@Sun.COM  * Returns:
18967917SReza.Sabdar@Sun.COM  *   void
18977917SReza.Sabdar@Sun.COM  */
18987917SReza.Sabdar@Sun.COM void
18997917SReza.Sabdar@Sun.COM ndmpd_mover_shut_down(ndmpd_session_t *session)
19007917SReza.Sabdar@Sun.COM {
19017917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_listen_sock != -1) {
19027917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
19037917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_listen_sock);
19047917SReza.Sabdar@Sun.COM 		(void) ndmpd_remove_file_handler(session,
19057917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_listen_sock);
19067917SReza.Sabdar@Sun.COM 		(void) close(session->ns_mover.md_listen_sock);
19077917SReza.Sabdar@Sun.COM 		session->ns_mover.md_listen_sock = -1;
19087917SReza.Sabdar@Sun.COM 	}
19097917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_sock != -1) {
19107917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
19117917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_sock);
19127917SReza.Sabdar@Sun.COM 		(void) ndmpd_remove_file_handler(session,
19137917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_sock);
19147917SReza.Sabdar@Sun.COM 		(void) close(session->ns_mover.md_sock);
19157917SReza.Sabdar@Sun.COM 		session->ns_mover.md_sock = -1;
19167917SReza.Sabdar@Sun.COM 	}
19177917SReza.Sabdar@Sun.COM }
19187917SReza.Sabdar@Sun.COM 
19197917SReza.Sabdar@Sun.COM 
19207917SReza.Sabdar@Sun.COM /*
19217917SReza.Sabdar@Sun.COM  * ndmpd_mover_cleanup
19227917SReza.Sabdar@Sun.COM  *
19237917SReza.Sabdar@Sun.COM  * Parameters:
19247917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
19257917SReza.Sabdar@Sun.COM  *
19267917SReza.Sabdar@Sun.COM  * Returns:
19277917SReza.Sabdar@Sun.COM  *   void
19287917SReza.Sabdar@Sun.COM  */
19297917SReza.Sabdar@Sun.COM void
19307917SReza.Sabdar@Sun.COM ndmpd_mover_cleanup(ndmpd_session_t *session)
19317917SReza.Sabdar@Sun.COM {
19327917SReza.Sabdar@Sun.COM 	NDMP_FREE(session->ns_mover.md_buf);
19337917SReza.Sabdar@Sun.COM }
19347917SReza.Sabdar@Sun.COM 
19357917SReza.Sabdar@Sun.COM 
19367917SReza.Sabdar@Sun.COM /*
19377917SReza.Sabdar@Sun.COM  * ndmpd_mover_connect
19387917SReza.Sabdar@Sun.COM  *   Create a connection to the specified mover.
19397917SReza.Sabdar@Sun.COM  *
19407917SReza.Sabdar@Sun.COM  * Parameters:
19417917SReza.Sabdar@Sun.COM  *   session (input) - session pointer
19427917SReza.Sabdar@Sun.COM  *
19437917SReza.Sabdar@Sun.COM  * Returns:
19447917SReza.Sabdar@Sun.COM  *   error code.
19457917SReza.Sabdar@Sun.COM  */
19467917SReza.Sabdar@Sun.COM ndmp_error
19477917SReza.Sabdar@Sun.COM ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
19487917SReza.Sabdar@Sun.COM {
19497917SReza.Sabdar@Sun.COM 	ndmp_mover_addr *mover = &session->ns_data.dd_mover;
19507917SReza.Sabdar@Sun.COM 	struct sockaddr_in sin;
19517917SReza.Sabdar@Sun.COM 	int sock = -1;
19527917SReza.Sabdar@Sun.COM 	int flag = 1;
19537917SReza.Sabdar@Sun.COM 
19547917SReza.Sabdar@Sun.COM 	if (mover->addr_type == NDMP_ADDR_TCP) {
19557917SReza.Sabdar@Sun.COM 		if (mover->ndmp_mover_addr_u.addr.ip_addr) {
19567917SReza.Sabdar@Sun.COM 			(void) memset((void *) &sin, 0, sizeof (sin));
19577917SReza.Sabdar@Sun.COM 			sin.sin_family = AF_INET;
19587917SReza.Sabdar@Sun.COM 			sin.sin_addr.s_addr =
19597917SReza.Sabdar@Sun.COM 			    htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
19607917SReza.Sabdar@Sun.COM 			sin.sin_port =
19617917SReza.Sabdar@Sun.COM 			    htons(mover->ndmp_mover_addr_u.addr.port);
19627917SReza.Sabdar@Sun.COM 
19637917SReza.Sabdar@Sun.COM 			/*
19647917SReza.Sabdar@Sun.COM 			 * If the address type is TCP but both the address and
19657917SReza.Sabdar@Sun.COM 			 * the port number are zero, we have to use a different
19667917SReza.Sabdar@Sun.COM 			 * socket than the mover socket. This can happen when
19677917SReza.Sabdar@Sun.COM 			 * using NDMP disk to disk copy (AKA D2D copy).
19687917SReza.Sabdar@Sun.COM 			 * The NDMPCopy client will send a zero address to
19697917SReza.Sabdar@Sun.COM 			 * direct the server to use the mover socket as the
19707917SReza.Sabdar@Sun.COM 			 * data socket to receive the recovery data.
19717917SReza.Sabdar@Sun.COM 			 */
19727917SReza.Sabdar@Sun.COM 			if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
19737917SReza.Sabdar@Sun.COM 				session->ns_data.dd_sock =
19747917SReza.Sabdar@Sun.COM 				    session->ns_mover.md_sock;
19757917SReza.Sabdar@Sun.COM 				return (NDMP_NO_ERR);
19767917SReza.Sabdar@Sun.COM 			}
19777917SReza.Sabdar@Sun.COM 
19787917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
19797917SReza.Sabdar@Sun.COM 			    mover->ndmp_mover_addr_u.addr.ip_addr,
19807917SReza.Sabdar@Sun.COM 			    (ulong_t)sin.sin_port);
19817917SReza.Sabdar@Sun.COM 
19827917SReza.Sabdar@Sun.COM 			if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
19837917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG, "Socket error: %m");
19847917SReza.Sabdar@Sun.COM 				return (NDMP_IO_ERR);
19857917SReza.Sabdar@Sun.COM 			}
19867917SReza.Sabdar@Sun.COM 			if (connect(sock, (struct sockaddr *)&sin,
19877917SReza.Sabdar@Sun.COM 			    sizeof (sin)) < 0) {
19887917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG, "Connect error: %m");
19897917SReza.Sabdar@Sun.COM 				(void) close(sock);
19907917SReza.Sabdar@Sun.COM 				return (NDMP_IO_ERR);
19917917SReza.Sabdar@Sun.COM 			}
19927917SReza.Sabdar@Sun.COM 
19937917SReza.Sabdar@Sun.COM 			if (ndmp_sbs > 0)
19947917SReza.Sabdar@Sun.COM 				ndmp_set_socket_snd_buf(sock,
19957917SReza.Sabdar@Sun.COM 				    ndmp_sbs * KILOBYTE);
19967917SReza.Sabdar@Sun.COM 			if (ndmp_rbs > 0)
19977917SReza.Sabdar@Sun.COM 				ndmp_set_socket_rcv_buf(sock,
19987917SReza.Sabdar@Sun.COM 				    ndmp_rbs * KILOBYTE);
19997917SReza.Sabdar@Sun.COM 
20007917SReza.Sabdar@Sun.COM 			ndmp_set_socket_nodelay(sock);
20017917SReza.Sabdar@Sun.COM 			(void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag,
20027917SReza.Sabdar@Sun.COM 			    sizeof (flag));
20037917SReza.Sabdar@Sun.COM 		} else {
20047917SReza.Sabdar@Sun.COM 			if ((session->ns_mover.md_state !=
20057917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_STATE_ACTIVE) ||
20067917SReza.Sabdar@Sun.COM 			    (session->ns_mover.md_sock == -1)) {
20077917SReza.Sabdar@Sun.COM 
20087917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
20097917SReza.Sabdar@Sun.COM 				    "Not in active  state mover"
20107917SReza.Sabdar@Sun.COM 				    "  state = %d or Invalid mover sock=%d",
20117917SReza.Sabdar@Sun.COM 				    session->ns_mover.md_state,
20127917SReza.Sabdar@Sun.COM 				    session->ns_mover.md_sock);
20137917SReza.Sabdar@Sun.COM 				return (NDMP_ILLEGAL_STATE_ERR);
20147917SReza.Sabdar@Sun.COM 			}
20157917SReza.Sabdar@Sun.COM 
20167917SReza.Sabdar@Sun.COM 			sock = session->ns_mover.md_sock;
20177917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
20187917SReza.Sabdar@Sun.COM 			    "session: 0x%x setting data sock fd: %d to be"
20197917SReza.Sabdar@Sun.COM 			    " same as listen_sock", session, sock);
20207917SReza.Sabdar@Sun.COM 		}
20217917SReza.Sabdar@Sun.COM 
20227917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
20237917SReza.Sabdar@Sun.COM 
20247917SReza.Sabdar@Sun.COM 		session->ns_data.dd_sock = sock;
20257917SReza.Sabdar@Sun.COM 
20267917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
20277917SReza.Sabdar@Sun.COM 
20287917SReza.Sabdar@Sun.COM 		return (NDMP_NO_ERR);
20297917SReza.Sabdar@Sun.COM 	}
20307917SReza.Sabdar@Sun.COM 	/* Local mover connection. */
20317917SReza.Sabdar@Sun.COM 
20327917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
20337917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
20347917SReza.Sabdar@Sun.COM 		return (NDMP_ILLEGAL_STATE_ERR);
20357917SReza.Sabdar@Sun.COM 	}
20367917SReza.Sabdar@Sun.COM 	if (session->ns_tape.td_fd == -1) {
20377917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Tape device not open");
20387917SReza.Sabdar@Sun.COM 		return (NDMP_DEV_NOT_OPEN_ERR);
20397917SReza.Sabdar@Sun.COM 	}
20407917SReza.Sabdar@Sun.COM 	if (mover_mode == NDMP_MOVER_MODE_READ &&
20417917SReza.Sabdar@Sun.COM 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
20427917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Write protected device.");
20437917SReza.Sabdar@Sun.COM 		return (NDMP_WRITE_PROTECT_ERR);
20447917SReza.Sabdar@Sun.COM 	}
20457917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
20467917SReza.Sabdar@Sun.COM 	session->ns_mover.md_mode = mover_mode;
20477917SReza.Sabdar@Sun.COM 
20487917SReza.Sabdar@Sun.COM 	return (NDMP_NO_ERR);
20497917SReza.Sabdar@Sun.COM }
20507917SReza.Sabdar@Sun.COM 
20517917SReza.Sabdar@Sun.COM 
20527917SReza.Sabdar@Sun.COM 
20537917SReza.Sabdar@Sun.COM /*
20547917SReza.Sabdar@Sun.COM  * ndmpd_mover_seek
20557917SReza.Sabdar@Sun.COM  *
20567917SReza.Sabdar@Sun.COM  * Seek to the requested data stream position.
20577917SReza.Sabdar@Sun.COM  * If the requested offset is outside of the current window,
20587917SReza.Sabdar@Sun.COM  * the mover is paused and a notify_mover_paused request is sent
20597917SReza.Sabdar@Sun.COM  * notifying the client that a seek is required.
20607917SReza.Sabdar@Sun.COM  * If the requested offest is within the window but not within the
20617917SReza.Sabdar@Sun.COM  * current record, then the tape is positioned to the record containing
20627917SReza.Sabdar@Sun.COM  * the requested offest.
20637917SReza.Sabdar@Sun.COM  * The requested amount of data is then read from the tape device and
20647917SReza.Sabdar@Sun.COM  * written to the data connection.
20657917SReza.Sabdar@Sun.COM  *
20667917SReza.Sabdar@Sun.COM  * Parameters:
20677917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
20687917SReza.Sabdar@Sun.COM  *   offset  (input) - data stream position to seek to.
20697917SReza.Sabdar@Sun.COM  *   length  (input) - amount of data that will be read.
20707917SReza.Sabdar@Sun.COM  *
20717917SReza.Sabdar@Sun.COM  * Returns:
20727917SReza.Sabdar@Sun.COM  *   1 - seek pending completion by the NDMP client.
20737917SReza.Sabdar@Sun.COM  *   0 - seek successfully completed.
20747917SReza.Sabdar@Sun.COM  *  -1 - error.
20757917SReza.Sabdar@Sun.COM  */
20767917SReza.Sabdar@Sun.COM int
20777917SReza.Sabdar@Sun.COM ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
20787917SReza.Sabdar@Sun.COM     u_longlong_t length)
20797917SReza.Sabdar@Sun.COM {
20807917SReza.Sabdar@Sun.COM 	int ctlcmd;
20817917SReza.Sabdar@Sun.COM 	int ctlcnt;
20827917SReza.Sabdar@Sun.COM 	u_longlong_t tape_position;
20837917SReza.Sabdar@Sun.COM 	u_longlong_t buf_position;
20847917SReza.Sabdar@Sun.COM 	ndmp_notify_mover_paused_request pause_request;
20857917SReza.Sabdar@Sun.COM 
20867917SReza.Sabdar@Sun.COM 	session->ns_mover.md_seek_position = offset;
20877917SReza.Sabdar@Sun.COM 	session->ns_mover.md_bytes_left_to_read = length;
20887917SReza.Sabdar@Sun.COM 
20897917SReza.Sabdar@Sun.COM 	/*
20907917SReza.Sabdar@Sun.COM 	 * If the requested position is outside of the window,
20917917SReza.Sabdar@Sun.COM 	 * notify the client that a seek is required.
20927917SReza.Sabdar@Sun.COM 	 */
20937917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_seek_position <
20947917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_window_offset ||
20957917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_seek_position >=
20967917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_window_offset +
20977917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_window_length) {
20987917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
20997917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_seek_position);
21007917SReza.Sabdar@Sun.COM 
21017917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = 0;
21027917SReza.Sabdar@Sun.COM 		session->ns_mover.md_r_index = 0;
21037917SReza.Sabdar@Sun.COM 
21047917SReza.Sabdar@Sun.COM 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
21057917SReza.Sabdar@Sun.COM 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
21067917SReza.Sabdar@Sun.COM 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
21077917SReza.Sabdar@Sun.COM 		pause_request.seek_position = long_long_to_quad(offset);
21087917SReza.Sabdar@Sun.COM 
21097917SReza.Sabdar@Sun.COM 		if (ndmp_send_request(session->ns_connection,
21107917SReza.Sabdar@Sun.COM 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
21117917SReza.Sabdar@Sun.COM 		    (void *) &pause_request, 0) < 0) {
21127917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
21137917SReza.Sabdar@Sun.COM 			    "Sending notify_mover_paused request");
21147917SReza.Sabdar@Sun.COM 			return (-1);
21157917SReza.Sabdar@Sun.COM 		}
21167917SReza.Sabdar@Sun.COM 		return (1);
21177917SReza.Sabdar@Sun.COM 	}
21187917SReza.Sabdar@Sun.COM 	/*
21197917SReza.Sabdar@Sun.COM 	 * Determine the data stream position of the first byte in the
21207917SReza.Sabdar@Sun.COM 	 * data buffer.
21217917SReza.Sabdar@Sun.COM 	 */
21227917SReza.Sabdar@Sun.COM 	buf_position = session->ns_mover.md_position -
21237917SReza.Sabdar@Sun.COM 	    (session->ns_mover.md_position % session->ns_mover.md_record_size);
21247917SReza.Sabdar@Sun.COM 
21257917SReza.Sabdar@Sun.COM 	/*
21267917SReza.Sabdar@Sun.COM 	 * Determine the data stream position of the next byte that
21277917SReza.Sabdar@Sun.COM 	 * will be read from tape.
21287917SReza.Sabdar@Sun.COM 	 */
21297917SReza.Sabdar@Sun.COM 	tape_position = buf_position;
21307917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_w_index != 0)
21317917SReza.Sabdar@Sun.COM 		tape_position += session->ns_mover.md_record_size;
21327917SReza.Sabdar@Sun.COM 
21337917SReza.Sabdar@Sun.COM 	/*
21347917SReza.Sabdar@Sun.COM 	 * Check if requested position is for data that has been read and is
21357917SReza.Sabdar@Sun.COM 	 * in the buffer.
21367917SReza.Sabdar@Sun.COM 	 */
21377917SReza.Sabdar@Sun.COM 	if (offset >= buf_position && offset < tape_position) {
21387917SReza.Sabdar@Sun.COM 		session->ns_mover.md_position = offset;
21397917SReza.Sabdar@Sun.COM 		session->ns_mover.md_r_index = session->ns_mover.md_position -
21407917SReza.Sabdar@Sun.COM 		    buf_position;
21417917SReza.Sabdar@Sun.COM 
21427917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
21437917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_position,
21447917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_r_index);
21457917SReza.Sabdar@Sun.COM 
21467917SReza.Sabdar@Sun.COM 		return (0);
21477917SReza.Sabdar@Sun.COM 	}
21487917SReza.Sabdar@Sun.COM 
21497917SReza.Sabdar@Sun.COM 	ctlcmd = 0;
21507917SReza.Sabdar@Sun.COM 	if (tape_position > session->ns_mover.md_seek_position) {
21517917SReza.Sabdar@Sun.COM 		/* Need to seek backward. */
21527917SReza.Sabdar@Sun.COM 		ctlcmd = MTBSR;
21537917SReza.Sabdar@Sun.COM 		ctlcnt = (int)((tape_position - offset - 1)
21547917SReza.Sabdar@Sun.COM 		    / session->ns_mover.md_record_size) + 1;
21557917SReza.Sabdar@Sun.COM 		tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
21567917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_record_size) + 1) *
21577917SReza.Sabdar@Sun.COM 		    (u_longlong_t)session->ns_mover.md_record_size);
21587917SReza.Sabdar@Sun.COM 
21597917SReza.Sabdar@Sun.COM 	} else if (offset >= tape_position + session->ns_mover.md_record_size) {
21607917SReza.Sabdar@Sun.COM 		/* Need to seek forward. */
21617917SReza.Sabdar@Sun.COM 		ctlcmd = MTFSR;
21627917SReza.Sabdar@Sun.COM 		ctlcnt = (int)((offset - tape_position)
21637917SReza.Sabdar@Sun.COM 		    / session->ns_mover.md_record_size);
21647917SReza.Sabdar@Sun.COM 		tape_position += ((u_longlong_t)(((offset - tape_position) /
21657917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_record_size)) *
21667917SReza.Sabdar@Sun.COM 		    (u_longlong_t)session->ns_mover.md_record_size);
21677917SReza.Sabdar@Sun.COM 	}
21687917SReza.Sabdar@Sun.COM 	/* Reposition the tape if necessary. */
21697917SReza.Sabdar@Sun.COM 	if (ctlcmd) {
21707917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
21717917SReza.Sabdar@Sun.COM 		    ctlcmd, ctlcnt);
21727917SReza.Sabdar@Sun.COM 		(void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
21737917SReza.Sabdar@Sun.COM 	}
21747917SReza.Sabdar@Sun.COM 
21757917SReza.Sabdar@Sun.COM 	session->ns_mover.md_position = tape_position;
21767917SReza.Sabdar@Sun.COM 	session->ns_mover.md_r_index = 0;
21777917SReza.Sabdar@Sun.COM 	session->ns_mover.md_w_index = 0;
21787917SReza.Sabdar@Sun.COM 
21797917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
21807917SReza.Sabdar@Sun.COM 
21817917SReza.Sabdar@Sun.COM 	return (0);
21827917SReza.Sabdar@Sun.COM }
21837917SReza.Sabdar@Sun.COM 
21847917SReza.Sabdar@Sun.COM 
21857917SReza.Sabdar@Sun.COM /* ** static functions ************************************************** */
21867917SReza.Sabdar@Sun.COM 
21877917SReza.Sabdar@Sun.COM /*
21887917SReza.Sabdar@Sun.COM  * create_listen_socket_v2
21897917SReza.Sabdar@Sun.COM  *
21907917SReza.Sabdar@Sun.COM  * Creates a socket for listening for accepting data connections.
21917917SReza.Sabdar@Sun.COM  *
21927917SReza.Sabdar@Sun.COM  * Parameters:
21937917SReza.Sabdar@Sun.COM  *   session (input)  - session pointer.
21947917SReza.Sabdar@Sun.COM  *   addr    (output) - location to store address of socket.
21957917SReza.Sabdar@Sun.COM  *   port    (output) - location to store port of socket.
21967917SReza.Sabdar@Sun.COM  *
21977917SReza.Sabdar@Sun.COM  * Returns:
21987917SReza.Sabdar@Sun.COM  *   0 - success.
21997917SReza.Sabdar@Sun.COM  *  -1 - error.
22007917SReza.Sabdar@Sun.COM  */
22017917SReza.Sabdar@Sun.COM static int
22027917SReza.Sabdar@Sun.COM create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
22037917SReza.Sabdar@Sun.COM {
22047917SReza.Sabdar@Sun.COM 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
22057917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_listen_sock < 0)
22067917SReza.Sabdar@Sun.COM 		return (-1);
22077917SReza.Sabdar@Sun.COM 
22087917SReza.Sabdar@Sun.COM 	/*
22097917SReza.Sabdar@Sun.COM 	 * Add a file handler for the listen socket.
22107917SReza.Sabdar@Sun.COM 	 * ndmpd_select will call accept_connection when a
22117917SReza.Sabdar@Sun.COM 	 * connection is ready to be accepted.
22127917SReza.Sabdar@Sun.COM 	 */
22137917SReza.Sabdar@Sun.COM 	if (ndmpd_add_file_handler(session, (void *) session,
22147917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
22157917SReza.Sabdar@Sun.COM 	    accept_connection) < 0) {
22167917SReza.Sabdar@Sun.COM 		(void) close(session->ns_mover.md_listen_sock);
22177917SReza.Sabdar@Sun.COM 		session->ns_mover.md_listen_sock = -1;
22187917SReza.Sabdar@Sun.COM 		return (-1);
22197917SReza.Sabdar@Sun.COM 	}
22207917SReza.Sabdar@Sun.COM 
22217917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
22227917SReza.Sabdar@Sun.COM 	return (0);
22237917SReza.Sabdar@Sun.COM }
22247917SReza.Sabdar@Sun.COM 
22257917SReza.Sabdar@Sun.COM 
22267917SReza.Sabdar@Sun.COM /*
22277917SReza.Sabdar@Sun.COM  * accept_connection
22287917SReza.Sabdar@Sun.COM  *
22297917SReza.Sabdar@Sun.COM  * Accept a data connection from a data server.
22307917SReza.Sabdar@Sun.COM  * Called by ndmpd_select when a connection is pending on
22317917SReza.Sabdar@Sun.COM  * the mover listen socket.
22327917SReza.Sabdar@Sun.COM  *
22337917SReza.Sabdar@Sun.COM  * Parameters:
22347917SReza.Sabdar@Sun.COM  *   cookie  (input) - session pointer.
22357917SReza.Sabdar@Sun.COM  *   fd      (input) - file descriptor.
22367917SReza.Sabdar@Sun.COM  *   mode    (input) - select mode.
22377917SReza.Sabdar@Sun.COM  *
22387917SReza.Sabdar@Sun.COM  * Returns:
22397917SReza.Sabdar@Sun.COM  *   void.
22407917SReza.Sabdar@Sun.COM  */
22417917SReza.Sabdar@Sun.COM /*ARGSUSED*/
22427917SReza.Sabdar@Sun.COM static void
22437917SReza.Sabdar@Sun.COM accept_connection(void *cookie, int fd, ulong_t mode)
22447917SReza.Sabdar@Sun.COM {
22457917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
22467917SReza.Sabdar@Sun.COM 	struct sockaddr_in from;
22477917SReza.Sabdar@Sun.COM 	int from_len;
22487917SReza.Sabdar@Sun.COM 	int flag = 1;
22497917SReza.Sabdar@Sun.COM 
22507917SReza.Sabdar@Sun.COM 	from_len = sizeof (from);
22517917SReza.Sabdar@Sun.COM 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
22527917SReza.Sabdar@Sun.COM 	    &from_len);
22537917SReza.Sabdar@Sun.COM 
22547917SReza.Sabdar@Sun.COM 	(void) ndmpd_remove_file_handler(session, fd);
22557917SReza.Sabdar@Sun.COM 	(void) close(session->ns_mover.md_listen_sock);
22567917SReza.Sabdar@Sun.COM 	session->ns_mover.md_listen_sock = -1;
22577917SReza.Sabdar@Sun.COM 
22587917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_sock < 0) {
22597917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
22607917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
22617917SReza.Sabdar@Sun.COM 		return;
22627917SReza.Sabdar@Sun.COM 	}
22637917SReza.Sabdar@Sun.COM 
22647917SReza.Sabdar@Sun.COM 	(void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE,
22657917SReza.Sabdar@Sun.COM 	    &flag, sizeof (flag));
22667917SReza.Sabdar@Sun.COM 	ndmp_set_socket_nodelay(session->ns_mover.md_sock);
22677917SReza.Sabdar@Sun.COM 	ndmp_set_socket_rcv_buf(session->ns_mover.md_sock, 60 * KILOBYTE);
22687917SReza.Sabdar@Sun.COM 	ndmp_set_socket_snd_buf(session->ns_mover.md_sock, 60 * KILOBYTE);
22697917SReza.Sabdar@Sun.COM 
22707917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
22717917SReza.Sabdar@Sun.COM 
22727917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
22737917SReza.Sabdar@Sun.COM 		if (start_mover_for_backup(session) < 0) {
22747917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
22757917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
22767917SReza.Sabdar@Sun.COM 			return;
22777917SReza.Sabdar@Sun.COM 		}
22787917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
22797917SReza.Sabdar@Sun.COM 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
22807917SReza.Sabdar@Sun.COM 		    ntohs(from.sin_port));
22817917SReza.Sabdar@Sun.COM 	} else {
22827917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
22837917SReza.Sabdar@Sun.COM 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
22847917SReza.Sabdar@Sun.COM 		    ntohs(from.sin_port));
22857917SReza.Sabdar@Sun.COM 	}
22867917SReza.Sabdar@Sun.COM 
22877917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "Received connection");
22887917SReza.Sabdar@Sun.COM 
22897917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
22907917SReza.Sabdar@Sun.COM }
22917917SReza.Sabdar@Sun.COM 
22927917SReza.Sabdar@Sun.COM /*
22937917SReza.Sabdar@Sun.COM  * tape_write
22947917SReza.Sabdar@Sun.COM  *
22957917SReza.Sabdar@Sun.COM  * Writes a data record to tape. Detects and handles EOT conditions.
22967917SReza.Sabdar@Sun.COM  *
22977917SReza.Sabdar@Sun.COM  * Parameters:
22987917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
22997917SReza.Sabdar@Sun.COM  *   data    (input) - data to be written.
23007917SReza.Sabdar@Sun.COM  *   length  (input) - length of data to be written.
23017917SReza.Sabdar@Sun.COM  *
23027917SReza.Sabdar@Sun.COM  * Returns:
23037917SReza.Sabdar@Sun.COM  *    0 - operation aborted by client.
23047917SReza.Sabdar@Sun.COM  *   -1 - error.
23057917SReza.Sabdar@Sun.COM  *   otherwise - number of bytes written.
23067917SReza.Sabdar@Sun.COM  */
23077917SReza.Sabdar@Sun.COM static int
23087917SReza.Sabdar@Sun.COM tape_write(ndmpd_session_t *session, char *data, ssize_t length)
23097917SReza.Sabdar@Sun.COM {
23107917SReza.Sabdar@Sun.COM 	ssize_t n;
23117917SReza.Sabdar@Sun.COM 	int err;
23127917SReza.Sabdar@Sun.COM 
23137917SReza.Sabdar@Sun.COM 	for (; ; ) {
23147917SReza.Sabdar@Sun.COM 		/*
23157917SReza.Sabdar@Sun.COM 		 * Refer to the comment at the top of ndmpd_tape.c file for
23167917SReza.Sabdar@Sun.COM 		 * Mammoth2 tape drives.
23177917SReza.Sabdar@Sun.COM 		 */
23187917SReza.Sabdar@Sun.COM 		if (session->ns_tape.td_eom_seen) {
23197917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "eom_seen");
23207917SReza.Sabdar@Sun.COM 			session->ns_tape.td_eom_seen = FALSE;
23217917SReza.Sabdar@Sun.COM 			/*
23227917SReza.Sabdar@Sun.COM 			 * End of media reached.
23237917SReza.Sabdar@Sun.COM 			 * Notify client and wait for the client to
23247917SReza.Sabdar@Sun.COM 			 * either abort the operation or continue the
23257917SReza.Sabdar@Sun.COM 			 * operation after changing the tape.
23267917SReza.Sabdar@Sun.COM 			 */
23277917SReza.Sabdar@Sun.COM 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
23287917SReza.Sabdar@Sun.COM 			    ++ndmp_log_msg_id,
23297917SReza.Sabdar@Sun.COM 			    "End of tape reached. Load next tape.\n");
23307917SReza.Sabdar@Sun.COM 
23317917SReza.Sabdar@Sun.COM 			err = change_tape(session);
23327917SReza.Sabdar@Sun.COM 
23337917SReza.Sabdar@Sun.COM 			/* Operation aborted or connection terminated? */
23347917SReza.Sabdar@Sun.COM 			if (err < 0)
23357917SReza.Sabdar@Sun.COM 				return (-1);
23367917SReza.Sabdar@Sun.COM 
23377917SReza.Sabdar@Sun.COM 			continue;
23387917SReza.Sabdar@Sun.COM 		}
23397917SReza.Sabdar@Sun.COM 
23407917SReza.Sabdar@Sun.COM 		n = write(session->ns_tape.td_fd, data, length);
23417917SReza.Sabdar@Sun.COM 		if (n < 0) {
23427917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
23437917SReza.Sabdar@Sun.COM 			return (-1);
23447917SReza.Sabdar@Sun.COM 		}
23457917SReza.Sabdar@Sun.COM 		NS_ADD(wtape, n);
23467917SReza.Sabdar@Sun.COM 
23477917SReza.Sabdar@Sun.COM 		if (n == 0 || n != length) {
23487917SReza.Sabdar@Sun.COM 			if (n != 0) {
23497917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG, "LEOT n: %d", n);
23507917SReza.Sabdar@Sun.COM 
23517917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG, "Backup one record");
23527917SReza.Sabdar@Sun.COM 				(void) ndmp_mtioctl(session->ns_tape.td_fd,
23537917SReza.Sabdar@Sun.COM 				    MTBSR, 1);
23547917SReza.Sabdar@Sun.COM 
23557917SReza.Sabdar@Sun.COM 				/* setting logical EOM */
23567917SReza.Sabdar@Sun.COM 				ndmpd_write_eom(session->ns_tape.td_fd);
23577917SReza.Sabdar@Sun.COM 			}
23587917SReza.Sabdar@Sun.COM 
23597917SReza.Sabdar@Sun.COM 			/*
23607917SReza.Sabdar@Sun.COM 			 * End of media reached.
23617917SReza.Sabdar@Sun.COM 			 * Notify client and wait for the client to
23627917SReza.Sabdar@Sun.COM 			 * either abort the operation or continue the
23637917SReza.Sabdar@Sun.COM 			 * operation after changing the tape.
23647917SReza.Sabdar@Sun.COM 			 */
23657917SReza.Sabdar@Sun.COM 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
23667917SReza.Sabdar@Sun.COM 			    ++ndmp_log_msg_id,
23677917SReza.Sabdar@Sun.COM 			    "End of tape reached. Load next tape.\n");
23687917SReza.Sabdar@Sun.COM 
23697917SReza.Sabdar@Sun.COM 			err = change_tape(session);
23707917SReza.Sabdar@Sun.COM 
23717917SReza.Sabdar@Sun.COM 			/* Operation aborted or connection terminated? */
23727917SReza.Sabdar@Sun.COM 			if (err < 0)
23737917SReza.Sabdar@Sun.COM 				return (-1);
23747917SReza.Sabdar@Sun.COM 
23757917SReza.Sabdar@Sun.COM 			/* Retry the write to the new tape. */
23767917SReza.Sabdar@Sun.COM 			continue;
23777917SReza.Sabdar@Sun.COM 		}
23787917SReza.Sabdar@Sun.COM 
23797917SReza.Sabdar@Sun.COM 		session->ns_tape.td_record_count++;
23807917SReza.Sabdar@Sun.COM 		return (n);
23817917SReza.Sabdar@Sun.COM 	}
23827917SReza.Sabdar@Sun.COM }
23837917SReza.Sabdar@Sun.COM 
23847917SReza.Sabdar@Sun.COM 
23857917SReza.Sabdar@Sun.COM /*
23867917SReza.Sabdar@Sun.COM  * tape_read
23877917SReza.Sabdar@Sun.COM  *
23887917SReza.Sabdar@Sun.COM  * Reads a data record from tape. Detects and handles EOT conditions.
23897917SReza.Sabdar@Sun.COM  *
23907917SReza.Sabdar@Sun.COM  * Parameters:
23917917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
23927917SReza.Sabdar@Sun.COM  *   data    (input) - location to read data to.
23937917SReza.Sabdar@Sun.COM  *
23947917SReza.Sabdar@Sun.COM  * Returns:
23957917SReza.Sabdar@Sun.COM  *    0 - operation aborted.
23967917SReza.Sabdar@Sun.COM  *   -1 - tape read error.
23977917SReza.Sabdar@Sun.COM  *   otherwise - number of bytes read.
23987917SReza.Sabdar@Sun.COM  */
23997917SReza.Sabdar@Sun.COM static int
24007917SReza.Sabdar@Sun.COM tape_read(ndmpd_session_t *session, char *data)
24017917SReza.Sabdar@Sun.COM {
24027917SReza.Sabdar@Sun.COM 	ssize_t n;
24037917SReza.Sabdar@Sun.COM 	int err;
24047917SReza.Sabdar@Sun.COM 	int count = session->ns_mover.md_record_size;
24057917SReza.Sabdar@Sun.COM 
24067917SReza.Sabdar@Sun.COM 	for (; ; ) {
24077917SReza.Sabdar@Sun.COM 		n = read(session->ns_tape.td_fd, data, count);
24087917SReza.Sabdar@Sun.COM 		if (n < 0) {
24097917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
24107917SReza.Sabdar@Sun.COM 			return (TAPE_READ_ERR);
24117917SReza.Sabdar@Sun.COM 		}
24127917SReza.Sabdar@Sun.COM 		NS_ADD(rtape, n);
24137917SReza.Sabdar@Sun.COM 
24147917SReza.Sabdar@Sun.COM 		if (n == 0) {
24157917SReza.Sabdar@Sun.COM 			if (!is_writer_running(session))
24167917SReza.Sabdar@Sun.COM 				return (TAPE_NO_WRITER_ERR);
24177917SReza.Sabdar@Sun.COM 
24187917SReza.Sabdar@Sun.COM 			/*
24197917SReza.Sabdar@Sun.COM 			 * End of media reached.
24207917SReza.Sabdar@Sun.COM 			 * Notify client and wait for the client to
24217917SReza.Sabdar@Sun.COM 			 * either abort the data operation or continue the
24227917SReza.Sabdar@Sun.COM 			 * operation after changing the tape.
24237917SReza.Sabdar@Sun.COM 			 */
24247917SReza.Sabdar@Sun.COM 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
24257917SReza.Sabdar@Sun.COM 			    ++ndmp_log_msg_id,
24267917SReza.Sabdar@Sun.COM 			    "End of tape reached. Load next tape");
24277917SReza.Sabdar@Sun.COM 
24287917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
24297917SReza.Sabdar@Sun.COM 			    "End of tape reached. Load next tape");
24307917SReza.Sabdar@Sun.COM 
24317917SReza.Sabdar@Sun.COM 			err = change_tape(session);
24327917SReza.Sabdar@Sun.COM 
24337917SReza.Sabdar@Sun.COM 			/* Operation aborted or connection terminated? */
24347917SReza.Sabdar@Sun.COM 			if (err < 0) {
24357917SReza.Sabdar@Sun.COM 				/*
24367917SReza.Sabdar@Sun.COM 				 * K.L. Go back one record if it is read
24377917SReza.Sabdar@Sun.COM 				 * but not used.
24387917SReza.Sabdar@Sun.COM 				 */
24397917SReza.Sabdar@Sun.COM 
24407917SReza.Sabdar@Sun.COM 				if (count != session->ns_mover.md_record_size) {
24417917SReza.Sabdar@Sun.COM 					(void) ndmp_mtioctl(
24427917SReza.Sabdar@Sun.COM 					    session->ns_tape.td_fd, MTBSR, 1);
24437917SReza.Sabdar@Sun.COM 				}
24447917SReza.Sabdar@Sun.COM 				return (0);
24457917SReza.Sabdar@Sun.COM 			}
24467917SReza.Sabdar@Sun.COM 			/* Retry the read from the new tape. */
24477917SReza.Sabdar@Sun.COM 			continue;
24487917SReza.Sabdar@Sun.COM 		}
24497917SReza.Sabdar@Sun.COM 
24507917SReza.Sabdar@Sun.COM 		/* Change to pass Veritas Netbackup prequal test. */
24517917SReza.Sabdar@Sun.COM 		data += n;
24527917SReza.Sabdar@Sun.COM 		count -= n;
24537917SReza.Sabdar@Sun.COM 		if (count <= 0) {
24547917SReza.Sabdar@Sun.COM 			session->ns_mover.md_record_num++;
24557917SReza.Sabdar@Sun.COM 			session->ns_tape.td_record_count++;
24567917SReza.Sabdar@Sun.COM 			return (n);
24577917SReza.Sabdar@Sun.COM 		}
24587917SReza.Sabdar@Sun.COM 	}
24597917SReza.Sabdar@Sun.COM }
24607917SReza.Sabdar@Sun.COM 
24617917SReza.Sabdar@Sun.COM /*
24627917SReza.Sabdar@Sun.COM  * change_tape
24637917SReza.Sabdar@Sun.COM  *
24647917SReza.Sabdar@Sun.COM  * Send a notify_pause request (protocol version 1) or
24657917SReza.Sabdar@Sun.COM  * notify_mover_pause request (protocol version 2) to the
24667917SReza.Sabdar@Sun.COM  * NDMP client to inform
24677917SReza.Sabdar@Sun.COM  * the client that a tape volume change is required.
24687917SReza.Sabdar@Sun.COM  * Process messages until the data/mover operation is either aborted
24697917SReza.Sabdar@Sun.COM  * or continued.
24707917SReza.Sabdar@Sun.COM  *
24717917SReza.Sabdar@Sun.COM  * Parameters:
24727917SReza.Sabdar@Sun.COM  *   client_data (input) - session pointer.
24737917SReza.Sabdar@Sun.COM  *
24747917SReza.Sabdar@Sun.COM  * Returns:
24757917SReza.Sabdar@Sun.COM  *   0 - operation has been continued.
24767917SReza.Sabdar@Sun.COM  *  -1 - operation has been aborted.
24777917SReza.Sabdar@Sun.COM  */
24787917SReza.Sabdar@Sun.COM static int
24797917SReza.Sabdar@Sun.COM change_tape(ndmpd_session_t *session)
24807917SReza.Sabdar@Sun.COM {
24817917SReza.Sabdar@Sun.COM 	ndmp_notify_mover_paused_request request;
24827917SReza.Sabdar@Sun.COM 
24837917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
24847917SReza.Sabdar@Sun.COM 
24857917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
24867917SReza.Sabdar@Sun.COM 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
24877917SReza.Sabdar@Sun.COM 	else
24887917SReza.Sabdar@Sun.COM 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
24897917SReza.Sabdar@Sun.COM 
24907917SReza.Sabdar@Sun.COM 	request.reason = session->ns_mover.md_pause_reason;
24917917SReza.Sabdar@Sun.COM 	request.seek_position = long_long_to_quad(0LL);
24927917SReza.Sabdar@Sun.COM 
24937917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
24947917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_pause_reason);
24957917SReza.Sabdar@Sun.COM 
24967917SReza.Sabdar@Sun.COM 	if (ndmp_send_request(session->ns_connection,
24977917SReza.Sabdar@Sun.COM 	    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
24987917SReza.Sabdar@Sun.COM 	    (void *) &request, 0) < 0) {
24997917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
25007917SReza.Sabdar@Sun.COM 		    "Sending notify_mover_paused request");
25017917SReza.Sabdar@Sun.COM 		return (-1);
25027917SReza.Sabdar@Sun.COM 	}
25037917SReza.Sabdar@Sun.COM 	/*
25047917SReza.Sabdar@Sun.COM 	 * Wait for until the state is changed by
25057917SReza.Sabdar@Sun.COM 	 * an abort or continue request.
25067917SReza.Sabdar@Sun.COM 	 */
25077917SReza.Sabdar@Sun.COM 	nlp_ref_nw(session);
25087917SReza.Sabdar@Sun.COM 	for (; ; ) {
25097917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "calling nlp_wait_nw()");
25107917SReza.Sabdar@Sun.COM 
25117917SReza.Sabdar@Sun.COM 		nlp_wait_nw(session);
25127917SReza.Sabdar@Sun.COM 
25137917SReza.Sabdar@Sun.COM 		if (nlp_event_rv_get(session) < 0) {
25147917SReza.Sabdar@Sun.COM 			nlp_unref_nw(session);
25157917SReza.Sabdar@Sun.COM 			return (-1);
25167917SReza.Sabdar@Sun.COM 		}
25177917SReza.Sabdar@Sun.COM 
25187917SReza.Sabdar@Sun.COM 		if (session->ns_eof == TRUE) {
25197917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "session->ns_eof == TRUE");
25207917SReza.Sabdar@Sun.COM 			nlp_unref_nw(session);
25217917SReza.Sabdar@Sun.COM 			return (-1);
25227917SReza.Sabdar@Sun.COM 		}
25237917SReza.Sabdar@Sun.COM 
25247917SReza.Sabdar@Sun.COM 		switch (session->ns_mover.md_state) {
25257917SReza.Sabdar@Sun.COM 		case NDMP_MOVER_STATE_ACTIVE:
25267917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
25277917SReza.Sabdar@Sun.COM 			    "mover.state: NDMP_MOVER_STATE_ACTIVE");
25287917SReza.Sabdar@Sun.COM 
25297917SReza.Sabdar@Sun.COM 			nlp_unref_nw(session);
25307917SReza.Sabdar@Sun.COM 			session->ns_tape.td_record_count = 0;
25317917SReza.Sabdar@Sun.COM 			return (0);
25327917SReza.Sabdar@Sun.COM 
25337917SReza.Sabdar@Sun.COM 		case NDMP_MOVER_STATE_PAUSED:
25347917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
25357917SReza.Sabdar@Sun.COM 			    "mover.state: NDMP_MOVER_STATE_PAUSED");
25367917SReza.Sabdar@Sun.COM 			continue;
25377917SReza.Sabdar@Sun.COM 
25387917SReza.Sabdar@Sun.COM 		default:
25397917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "default");
25407917SReza.Sabdar@Sun.COM 			nlp_unref_nw(session);
25417917SReza.Sabdar@Sun.COM 			return (-1);
25427917SReza.Sabdar@Sun.COM 		}
25437917SReza.Sabdar@Sun.COM 	}
25447917SReza.Sabdar@Sun.COM 
25457917SReza.Sabdar@Sun.COM 	/* nlp_unref_nw(session); - statement never reached */
25467917SReza.Sabdar@Sun.COM }
25477917SReza.Sabdar@Sun.COM 
25487917SReza.Sabdar@Sun.COM 
25497917SReza.Sabdar@Sun.COM /*
25507917SReza.Sabdar@Sun.COM  * discard_data
25517917SReza.Sabdar@Sun.COM  *
25527917SReza.Sabdar@Sun.COM  * Read and discard data from the data connection.
25537917SReza.Sabdar@Sun.COM  * Called when a module has called ndmpd_seek() prior to
25547917SReza.Sabdar@Sun.COM  * reading all of the data from the previous seek.
25557917SReza.Sabdar@Sun.COM  *
25567917SReza.Sabdar@Sun.COM  * Parameters:
25577917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
25587917SReza.Sabdar@Sun.COM  *
25597917SReza.Sabdar@Sun.COM  * Returns:
25607917SReza.Sabdar@Sun.COM  *   number of bytes read and discarded.
25617917SReza.Sabdar@Sun.COM  *  -1 - error.
25627917SReza.Sabdar@Sun.COM  */
25637917SReza.Sabdar@Sun.COM static int
25647917SReza.Sabdar@Sun.COM discard_data(ndmpd_session_t *session, ulong_t length)
25657917SReza.Sabdar@Sun.COM {
25667917SReza.Sabdar@Sun.COM 	int n;
25677917SReza.Sabdar@Sun.COM 	char *addr;
25687917SReza.Sabdar@Sun.COM 
25697917SReza.Sabdar@Sun.COM 	if ((addr = ndmp_malloc(length)) == NULL)
25707917SReza.Sabdar@Sun.COM 		return (-1);
25717917SReza.Sabdar@Sun.COM 
25727917SReza.Sabdar@Sun.COM 	/* Read and discard the data. */
25737917SReza.Sabdar@Sun.COM 	n = read(session->ns_mover.md_sock, addr, length);
25747917SReza.Sabdar@Sun.COM 	if (n < 0) {
25757917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
25767917SReza.Sabdar@Sun.COM 		free(addr);
25777917SReza.Sabdar@Sun.COM 		return (-1);
25787917SReza.Sabdar@Sun.COM 	}
25797917SReza.Sabdar@Sun.COM 
25807917SReza.Sabdar@Sun.COM 	free(addr);
25817917SReza.Sabdar@Sun.COM 	return (n);
25827917SReza.Sabdar@Sun.COM }
25837917SReza.Sabdar@Sun.COM 
25847917SReza.Sabdar@Sun.COM 
25857917SReza.Sabdar@Sun.COM /*
25867917SReza.Sabdar@Sun.COM  * mover_tape_read_one_buf
25877917SReza.Sabdar@Sun.COM  *
25887917SReza.Sabdar@Sun.COM  * Read one buffer from the tape. This is used by mover_tape_reader
25897917SReza.Sabdar@Sun.COM  *
25907917SReza.Sabdar@Sun.COM  * Parameters:
25917917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
25927917SReza.Sabdar@Sun.COM  *   buf (input) - buffer read
25937917SReza.Sabdar@Sun.COM  *
25947917SReza.Sabdar@Sun.COM  * Returns:
25957917SReza.Sabdar@Sun.COM  *   0: on success
25967917SReza.Sabdar@Sun.COM  *  -1: otherwise
25977917SReza.Sabdar@Sun.COM  */
25987917SReza.Sabdar@Sun.COM static int
25997917SReza.Sabdar@Sun.COM mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
26007917SReza.Sabdar@Sun.COM {
26017917SReza.Sabdar@Sun.COM 	int n;
26027917SReza.Sabdar@Sun.COM 
26037917SReza.Sabdar@Sun.COM 	tlm_buffer_mark_empty(buf);
26047917SReza.Sabdar@Sun.COM 
26057917SReza.Sabdar@Sun.COM 	/*
26067917SReza.Sabdar@Sun.COM 	 * If the end of the mover window has been reached,
26077917SReza.Sabdar@Sun.COM 	 * then notify the client that a seek is needed.
26087917SReza.Sabdar@Sun.COM 	 * Remove the file handler to prevent this function from
26097917SReza.Sabdar@Sun.COM 	 * being called. The handler will be reinstalled in
26107917SReza.Sabdar@Sun.COM 	 * ndmpd_mover_continue.
26117917SReza.Sabdar@Sun.COM 	 */
26127917SReza.Sabdar@Sun.COM 
26137917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_position >=
26147917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_window_offset +
26157917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_window_length) {
26167917SReza.Sabdar@Sun.COM 		ndmp_notify_mover_paused_request pause_request;
26177917SReza.Sabdar@Sun.COM 
26187917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "end of mover window");
26197917SReza.Sabdar@Sun.COM 
26207917SReza.Sabdar@Sun.COM 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
26217917SReza.Sabdar@Sun.COM 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
26227917SReza.Sabdar@Sun.COM 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
26237917SReza.Sabdar@Sun.COM 		pause_request.seek_position =
26247917SReza.Sabdar@Sun.COM 		    long_long_to_quad(session->ns_mover.md_position);
26257917SReza.Sabdar@Sun.COM 
26267917SReza.Sabdar@Sun.COM 		if (ndmp_send_request(session->ns_connection,
26277917SReza.Sabdar@Sun.COM 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
26287917SReza.Sabdar@Sun.COM 		    (void *) &pause_request, 0) < 0) {
26297917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
26307917SReza.Sabdar@Sun.COM 			    "Sending notify_mover_paused request");
26317917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
26327917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
26337917SReza.Sabdar@Sun.COM 		}
26347917SReza.Sabdar@Sun.COM 		buf->tb_errno = EIO;
26357917SReza.Sabdar@Sun.COM 		return (TAPE_READ_ERR);
26367917SReza.Sabdar@Sun.COM 	}
26377917SReza.Sabdar@Sun.COM 
26387917SReza.Sabdar@Sun.COM 	n = tape_read(session, buf->tb_buffer_data);
26397917SReza.Sabdar@Sun.COM 
26407917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
26417917SReza.Sabdar@Sun.COM 
26427917SReza.Sabdar@Sun.COM 	if (n <= 0) {
26437917SReza.Sabdar@Sun.COM 		if (n < 0)
26447917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
26457917SReza.Sabdar@Sun.COM 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
26467917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
26477917SReza.Sabdar@Sun.COM 		return (TAPE_READ_ERR);
26487917SReza.Sabdar@Sun.COM 	}
26497917SReza.Sabdar@Sun.COM 
26507917SReza.Sabdar@Sun.COM 	buf->tb_full = TRUE;
26517917SReza.Sabdar@Sun.COM 	buf->tb_buffer_size = session->ns_mover.md_record_size;
26527917SReza.Sabdar@Sun.COM 
26537917SReza.Sabdar@Sun.COM 	/*
26547917SReza.Sabdar@Sun.COM 	 * Discard data if the current data stream position is
26557917SReza.Sabdar@Sun.COM 	 * prior to the seek position. This is necessary if a seek
26567917SReza.Sabdar@Sun.COM 	 * request set the seek pointer to a position that is not a
26577917SReza.Sabdar@Sun.COM 	 * record boundary. The seek request handler can only position
26587917SReza.Sabdar@Sun.COM 	 * to the start of a record.
26597917SReza.Sabdar@Sun.COM 	 */
26607917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
26617917SReza.Sabdar@Sun.COM 		session->ns_mover.md_position =
26627917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_seek_position;
26637917SReza.Sabdar@Sun.COM 
26647917SReza.Sabdar@Sun.COM 	return (0);
26657917SReza.Sabdar@Sun.COM }
26667917SReza.Sabdar@Sun.COM 
26677917SReza.Sabdar@Sun.COM 
26687917SReza.Sabdar@Sun.COM /*
26697917SReza.Sabdar@Sun.COM  * mover_tape_reader
26707917SReza.Sabdar@Sun.COM  *
26717917SReza.Sabdar@Sun.COM  * Mover tape reader thread. It is launched when the mover is started
26727917SReza.Sabdar@Sun.COM  * for restore.
26737917SReza.Sabdar@Sun.COM  *
26747917SReza.Sabdar@Sun.COM  * Parameters:
26757917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
26767917SReza.Sabdar@Sun.COM  *
26777917SReza.Sabdar@Sun.COM  * Returns:
26787917SReza.Sabdar@Sun.COM  *   0: on success
26797917SReza.Sabdar@Sun.COM  *  -1: otherwise
26807917SReza.Sabdar@Sun.COM  */
26817917SReza.Sabdar@Sun.COM int
26827917SReza.Sabdar@Sun.COM mover_tape_reader(ndmpd_session_t *session)
26837917SReza.Sabdar@Sun.COM {
26847917SReza.Sabdar@Sun.COM 	int bidx;	/* buffer index */
26857917SReza.Sabdar@Sun.COM 	int rv;
26867917SReza.Sabdar@Sun.COM 	ndmp_lbr_params_t *nlp;
26877917SReza.Sabdar@Sun.COM 	tlm_buffer_t *buf;
26887917SReza.Sabdar@Sun.COM 	tlm_buffers_t *bufs;
26897917SReza.Sabdar@Sun.COM 	tlm_cmd_t *lcmd;	/* Local command */
26907917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;	/* Commands structure */
26917917SReza.Sabdar@Sun.COM 
26927917SReza.Sabdar@Sun.COM 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
26937917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
26947917SReza.Sabdar@Sun.COM 		return (-1);
26957917SReza.Sabdar@Sun.COM 	}
26967917SReza.Sabdar@Sun.COM 
26977917SReza.Sabdar@Sun.COM 	cmds = &nlp->nlp_cmds;
26987917SReza.Sabdar@Sun.COM 	lcmd = cmds->tcs_command;
26997917SReza.Sabdar@Sun.COM 	bufs = lcmd->tc_buffers;
27007917SReza.Sabdar@Sun.COM 
27017917SReza.Sabdar@Sun.COM 	lcmd->tc_ref++;
27027917SReza.Sabdar@Sun.COM 	cmds->tcs_reader_count++;
27037917SReza.Sabdar@Sun.COM 
27047917SReza.Sabdar@Sun.COM 	/*
27057917SReza.Sabdar@Sun.COM 	 * Let our parent thread know that we are running.
27067917SReza.Sabdar@Sun.COM 	 */
27077917SReza.Sabdar@Sun.COM 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
27087917SReza.Sabdar@Sun.COM 
27097917SReza.Sabdar@Sun.COM 	buf = tlm_buffer_in_buf(bufs, &bidx);
27107917SReza.Sabdar@Sun.COM 	while (cmds->tcs_reader == TLM_RESTORE_RUN &&
27117917SReza.Sabdar@Sun.COM 	    lcmd->tc_reader == TLM_RESTORE_RUN) {
27127917SReza.Sabdar@Sun.COM 		buf = tlm_buffer_in_buf(bufs, NULL);
27137917SReza.Sabdar@Sun.COM 
27147917SReza.Sabdar@Sun.COM 		if (buf->tb_full) {
27157917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
27167917SReza.Sabdar@Sun.COM 			/*
27177917SReza.Sabdar@Sun.COM 			 * The buffer is still full, wait for the consumer
27187917SReza.Sabdar@Sun.COM 			 * thread to use it.
27197917SReza.Sabdar@Sun.COM 			 */
27207917SReza.Sabdar@Sun.COM 			tlm_buffer_out_buf_timed_wait(bufs, 100);
27217917SReza.Sabdar@Sun.COM 
27227917SReza.Sabdar@Sun.COM 		} else {
27237917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "r%d", bidx);
27247917SReza.Sabdar@Sun.COM 
27257917SReza.Sabdar@Sun.COM 			rv = mover_tape_read_one_buf(session, buf);
27267917SReza.Sabdar@Sun.COM 			/*
27277917SReza.Sabdar@Sun.COM 			 * If there was an error while reading, such as
27287917SReza.Sabdar@Sun.COM 			 * end of stream.
27297917SReza.Sabdar@Sun.COM 			 */
27307917SReza.Sabdar@Sun.COM 			if (rv < 0) {
27317917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
27327917SReza.Sabdar@Sun.COM 				break;
27337917SReza.Sabdar@Sun.COM 			}
27347917SReza.Sabdar@Sun.COM 
27357917SReza.Sabdar@Sun.COM 			/*
27367917SReza.Sabdar@Sun.COM 			 * Can we do more buffering?
27377917SReza.Sabdar@Sun.COM 			 */
27387917SReza.Sabdar@Sun.COM 			if (is_buffer_erroneous(buf)) {
27397917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
27407917SReza.Sabdar@Sun.COM 				    "Exiting, errno: %d, eot: %d, eof: %d",
27417917SReza.Sabdar@Sun.COM 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
27427917SReza.Sabdar@Sun.COM 				break;
27437917SReza.Sabdar@Sun.COM 			}
27447917SReza.Sabdar@Sun.COM 
27457917SReza.Sabdar@Sun.COM 			(void) tlm_buffer_advance_in_idx(bufs);
27467917SReza.Sabdar@Sun.COM 			tlm_buffer_release_in_buf(bufs);
27477917SReza.Sabdar@Sun.COM 			bidx = bufs->tbs_buffer_in;
27487917SReza.Sabdar@Sun.COM 		}
27497917SReza.Sabdar@Sun.COM 	}
27507917SReza.Sabdar@Sun.COM 
27517917SReza.Sabdar@Sun.COM 	/* If the consumer is waiting for us, wake it up. */
27527917SReza.Sabdar@Sun.COM 	tlm_buffer_release_in_buf(bufs);
27537917SReza.Sabdar@Sun.COM 
27547917SReza.Sabdar@Sun.COM 	/*
27557917SReza.Sabdar@Sun.COM 	 * Clean up.
27567917SReza.Sabdar@Sun.COM 	 */
27577917SReza.Sabdar@Sun.COM 	cmds->tcs_reader_count--;
27587917SReza.Sabdar@Sun.COM 	lcmd->tc_ref--;
27597917SReza.Sabdar@Sun.COM 	lcmd->tc_writer = TLM_STOP;
27607917SReza.Sabdar@Sun.COM 	return (0);
27617917SReza.Sabdar@Sun.COM }
27627917SReza.Sabdar@Sun.COM 
27637917SReza.Sabdar@Sun.COM 
27647917SReza.Sabdar@Sun.COM /*
27657917SReza.Sabdar@Sun.COM  * mover_socket_write_one_buf
27667917SReza.Sabdar@Sun.COM  *
27677917SReza.Sabdar@Sun.COM  * Write one buffer to the network socket. This is used by mover_socket_writer
27687917SReza.Sabdar@Sun.COM  *
27697917SReza.Sabdar@Sun.COM  * Parameters:
27707917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
27717917SReza.Sabdar@Sun.COM  *   buf (input) - buffer read
27727917SReza.Sabdar@Sun.COM  *
27737917SReza.Sabdar@Sun.COM  * Returns:
27747917SReza.Sabdar@Sun.COM  *   0: on success
27757917SReza.Sabdar@Sun.COM  *  -1: otherwise
27767917SReza.Sabdar@Sun.COM  */
27777917SReza.Sabdar@Sun.COM static int
27787917SReza.Sabdar@Sun.COM mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
27797917SReza.Sabdar@Sun.COM {
27807917SReza.Sabdar@Sun.COM 	int n;
27817917SReza.Sabdar@Sun.COM 
27827917SReza.Sabdar@Sun.COM 	/* Write the data to the data connection. */
27837917SReza.Sabdar@Sun.COM 	errno = 0;
27847917SReza.Sabdar@Sun.COM 	n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
27857917SReza.Sabdar@Sun.COM 	    buf->tb_buffer_size);
27867917SReza.Sabdar@Sun.COM 
27877917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
27887917SReza.Sabdar@Sun.COM 
27897917SReza.Sabdar@Sun.COM 	if (n < 0) {
27907917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
27917917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
27927917SReza.Sabdar@Sun.COM 		return (-1);
27937917SReza.Sabdar@Sun.COM 	}
27947917SReza.Sabdar@Sun.COM 
27957917SReza.Sabdar@Sun.COM 	session->ns_mover.md_position += n;
27967917SReza.Sabdar@Sun.COM 	session->ns_mover.md_bytes_left_to_read -= n;
27977917SReza.Sabdar@Sun.COM 	tlm_buffer_mark_empty(buf);
27987917SReza.Sabdar@Sun.COM 
27997917SReza.Sabdar@Sun.COM 	/*
28007917SReza.Sabdar@Sun.COM 	 * If the read limit has been reached,
28017917SReza.Sabdar@Sun.COM 	 * then remove the file handler to prevent this
28027917SReza.Sabdar@Sun.COM 	 * function from getting called. The next mover_read request
28037917SReza.Sabdar@Sun.COM 	 * will reinstall the handler.
28047917SReza.Sabdar@Sun.COM 	 */
28057917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_bytes_left_to_read == 0) {
28067917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
28077917SReza.Sabdar@Sun.COM 		(void) ndmpd_remove_file_handler(session,
28087917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_sock);
28097917SReza.Sabdar@Sun.COM 		return (-1);
28107917SReza.Sabdar@Sun.COM 	}
28117917SReza.Sabdar@Sun.COM 
28127917SReza.Sabdar@Sun.COM 	return (0);
28137917SReza.Sabdar@Sun.COM }
28147917SReza.Sabdar@Sun.COM 
28157917SReza.Sabdar@Sun.COM 
28167917SReza.Sabdar@Sun.COM 
28177917SReza.Sabdar@Sun.COM /*
28187917SReza.Sabdar@Sun.COM  * mover_socket_writer
28197917SReza.Sabdar@Sun.COM  *
28207917SReza.Sabdar@Sun.COM  * Mover's socket writer thread. This thread sends the read buffer
28217917SReza.Sabdar@Sun.COM  * from the tape to the data server through the network socket.
28227917SReza.Sabdar@Sun.COM  *
28237917SReza.Sabdar@Sun.COM  * Parameters:
28247917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
28257917SReza.Sabdar@Sun.COM  *
28267917SReza.Sabdar@Sun.COM  * Returns:
28277917SReza.Sabdar@Sun.COM  *   0: on success
28287917SReza.Sabdar@Sun.COM  *  -1: otherwise
28297917SReza.Sabdar@Sun.COM  */
28307917SReza.Sabdar@Sun.COM int
28317917SReza.Sabdar@Sun.COM mover_socket_writer(ndmpd_session_t *session)
28327917SReza.Sabdar@Sun.COM {
28337917SReza.Sabdar@Sun.COM 	int bidx;	/* buffer index */
28347917SReza.Sabdar@Sun.COM 	ndmp_lbr_params_t *nlp;
28357917SReza.Sabdar@Sun.COM 	tlm_buffer_t *buf;
28367917SReza.Sabdar@Sun.COM 	tlm_buffers_t *bufs;
28377917SReza.Sabdar@Sun.COM 	tlm_cmd_t *lcmd;	/* Local command */
28387917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;	/* Commands structure */
28397917SReza.Sabdar@Sun.COM 
28407917SReza.Sabdar@Sun.COM 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
28417917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
28427917SReza.Sabdar@Sun.COM 		return (-1);
28437917SReza.Sabdar@Sun.COM 	}
28447917SReza.Sabdar@Sun.COM 
28457917SReza.Sabdar@Sun.COM 	cmds = &nlp->nlp_cmds;
28467917SReza.Sabdar@Sun.COM 	lcmd = cmds->tcs_command;
28477917SReza.Sabdar@Sun.COM 	bufs = lcmd->tc_buffers;
28487917SReza.Sabdar@Sun.COM 
28497917SReza.Sabdar@Sun.COM 	lcmd->tc_ref++;
28507917SReza.Sabdar@Sun.COM 	cmds->tcs_writer_count++;
28517917SReza.Sabdar@Sun.COM 
28527917SReza.Sabdar@Sun.COM 	/*
28537917SReza.Sabdar@Sun.COM 	 * Let our parent thread know that we are running.
28547917SReza.Sabdar@Sun.COM 	 */
28557917SReza.Sabdar@Sun.COM 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
28567917SReza.Sabdar@Sun.COM 
28577917SReza.Sabdar@Sun.COM 	bidx = bufs->tbs_buffer_out;
28587917SReza.Sabdar@Sun.COM 	while (cmds->tcs_writer != (int)TLM_ABORT &&
28597917SReza.Sabdar@Sun.COM 	    lcmd->tc_writer != (int)TLM_ABORT) {
28607917SReza.Sabdar@Sun.COM 		buf = &bufs->tbs_buffer[bidx];
28617917SReza.Sabdar@Sun.COM 
28627917SReza.Sabdar@Sun.COM 		if (buf->tb_full) {
28637917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "w%d", bidx);
28647917SReza.Sabdar@Sun.COM 
28657917SReza.Sabdar@Sun.COM 			if (mover_socket_write_one_buf(session, buf) < 0) {
28667917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
28677917SReza.Sabdar@Sun.COM 				    "mover_socket_write_one_buf() < 0");
28687917SReza.Sabdar@Sun.COM 				break;
28697917SReza.Sabdar@Sun.COM 			}
28707917SReza.Sabdar@Sun.COM 
28717917SReza.Sabdar@Sun.COM 			(void) tlm_buffer_advance_out_idx(bufs);
28727917SReza.Sabdar@Sun.COM 			tlm_buffer_release_out_buf(bufs);
28737917SReza.Sabdar@Sun.COM 			bidx = bufs->tbs_buffer_out;
28747917SReza.Sabdar@Sun.COM 		} else {
28757917SReza.Sabdar@Sun.COM 			if (lcmd->tc_writer != TLM_RESTORE_RUN) {
28767917SReza.Sabdar@Sun.COM 				/* No more data is coming, time to exit */
28777917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG, "Time to exit");
28787917SReza.Sabdar@Sun.COM 				break;
28797917SReza.Sabdar@Sun.COM 			}
28807917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
28817917SReza.Sabdar@Sun.COM 			/*
28827917SReza.Sabdar@Sun.COM 			 * The buffer is not full, wait for the producer
28837917SReza.Sabdar@Sun.COM 			 * thread to fill it.
28847917SReza.Sabdar@Sun.COM 			 */
2885*8800SReza.Sabdar@Sun.COM 			tlm_buffer_in_buf_timed_wait(bufs, 100);
28867917SReza.Sabdar@Sun.COM 		}
28877917SReza.Sabdar@Sun.COM 	}
28887917SReza.Sabdar@Sun.COM 
28897917SReza.Sabdar@Sun.COM 	if (cmds->tcs_writer == (int)TLM_ABORT)
28907917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
28917917SReza.Sabdar@Sun.COM 	if (lcmd->tc_writer == (int)TLM_ABORT)
28927917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
28937917SReza.Sabdar@Sun.COM 
28947917SReza.Sabdar@Sun.COM 	/* If the producer is waiting for us, wake it up. */
28957917SReza.Sabdar@Sun.COM 	tlm_buffer_release_out_buf(bufs);
28967917SReza.Sabdar@Sun.COM 
28977917SReza.Sabdar@Sun.COM 	/*
28987917SReza.Sabdar@Sun.COM 	 * Clean up.
28997917SReza.Sabdar@Sun.COM 	 */
29007917SReza.Sabdar@Sun.COM 	cmds->tcs_writer_count--;
29017917SReza.Sabdar@Sun.COM 	lcmd->tc_ref--;
29027917SReza.Sabdar@Sun.COM 	lcmd->tc_reader = TLM_STOP;
29037917SReza.Sabdar@Sun.COM 	return (0);
29047917SReza.Sabdar@Sun.COM }
29057917SReza.Sabdar@Sun.COM 
29067917SReza.Sabdar@Sun.COM 
29077917SReza.Sabdar@Sun.COM /*
29087917SReza.Sabdar@Sun.COM  * start_mover_for_restore
29097917SReza.Sabdar@Sun.COM  *
29107917SReza.Sabdar@Sun.COM  * Creates the mover tape reader and network writer threads for
29117917SReza.Sabdar@Sun.COM  * the mover to perform the 3-way restore.
29127917SReza.Sabdar@Sun.COM  *
29137917SReza.Sabdar@Sun.COM  * Parameters:
29147917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
29157917SReza.Sabdar@Sun.COM  *
29167917SReza.Sabdar@Sun.COM  * Returns:
29177917SReza.Sabdar@Sun.COM  *   0: on success
29187917SReza.Sabdar@Sun.COM  *  -1: otherwise
29197917SReza.Sabdar@Sun.COM  */
29207917SReza.Sabdar@Sun.COM static int
29217917SReza.Sabdar@Sun.COM start_mover_for_restore(ndmpd_session_t *session)
29227917SReza.Sabdar@Sun.COM {
29237917SReza.Sabdar@Sun.COM 	ndmp_lbr_params_t *nlp;
29247917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;
29257917SReza.Sabdar@Sun.COM 	long xfer_size;
29267917SReza.Sabdar@Sun.COM 	int rc;
29277917SReza.Sabdar@Sun.COM 
29287917SReza.Sabdar@Sun.COM 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
29297917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
29307917SReza.Sabdar@Sun.COM 		return (-1);
29317917SReza.Sabdar@Sun.COM 	}
29327917SReza.Sabdar@Sun.COM 
29337917SReza.Sabdar@Sun.COM 	cmds = &nlp->nlp_cmds;
29347917SReza.Sabdar@Sun.COM 	(void) memset(cmds, 0, sizeof (*cmds));
29357917SReza.Sabdar@Sun.COM 	cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
29367917SReza.Sabdar@Sun.COM 	xfer_size = ndmp_buffer_get_size(session);
29377917SReza.Sabdar@Sun.COM 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
29387917SReza.Sabdar@Sun.COM 	if (cmds->tcs_command == NULL)
29397917SReza.Sabdar@Sun.COM 		return (-1);
29407917SReza.Sabdar@Sun.COM 
29417917SReza.Sabdar@Sun.COM 	cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
29427917SReza.Sabdar@Sun.COM 	cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
29437917SReza.Sabdar@Sun.COM 
29447917SReza.Sabdar@Sun.COM 	/*
29457917SReza.Sabdar@Sun.COM 	 * We intentionnally don't wait for the threads to start since the
29467917SReza.Sabdar@Sun.COM 	 * reply of the request (which resulted in calling this function)
29477917SReza.Sabdar@Sun.COM 	 * must be sent to the client before probable errors are sent
29487917SReza.Sabdar@Sun.COM 	 * to the client.
29497917SReza.Sabdar@Sun.COM 	 */
29507917SReza.Sabdar@Sun.COM 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session);
29517917SReza.Sabdar@Sun.COM 	if (rc == 0) {
29527917SReza.Sabdar@Sun.COM 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
29537917SReza.Sabdar@Sun.COM 	} else {
29547917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
29557917SReza.Sabdar@Sun.COM 		    strerror(rc));
29567917SReza.Sabdar@Sun.COM 		return (-1);
29577917SReza.Sabdar@Sun.COM 	}
29587917SReza.Sabdar@Sun.COM 
29597917SReza.Sabdar@Sun.COM 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session);
29607917SReza.Sabdar@Sun.COM 	if (rc == 0) {
29617917SReza.Sabdar@Sun.COM 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
29627917SReza.Sabdar@Sun.COM 	} else {
29637917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
29647917SReza.Sabdar@Sun.COM 		    strerror(rc));
29657917SReza.Sabdar@Sun.COM 		return (-1);
29667917SReza.Sabdar@Sun.COM 	}
29677917SReza.Sabdar@Sun.COM 
29687917SReza.Sabdar@Sun.COM 	tlm_release_reader_writer_ipc(cmds->tcs_command);
29697917SReza.Sabdar@Sun.COM 	return (0);
29707917SReza.Sabdar@Sun.COM }
29717917SReza.Sabdar@Sun.COM 
29727917SReza.Sabdar@Sun.COM 
29737917SReza.Sabdar@Sun.COM /*
29747917SReza.Sabdar@Sun.COM  * mover_socket_read_one_buf
29757917SReza.Sabdar@Sun.COM  *
29767917SReza.Sabdar@Sun.COM  * Read one buffer from the network socket for the mover. This is used
29777917SReza.Sabdar@Sun.COM  * by mover_socket_reader
29787917SReza.Sabdar@Sun.COM  *
29797917SReza.Sabdar@Sun.COM  * Parameters:
29807917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
29817917SReza.Sabdar@Sun.COM  *   buf (input) - buffer read
29827917SReza.Sabdar@Sun.COM  *   read_size (input) - size to be read
29837917SReza.Sabdar@Sun.COM  *
29847917SReza.Sabdar@Sun.COM  * Returns:
29857917SReza.Sabdar@Sun.COM  *   0: on success
29867917SReza.Sabdar@Sun.COM  *  -1: otherwise
29877917SReza.Sabdar@Sun.COM  */
29887917SReza.Sabdar@Sun.COM static int
29897917SReza.Sabdar@Sun.COM mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
29907917SReza.Sabdar@Sun.COM     long read_size)
29917917SReza.Sabdar@Sun.COM {
29927917SReza.Sabdar@Sun.COM 	int n, index;
29937917SReza.Sabdar@Sun.COM 	long toread;
29947917SReza.Sabdar@Sun.COM 
29957917SReza.Sabdar@Sun.COM 	tlm_buffer_mark_empty(buf);
29967917SReza.Sabdar@Sun.COM 	for (index = 0, toread = read_size; toread > 0; ) {
29977917SReza.Sabdar@Sun.COM 		errno = 0;
29987917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
29997917SReza.Sabdar@Sun.COM 
30007917SReza.Sabdar@Sun.COM 		n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
30017917SReza.Sabdar@Sun.COM 		    toread);
30027917SReza.Sabdar@Sun.COM 		if (n == 0) {
30037917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
30047917SReza.Sabdar@Sun.COM 			break;
30057917SReza.Sabdar@Sun.COM 		} else if (n > 0) {
30067917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
30077917SReza.Sabdar@Sun.COM 			index += n;
30087917SReza.Sabdar@Sun.COM 			toread -= n;
30097917SReza.Sabdar@Sun.COM 		} else {
30107917SReza.Sabdar@Sun.COM 			buf->tb_eof = TRUE;
30117917SReza.Sabdar@Sun.COM 			buf->tb_errno = errno;
30127917SReza.Sabdar@Sun.COM 			buf->tb_buffer_size = 0;
30137917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
30147917SReza.Sabdar@Sun.COM 			return (-1);
30157917SReza.Sabdar@Sun.COM 		}
30167917SReza.Sabdar@Sun.COM 	}
30177917SReza.Sabdar@Sun.COM 
30187917SReza.Sabdar@Sun.COM 	if (index > 0) {
30197917SReza.Sabdar@Sun.COM 		buf->tb_full = TRUE;
30207917SReza.Sabdar@Sun.COM 		buf->tb_buffer_size = read_size;
30217917SReza.Sabdar@Sun.COM 		if (read_size > 0)
30227917SReza.Sabdar@Sun.COM 			(void) memset(&buf->tb_buffer_data[index], 0,
30237917SReza.Sabdar@Sun.COM 			    read_size - index);
30247917SReza.Sabdar@Sun.COM 	} else {
30257917SReza.Sabdar@Sun.COM 		buf->tb_eof = TRUE;
30267917SReza.Sabdar@Sun.COM 		buf->tb_buffer_size = 0;
30277917SReza.Sabdar@Sun.COM 	}
30287917SReza.Sabdar@Sun.COM 
30297917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
30307917SReza.Sabdar@Sun.COM 	    " errno: %d, size: %d, data: 0x%x",
30317917SReza.Sabdar@Sun.COM 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
30327917SReza.Sabdar@Sun.COM 	    buf->tb_buffer_size, buf->tb_buffer_data);
30337917SReza.Sabdar@Sun.COM 
30347917SReza.Sabdar@Sun.COM 	return (0);
30357917SReza.Sabdar@Sun.COM }
30367917SReza.Sabdar@Sun.COM 
30377917SReza.Sabdar@Sun.COM 
30387917SReza.Sabdar@Sun.COM 
30397917SReza.Sabdar@Sun.COM /*
30407917SReza.Sabdar@Sun.COM  * mover_socket_reader
30417917SReza.Sabdar@Sun.COM  *
30427917SReza.Sabdar@Sun.COM  * Mover socket reader thread. This is used when reading data from the
30437917SReza.Sabdar@Sun.COM  * network socket for performing remote backups.
30447917SReza.Sabdar@Sun.COM  *
30457917SReza.Sabdar@Sun.COM  * Parameters:
30467917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
30477917SReza.Sabdar@Sun.COM  *
30487917SReza.Sabdar@Sun.COM  * Returns:
30497917SReza.Sabdar@Sun.COM  *   0: on success
30507917SReza.Sabdar@Sun.COM  *  -1: otherwise
30517917SReza.Sabdar@Sun.COM  */
30527917SReza.Sabdar@Sun.COM int
30537917SReza.Sabdar@Sun.COM mover_socket_reader(ndmpd_session_t *session)
30547917SReza.Sabdar@Sun.COM {
30557917SReza.Sabdar@Sun.COM 	int bidx;	/* buffer index */
30567917SReza.Sabdar@Sun.COM 	ndmp_lbr_params_t *nlp;
30577917SReza.Sabdar@Sun.COM 	tlm_buffer_t *buf;
30587917SReza.Sabdar@Sun.COM 	tlm_buffers_t *bufs;
30597917SReza.Sabdar@Sun.COM 	tlm_cmd_t *lcmd;	/* Local command */
30607917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;	/* Commands structure */
30617917SReza.Sabdar@Sun.COM 	static int nr = 0;
30627917SReza.Sabdar@Sun.COM 
30637917SReza.Sabdar@Sun.COM 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
30647917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
30657917SReza.Sabdar@Sun.COM 		return (-1);
30667917SReza.Sabdar@Sun.COM 	}
30677917SReza.Sabdar@Sun.COM 
30687917SReza.Sabdar@Sun.COM 	cmds = &nlp->nlp_cmds;
30697917SReza.Sabdar@Sun.COM 	lcmd = cmds->tcs_command;
30707917SReza.Sabdar@Sun.COM 	bufs = lcmd->tc_buffers;
30717917SReza.Sabdar@Sun.COM 
30727917SReza.Sabdar@Sun.COM 	lcmd->tc_ref++;
30737917SReza.Sabdar@Sun.COM 	cmds->tcs_reader_count++;
30747917SReza.Sabdar@Sun.COM 
30757917SReza.Sabdar@Sun.COM 	/*
30767917SReza.Sabdar@Sun.COM 	 * Let our parent thread know that we are running.
30777917SReza.Sabdar@Sun.COM 	 */
30787917SReza.Sabdar@Sun.COM 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
30797917SReza.Sabdar@Sun.COM 
30807917SReza.Sabdar@Sun.COM 	bidx = bufs->tbs_buffer_in;
30817917SReza.Sabdar@Sun.COM 	while (cmds->tcs_reader == TLM_BACKUP_RUN &&
30827917SReza.Sabdar@Sun.COM 	    lcmd->tc_reader == TLM_BACKUP_RUN) {
30837917SReza.Sabdar@Sun.COM 		buf = &bufs->tbs_buffer[bidx];
30847917SReza.Sabdar@Sun.COM 
30857917SReza.Sabdar@Sun.COM 		if (buf->tb_full) {
30867917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
30877917SReza.Sabdar@Sun.COM 			/*
30887917SReza.Sabdar@Sun.COM 			 * The buffer is still full, wait for the consumer
30897917SReza.Sabdar@Sun.COM 			 * thread to use it.
30907917SReza.Sabdar@Sun.COM 			 */
30917917SReza.Sabdar@Sun.COM 			tlm_buffer_out_buf_timed_wait(bufs, 100);
30927917SReza.Sabdar@Sun.COM 		} else {
30937917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
30947917SReza.Sabdar@Sun.COM 
30957917SReza.Sabdar@Sun.COM 			(void) mover_socket_read_one_buf(session, buf,
30967917SReza.Sabdar@Sun.COM 			    bufs->tbs_data_transfer_size);
30977917SReza.Sabdar@Sun.COM 
30987917SReza.Sabdar@Sun.COM 			/*
30997917SReza.Sabdar@Sun.COM 			 * Can we do more buffering?
31007917SReza.Sabdar@Sun.COM 			 */
31017917SReza.Sabdar@Sun.COM 			if (is_buffer_erroneous(buf)) {
31027917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
31037917SReza.Sabdar@Sun.COM 				    "Exiting, errno: %d, eot: %d, eof: %d",
31047917SReza.Sabdar@Sun.COM 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
31057917SReza.Sabdar@Sun.COM 				break;
31067917SReza.Sabdar@Sun.COM 			}
31077917SReza.Sabdar@Sun.COM 
31087917SReza.Sabdar@Sun.COM 			(void) tlm_buffer_advance_in_idx(bufs);
31097917SReza.Sabdar@Sun.COM 			tlm_buffer_release_in_buf(bufs);
31107917SReza.Sabdar@Sun.COM 			bidx = bufs->tbs_buffer_in;
31117917SReza.Sabdar@Sun.COM 		}
31127917SReza.Sabdar@Sun.COM 	}
31137917SReza.Sabdar@Sun.COM 
31147917SReza.Sabdar@Sun.COM 	if (cmds->tcs_reader != TLM_BACKUP_RUN)
31157917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
31167917SReza.Sabdar@Sun.COM 	if (lcmd->tc_reader != TLM_BACKUP_RUN)
31177917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
31187917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
31197917SReza.Sabdar@Sun.COM 
31207917SReza.Sabdar@Sun.COM 	/* If the consumer is waiting for us, wake it up. */
31217917SReza.Sabdar@Sun.COM 	tlm_buffer_release_in_buf(bufs);
31227917SReza.Sabdar@Sun.COM 
31237917SReza.Sabdar@Sun.COM 	/*
31247917SReza.Sabdar@Sun.COM 	 * Clean up.
31257917SReza.Sabdar@Sun.COM 	 */
31267917SReza.Sabdar@Sun.COM 	cmds->tcs_reader_count--;
31277917SReza.Sabdar@Sun.COM 	lcmd->tc_ref--;
31287917SReza.Sabdar@Sun.COM 	lcmd->tc_writer = TLM_STOP;
31297917SReza.Sabdar@Sun.COM 	return (0);
31307917SReza.Sabdar@Sun.COM }
31317917SReza.Sabdar@Sun.COM 
31327917SReza.Sabdar@Sun.COM 
31337917SReza.Sabdar@Sun.COM /*
31347917SReza.Sabdar@Sun.COM  * mover_tape_writer_one_buf
31357917SReza.Sabdar@Sun.COM  *
31367917SReza.Sabdar@Sun.COM  * Write one buffer for the mover to the local tape device. This is
31377917SReza.Sabdar@Sun.COM  * used by mover_tape_writer thread.
31387917SReza.Sabdar@Sun.COM  *
31397917SReza.Sabdar@Sun.COM  * Parameters:
31407917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
31417917SReza.Sabdar@Sun.COM  *   buf (input) - buffer read
31427917SReza.Sabdar@Sun.COM  *
31437917SReza.Sabdar@Sun.COM  * Returns:
31447917SReza.Sabdar@Sun.COM  *   0: on success
31457917SReza.Sabdar@Sun.COM  *  -1: otherwise
31467917SReza.Sabdar@Sun.COM  */
31477917SReza.Sabdar@Sun.COM static int
31487917SReza.Sabdar@Sun.COM mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
31497917SReza.Sabdar@Sun.COM {
31507917SReza.Sabdar@Sun.COM 	int n;
31517917SReza.Sabdar@Sun.COM 
31527917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
31537917SReza.Sabdar@Sun.COM 	    " errno: %d, size: %d, data: 0x%x",
31547917SReza.Sabdar@Sun.COM 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
31557917SReza.Sabdar@Sun.COM 	    buf->tb_buffer_size, buf->tb_buffer_data);
31567917SReza.Sabdar@Sun.COM 
31577917SReza.Sabdar@Sun.COM 	n = tape_write(session, buf->tb_buffer_data, buf->tb_buffer_size);
31587917SReza.Sabdar@Sun.COM 
31597917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "n: %d", n);
31607917SReza.Sabdar@Sun.COM 
31617917SReza.Sabdar@Sun.COM 	if (n <= 0) {
31627917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
31637917SReza.Sabdar@Sun.COM 		    : NDMP_MOVER_HALT_INTERNAL_ERROR));
31647917SReza.Sabdar@Sun.COM 		return (-1);
31657917SReza.Sabdar@Sun.COM 	}
31667917SReza.Sabdar@Sun.COM 	session->ns_mover.md_position += n;
31677917SReza.Sabdar@Sun.COM 	session->ns_mover.md_data_written += n;
31687917SReza.Sabdar@Sun.COM 	session->ns_mover.md_record_num++;
31697917SReza.Sabdar@Sun.COM 
31707917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
31717917SReza.Sabdar@Sun.COM 	tlm_buffer_mark_empty(buf);
31727917SReza.Sabdar@Sun.COM 
31737917SReza.Sabdar@Sun.COM 	return (0);
31747917SReza.Sabdar@Sun.COM }
31757917SReza.Sabdar@Sun.COM 
31767917SReza.Sabdar@Sun.COM 
31777917SReza.Sabdar@Sun.COM /*
31787917SReza.Sabdar@Sun.COM  * mover_tape_writer
31797917SReza.Sabdar@Sun.COM  *
31807917SReza.Sabdar@Sun.COM  * Mover tape writer thread. This is used for performing remote backups
31817917SReza.Sabdar@Sun.COM  * in a 3-way configuration. It writes the data from network socket to
31827917SReza.Sabdar@Sun.COM  * the locally attached tape device.
31837917SReza.Sabdar@Sun.COM  *
31847917SReza.Sabdar@Sun.COM  * Parameters:
31857917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
31867917SReza.Sabdar@Sun.COM  *
31877917SReza.Sabdar@Sun.COM  * Returns:
31887917SReza.Sabdar@Sun.COM  *   0: on success
31897917SReza.Sabdar@Sun.COM  *  -1: otherwise
31907917SReza.Sabdar@Sun.COM  */
31917917SReza.Sabdar@Sun.COM int
31927917SReza.Sabdar@Sun.COM mover_tape_writer(ndmpd_session_t *session)
31937917SReza.Sabdar@Sun.COM {
31947917SReza.Sabdar@Sun.COM 	int bidx;
31957917SReza.Sabdar@Sun.COM 	ndmp_lbr_params_t *nlp;
31967917SReza.Sabdar@Sun.COM 	tlm_buffer_t *buf;
31977917SReza.Sabdar@Sun.COM 	tlm_buffers_t *bufs;
31987917SReza.Sabdar@Sun.COM 	tlm_cmd_t *lcmd;
31997917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;
32007917SReza.Sabdar@Sun.COM 	static int nw = 0;
32017917SReza.Sabdar@Sun.COM 
32027917SReza.Sabdar@Sun.COM 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
32037917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
32047917SReza.Sabdar@Sun.COM 		return (-1);
32057917SReza.Sabdar@Sun.COM 	}
32067917SReza.Sabdar@Sun.COM 
32077917SReza.Sabdar@Sun.COM 	cmds = &nlp->nlp_cmds;
32087917SReza.Sabdar@Sun.COM 	lcmd = cmds->tcs_command;
32097917SReza.Sabdar@Sun.COM 	bufs = lcmd->tc_buffers;
32107917SReza.Sabdar@Sun.COM 
32117917SReza.Sabdar@Sun.COM 	lcmd->tc_ref++;
32127917SReza.Sabdar@Sun.COM 	cmds->tcs_writer_count++;
32137917SReza.Sabdar@Sun.COM 
32147917SReza.Sabdar@Sun.COM 	/*
32157917SReza.Sabdar@Sun.COM 	 * Let our parent thread know that we are running.
32167917SReza.Sabdar@Sun.COM 	 */
32177917SReza.Sabdar@Sun.COM 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
32187917SReza.Sabdar@Sun.COM 
32197917SReza.Sabdar@Sun.COM 	bidx = bufs->tbs_buffer_out;
32207917SReza.Sabdar@Sun.COM 	buf = &bufs->tbs_buffer[bidx];
32217917SReza.Sabdar@Sun.COM 	while (cmds->tcs_writer != (int)TLM_ABORT &&
32227917SReza.Sabdar@Sun.COM 	    lcmd->tc_writer != (int)TLM_ABORT) {
32237917SReza.Sabdar@Sun.COM 		if (buf->tb_full) {
32247917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
32257917SReza.Sabdar@Sun.COM 
32267917SReza.Sabdar@Sun.COM 			if (mover_tape_write_one_buf(session, buf) < 0) {
32277917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
32287917SReza.Sabdar@Sun.COM 				    "mover_tape_write_one_buf() failed");
32297917SReza.Sabdar@Sun.COM 				break;
32307917SReza.Sabdar@Sun.COM 			}
32317917SReza.Sabdar@Sun.COM 
32327917SReza.Sabdar@Sun.COM 			(void) tlm_buffer_advance_out_idx(bufs);
32337917SReza.Sabdar@Sun.COM 			tlm_buffer_release_out_buf(bufs);
32347917SReza.Sabdar@Sun.COM 			bidx = bufs->tbs_buffer_out;
32357917SReza.Sabdar@Sun.COM 			buf = &bufs->tbs_buffer[bidx];
32367917SReza.Sabdar@Sun.COM 		} else {
32377917SReza.Sabdar@Sun.COM 			if (lcmd->tc_writer != TLM_BACKUP_RUN) {
32387917SReza.Sabdar@Sun.COM 				/* No more data is coming, time to exit */
32397917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG, "Time to exit");
32407917SReza.Sabdar@Sun.COM 				break;
32417917SReza.Sabdar@Sun.COM 			}
32427917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
32437917SReza.Sabdar@Sun.COM 			/*
32447917SReza.Sabdar@Sun.COM 			 * The buffer is not full, wait for the producer
32457917SReza.Sabdar@Sun.COM 			 * thread to fill it.
32467917SReza.Sabdar@Sun.COM 			 */
32477917SReza.Sabdar@Sun.COM 			tlm_buffer_in_buf_timed_wait(bufs, 100);
32487917SReza.Sabdar@Sun.COM 		}
32497917SReza.Sabdar@Sun.COM 	}
32507917SReza.Sabdar@Sun.COM 
32517917SReza.Sabdar@Sun.COM 	if (cmds->tcs_writer == (int)TLM_ABORT)
32527917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
32537917SReza.Sabdar@Sun.COM 	if (lcmd->tc_writer == (int)TLM_ABORT)
32547917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
32557917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
32567917SReza.Sabdar@Sun.COM 
32577917SReza.Sabdar@Sun.COM 	if (buf->tb_errno == 0) {
32587917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
32597917SReza.Sabdar@Sun.COM 	} else {
32607917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
32617917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
32627917SReza.Sabdar@Sun.COM 	}
32637917SReza.Sabdar@Sun.COM 
32647917SReza.Sabdar@Sun.COM 	/* If the producer is waiting for us, wake it up. */
32657917SReza.Sabdar@Sun.COM 	tlm_buffer_release_out_buf(bufs);
32667917SReza.Sabdar@Sun.COM 
32677917SReza.Sabdar@Sun.COM 	/*
32687917SReza.Sabdar@Sun.COM 	 * Clean up.
32697917SReza.Sabdar@Sun.COM 	 */
32707917SReza.Sabdar@Sun.COM 	cmds->tcs_writer_count--;
32717917SReza.Sabdar@Sun.COM 	lcmd->tc_ref--;
32727917SReza.Sabdar@Sun.COM 	lcmd->tc_reader = TLM_STOP;
32737917SReza.Sabdar@Sun.COM 	return (0);
32747917SReza.Sabdar@Sun.COM }
32757917SReza.Sabdar@Sun.COM 
32767917SReza.Sabdar@Sun.COM 
32777917SReza.Sabdar@Sun.COM /*
32787917SReza.Sabdar@Sun.COM  * start_mover_for_backup
32797917SReza.Sabdar@Sun.COM  *
32807917SReza.Sabdar@Sun.COM  * Starts a remote backup by running socket reader and tape
32817917SReza.Sabdar@Sun.COM  * writer threads. The mover runs a remote backup in a 3-way backup
32827917SReza.Sabdar@Sun.COM  * configuration.
32837917SReza.Sabdar@Sun.COM  *
32847917SReza.Sabdar@Sun.COM  * Parameters:
32857917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
32867917SReza.Sabdar@Sun.COM  *
32877917SReza.Sabdar@Sun.COM  * Returns:
32887917SReza.Sabdar@Sun.COM  *   0: on success
32897917SReza.Sabdar@Sun.COM  *  -1: otherwise
32907917SReza.Sabdar@Sun.COM  */
32917917SReza.Sabdar@Sun.COM static int
32927917SReza.Sabdar@Sun.COM start_mover_for_backup(ndmpd_session_t *session)
32937917SReza.Sabdar@Sun.COM {
32947917SReza.Sabdar@Sun.COM 	ndmp_lbr_params_t *nlp;
32957917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;
32967917SReza.Sabdar@Sun.COM 	int rc;
32977917SReza.Sabdar@Sun.COM 
32987917SReza.Sabdar@Sun.COM 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
32997917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
33007917SReza.Sabdar@Sun.COM 		return (-1);
33017917SReza.Sabdar@Sun.COM 	}
33027917SReza.Sabdar@Sun.COM 
33037917SReza.Sabdar@Sun.COM 	cmds = &nlp->nlp_cmds;
33047917SReza.Sabdar@Sun.COM 	(void) memset(cmds, 0, sizeof (*cmds));
33057917SReza.Sabdar@Sun.COM 	cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
33067917SReza.Sabdar@Sun.COM 	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
33077917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_record_size);
33087917SReza.Sabdar@Sun.COM 	if (cmds->tcs_command == NULL)
33097917SReza.Sabdar@Sun.COM 		return (-1);
33107917SReza.Sabdar@Sun.COM 
33117917SReza.Sabdar@Sun.COM 	cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
33127917SReza.Sabdar@Sun.COM 	cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
33137917SReza.Sabdar@Sun.COM 
33147917SReza.Sabdar@Sun.COM 	/*
33157917SReza.Sabdar@Sun.COM 	 * We intentionally don't wait for the threads to start since the
33167917SReza.Sabdar@Sun.COM 	 * reply of the request (which resulted in calling this function)
33177917SReza.Sabdar@Sun.COM 	 * must be sent to the client before probable errors are sent
33187917SReza.Sabdar@Sun.COM 	 * to the client.
33197917SReza.Sabdar@Sun.COM 	 */
33207917SReza.Sabdar@Sun.COM 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session);
33217917SReza.Sabdar@Sun.COM 	if (rc == 0) {
33227917SReza.Sabdar@Sun.COM 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
33237917SReza.Sabdar@Sun.COM 	} else {
33247917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
33257917SReza.Sabdar@Sun.COM 		    strerror(rc));
33267917SReza.Sabdar@Sun.COM 		return (-1);
33277917SReza.Sabdar@Sun.COM 	}
33287917SReza.Sabdar@Sun.COM 
33297917SReza.Sabdar@Sun.COM 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session);
33307917SReza.Sabdar@Sun.COM 	if (rc == 0) {
33317917SReza.Sabdar@Sun.COM 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
33327917SReza.Sabdar@Sun.COM 	} else {
33337917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
33347917SReza.Sabdar@Sun.COM 		    strerror(rc));
33357917SReza.Sabdar@Sun.COM 		return (-1);
33367917SReza.Sabdar@Sun.COM 	}
33377917SReza.Sabdar@Sun.COM 
33387917SReza.Sabdar@Sun.COM 	tlm_release_reader_writer_ipc(cmds->tcs_command);
33397917SReza.Sabdar@Sun.COM 	return (0);
33407917SReza.Sabdar@Sun.COM }
33417917SReza.Sabdar@Sun.COM 
33427917SReza.Sabdar@Sun.COM 
33437917SReza.Sabdar@Sun.COM /*
33447917SReza.Sabdar@Sun.COM  * is_writer_running
33457917SReza.Sabdar@Sun.COM  *
33467917SReza.Sabdar@Sun.COM  * Find out if the writer thread has started or not.
33477917SReza.Sabdar@Sun.COM  *
33487917SReza.Sabdar@Sun.COM  * Parameters:
33497917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
33507917SReza.Sabdar@Sun.COM  *
33517917SReza.Sabdar@Sun.COM  * Returns:
33527917SReza.Sabdar@Sun.COM  *   0: not started
33537917SReza.Sabdar@Sun.COM  *   non-zero: started
33547917SReza.Sabdar@Sun.COM  */
33557917SReza.Sabdar@Sun.COM static boolean_t
33567917SReza.Sabdar@Sun.COM is_writer_running(ndmpd_session_t *session)
33577917SReza.Sabdar@Sun.COM {
33587917SReza.Sabdar@Sun.COM 	boolean_t rv;
33597917SReza.Sabdar@Sun.COM 	ndmp_lbr_params_t *nlp;
33607917SReza.Sabdar@Sun.COM 
33617917SReza.Sabdar@Sun.COM 	if (session == NULL)
33627917SReza.Sabdar@Sun.COM 		rv = 0;
33637917SReza.Sabdar@Sun.COM 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
33647917SReza.Sabdar@Sun.COM 		rv = 0;
33657917SReza.Sabdar@Sun.COM 	else
33667917SReza.Sabdar@Sun.COM 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
33677917SReza.Sabdar@Sun.COM 
33687917SReza.Sabdar@Sun.COM 	return (rv);
33697917SReza.Sabdar@Sun.COM }
33707917SReza.Sabdar@Sun.COM 
33717917SReza.Sabdar@Sun.COM 
33727917SReza.Sabdar@Sun.COM /*
33737917SReza.Sabdar@Sun.COM  * is_writer_running_v3
33747917SReza.Sabdar@Sun.COM  *
33757917SReza.Sabdar@Sun.COM  * Find out if the writer thread has started or not.
33767917SReza.Sabdar@Sun.COM  *
33777917SReza.Sabdar@Sun.COM  * Parameters:
33787917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
33797917SReza.Sabdar@Sun.COM  *
33807917SReza.Sabdar@Sun.COM  * Returns:
33817917SReza.Sabdar@Sun.COM  *   0: not started
33827917SReza.Sabdar@Sun.COM  *   non-zero: started
33837917SReza.Sabdar@Sun.COM  */
33847917SReza.Sabdar@Sun.COM static boolean_t
33857917SReza.Sabdar@Sun.COM is_writer_running_v3(ndmpd_session_t *session)
33867917SReza.Sabdar@Sun.COM {
33877917SReza.Sabdar@Sun.COM 	boolean_t rv;
33887917SReza.Sabdar@Sun.COM 	ndmp_lbr_params_t *nlp;
33897917SReza.Sabdar@Sun.COM 
33907917SReza.Sabdar@Sun.COM 	if (session == NULL)
33917917SReza.Sabdar@Sun.COM 		rv = 0;
33927917SReza.Sabdar@Sun.COM 	else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
33937917SReza.Sabdar@Sun.COM 		rv = 1;
33947917SReza.Sabdar@Sun.COM 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
33957917SReza.Sabdar@Sun.COM 		rv = 0;
33967917SReza.Sabdar@Sun.COM 	else
33977917SReza.Sabdar@Sun.COM 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
33987917SReza.Sabdar@Sun.COM 
33997917SReza.Sabdar@Sun.COM 	return (rv);
34007917SReza.Sabdar@Sun.COM }
34017917SReza.Sabdar@Sun.COM 
34027917SReza.Sabdar@Sun.COM 
34037917SReza.Sabdar@Sun.COM /*
34047917SReza.Sabdar@Sun.COM  * ndmpd_mover_wait_v3
34057917SReza.Sabdar@Sun.COM  *
34067917SReza.Sabdar@Sun.COM  * Take the mover state to PAUSED state
34077917SReza.Sabdar@Sun.COM  *
34087917SReza.Sabdar@Sun.COM  * Parameters:
34097917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
34107917SReza.Sabdar@Sun.COM  *
34117917SReza.Sabdar@Sun.COM  * Returns:
34127917SReza.Sabdar@Sun.COM  *   0: on success
34137917SReza.Sabdar@Sun.COM  *  -1: otherwise
34147917SReza.Sabdar@Sun.COM  */
34157917SReza.Sabdar@Sun.COM int
34167917SReza.Sabdar@Sun.COM ndmpd_mover_wait_v3(ndmpd_session_t *session)
34177917SReza.Sabdar@Sun.COM {
34187917SReza.Sabdar@Sun.COM 	int rv = 0;
34197917SReza.Sabdar@Sun.COM 
34207917SReza.Sabdar@Sun.COM 	nlp_ref_nw(session);
34217917SReza.Sabdar@Sun.COM 	for (; ; ) {
34227917SReza.Sabdar@Sun.COM 		nlp_wait_nw(session);
34237917SReza.Sabdar@Sun.COM 
34247917SReza.Sabdar@Sun.COM 		if (nlp_event_rv_get(session) < 0) {
34257917SReza.Sabdar@Sun.COM 			rv = -1;
34267917SReza.Sabdar@Sun.COM 			break;
34277917SReza.Sabdar@Sun.COM 		}
34287917SReza.Sabdar@Sun.COM 		if (session->ns_eof) {
34297917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "session->ns_eof");
34307917SReza.Sabdar@Sun.COM 			rv = -1;
34317917SReza.Sabdar@Sun.COM 			break;
34327917SReza.Sabdar@Sun.COM 		}
34337917SReza.Sabdar@Sun.COM 		if (session->ns_data.dd_abort) {
34347917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "data.abort");
34357917SReza.Sabdar@Sun.COM 			rv = -1;
34367917SReza.Sabdar@Sun.COM 			break;
34377917SReza.Sabdar@Sun.COM 		}
34387917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
34397917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
34407917SReza.Sabdar@Sun.COM 			    "mover.state: NDMP_MOVER_STATE_ACTIVE");
34417917SReza.Sabdar@Sun.COM 			session->ns_tape.td_record_count = 0;
34427917SReza.Sabdar@Sun.COM 			rv = 0;
34437917SReza.Sabdar@Sun.COM 			break;
34447917SReza.Sabdar@Sun.COM 		} else if (session->ns_mover.md_state ==
34457917SReza.Sabdar@Sun.COM 		    NDMP_MOVER_STATE_PAUSED) {
34467917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
34477917SReza.Sabdar@Sun.COM 			    "mover.state: NDMP_MOVER_STATE_PAUSED");
34487917SReza.Sabdar@Sun.COM 		} else {
34497917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "default");
34507917SReza.Sabdar@Sun.COM 			rv = -1;
34517917SReza.Sabdar@Sun.COM 			break;
34527917SReza.Sabdar@Sun.COM 		}
34537917SReza.Sabdar@Sun.COM 	}
34547917SReza.Sabdar@Sun.COM 
34557917SReza.Sabdar@Sun.COM 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
34567917SReza.Sabdar@Sun.COM 	nlp_unref_nw(session);
34577917SReza.Sabdar@Sun.COM 	return (rv);
34587917SReza.Sabdar@Sun.COM }
34597917SReza.Sabdar@Sun.COM 
34607917SReza.Sabdar@Sun.COM /*
34617917SReza.Sabdar@Sun.COM  * ndmpd_mover_error_send
34627917SReza.Sabdar@Sun.COM  *
34637917SReza.Sabdar@Sun.COM  * This function sends the notify message to the client.
34647917SReza.Sabdar@Sun.COM  *
34657917SReza.Sabdar@Sun.COM  * Parameters:
34667917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
34677917SReza.Sabdar@Sun.COM  *   reason  (input) - halt reason.
34687917SReza.Sabdar@Sun.COM  *
34697917SReza.Sabdar@Sun.COM  * Returns:
34707917SReza.Sabdar@Sun.COM  *   Error code
34717917SReza.Sabdar@Sun.COM  */
34727917SReza.Sabdar@Sun.COM int
34737917SReza.Sabdar@Sun.COM ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
34747917SReza.Sabdar@Sun.COM {
34757917SReza.Sabdar@Sun.COM 	ndmp_notify_mover_halted_request req;
34767917SReza.Sabdar@Sun.COM 
34777917SReza.Sabdar@Sun.COM 	req.reason = reason;
34787917SReza.Sabdar@Sun.COM 	req.text_reason = "";
34797917SReza.Sabdar@Sun.COM 
34807917SReza.Sabdar@Sun.COM 	return (ndmp_send_request(session->ns_connection,
34817917SReza.Sabdar@Sun.COM 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
34827917SReza.Sabdar@Sun.COM }
34837917SReza.Sabdar@Sun.COM 
34847917SReza.Sabdar@Sun.COM 
34857917SReza.Sabdar@Sun.COM /*
34867917SReza.Sabdar@Sun.COM  * ndmpd_mover_error_send_v4
34877917SReza.Sabdar@Sun.COM  *
34887917SReza.Sabdar@Sun.COM  * This function sends the notify message to the client.
34897917SReza.Sabdar@Sun.COM  *
34907917SReza.Sabdar@Sun.COM  * Parameters:
34917917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
34927917SReza.Sabdar@Sun.COM  *   reason  (input) - halt reason.
34937917SReza.Sabdar@Sun.COM  *
34947917SReza.Sabdar@Sun.COM  * Returns:
34957917SReza.Sabdar@Sun.COM  *   Error code
34967917SReza.Sabdar@Sun.COM  */
34977917SReza.Sabdar@Sun.COM int
34987917SReza.Sabdar@Sun.COM ndmpd_mover_error_send_v4(ndmpd_session_t *session,
34997917SReza.Sabdar@Sun.COM     ndmp_mover_halt_reason reason)
35007917SReza.Sabdar@Sun.COM {
35017917SReza.Sabdar@Sun.COM 	ndmp_notify_mover_halted_request_v4 req;
35027917SReza.Sabdar@Sun.COM 
35037917SReza.Sabdar@Sun.COM 	req.reason = reason;
35047917SReza.Sabdar@Sun.COM 
35057917SReza.Sabdar@Sun.COM 	return (ndmp_send_request(session->ns_connection,
35067917SReza.Sabdar@Sun.COM 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
35077917SReza.Sabdar@Sun.COM }
35087917SReza.Sabdar@Sun.COM 
35097917SReza.Sabdar@Sun.COM 
35107917SReza.Sabdar@Sun.COM /*
35117917SReza.Sabdar@Sun.COM  * ndmpd_mover_error
35127917SReza.Sabdar@Sun.COM  *
35137917SReza.Sabdar@Sun.COM  * This function is called when an unrecoverable mover error
35147917SReza.Sabdar@Sun.COM  * has been detected. A notify message is sent to the client and the
35157917SReza.Sabdar@Sun.COM  * mover is placed into the halted state.
35167917SReza.Sabdar@Sun.COM  *
35177917SReza.Sabdar@Sun.COM  * Parameters:
35187917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
35197917SReza.Sabdar@Sun.COM  *   reason  (input) - halt reason.
35207917SReza.Sabdar@Sun.COM  *
35217917SReza.Sabdar@Sun.COM  * Returns:
35227917SReza.Sabdar@Sun.COM  *   void.
35237917SReza.Sabdar@Sun.COM  */
35247917SReza.Sabdar@Sun.COM void
35257917SReza.Sabdar@Sun.COM ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
35267917SReza.Sabdar@Sun.COM {
35277917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
35287917SReza.Sabdar@Sun.COM 	    (session->ns_protocol_version > NDMPV2 &&
35297917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
35307917SReza.Sabdar@Sun.COM 		return;
35317917SReza.Sabdar@Sun.COM 
35327917SReza.Sabdar@Sun.COM 	if (session->ns_protocol_version == NDMPV4) {
35337917SReza.Sabdar@Sun.COM 		if (ndmpd_mover_error_send_v4(session, reason) < 0)
35347917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
35357917SReza.Sabdar@Sun.COM 			    "Error sending notify_mover_halted request");
35367917SReza.Sabdar@Sun.COM 	} else {
35377917SReza.Sabdar@Sun.COM 		/* No media error in V3 */
35387917SReza.Sabdar@Sun.COM 		if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
35397917SReza.Sabdar@Sun.COM 			reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
35407917SReza.Sabdar@Sun.COM 		if (ndmpd_mover_error_send(session, reason) < 0)
35417917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
35427917SReza.Sabdar@Sun.COM 			    "Error sending notify_mover_halted request");
35437917SReza.Sabdar@Sun.COM 	}
35447917SReza.Sabdar@Sun.COM 
35457917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_listen_sock != -1) {
35467917SReza.Sabdar@Sun.COM 		(void) ndmpd_remove_file_handler(session,
35477917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_listen_sock);
35487917SReza.Sabdar@Sun.COM 		(void) close(session->ns_mover.md_listen_sock);
35497917SReza.Sabdar@Sun.COM 		session->ns_mover.md_listen_sock = -1;
35507917SReza.Sabdar@Sun.COM 	}
35517917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_sock != -1) {
35527917SReza.Sabdar@Sun.COM 		(void) ndmpd_remove_file_handler(session,
35537917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_sock);
35547917SReza.Sabdar@Sun.COM 		(void) close(session->ns_mover.md_sock);
35557917SReza.Sabdar@Sun.COM 		session->ns_mover.md_sock = -1;
35567917SReza.Sabdar@Sun.COM 	}
35577917SReza.Sabdar@Sun.COM 
35587917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
35597917SReza.Sabdar@Sun.COM 	session->ns_mover.md_halt_reason = reason;
35607917SReza.Sabdar@Sun.COM }
35617917SReza.Sabdar@Sun.COM 
35627917SReza.Sabdar@Sun.COM 
35637917SReza.Sabdar@Sun.COM /*
35647917SReza.Sabdar@Sun.COM  * mover_pause_v3
35657917SReza.Sabdar@Sun.COM  *
35667917SReza.Sabdar@Sun.COM  * Send an ndmp_notify_mover_paused request to the
35677917SReza.Sabdar@Sun.COM  * NDMP client to inform the client that its attention is required.
35687917SReza.Sabdar@Sun.COM  * Process messages until the data/mover operation is either aborted
35697917SReza.Sabdar@Sun.COM  * or continued.
35707917SReza.Sabdar@Sun.COM  *
35717917SReza.Sabdar@Sun.COM  * Parameters:
35727917SReza.Sabdar@Sun.COM  *   client_data (input) - session pointer.
35737917SReza.Sabdar@Sun.COM  *   reason (input) - pause reason.
35747917SReza.Sabdar@Sun.COM  *
35757917SReza.Sabdar@Sun.COM  * Returns:
35767917SReza.Sabdar@Sun.COM  *   0 - operation has been continued.
35777917SReza.Sabdar@Sun.COM  *  -1 - operation has been aborted.
35787917SReza.Sabdar@Sun.COM  */
35797917SReza.Sabdar@Sun.COM static int
35807917SReza.Sabdar@Sun.COM mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
35817917SReza.Sabdar@Sun.COM {
35827917SReza.Sabdar@Sun.COM 	int rv;
35837917SReza.Sabdar@Sun.COM 	ndmp_notify_mover_paused_request request;
35847917SReza.Sabdar@Sun.COM 
35857917SReza.Sabdar@Sun.COM 	rv = 0;
35867917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
35877917SReza.Sabdar@Sun.COM 	session->ns_mover.md_pause_reason = reason;
35887917SReza.Sabdar@Sun.COM 	session->ns_mover.md_pre_cond = FALSE;
35897917SReza.Sabdar@Sun.COM 
35907917SReza.Sabdar@Sun.COM 	request.reason = session->ns_mover.md_pause_reason;
35917917SReza.Sabdar@Sun.COM 	request.seek_position =
35927917SReza.Sabdar@Sun.COM 	    long_long_to_quad(session->ns_mover.md_position);
35937917SReza.Sabdar@Sun.COM 
35947917SReza.Sabdar@Sun.COM 	if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
35957917SReza.Sabdar@Sun.COM 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
35967917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
35977917SReza.Sabdar@Sun.COM 		    "Error sending notify_mover_paused_request");
35987917SReza.Sabdar@Sun.COM 		return (-1);
35997917SReza.Sabdar@Sun.COM 	}
36007917SReza.Sabdar@Sun.COM 
36017917SReza.Sabdar@Sun.COM 	/*
36027917SReza.Sabdar@Sun.COM 	 * 3-way operations are single-thread.  The same thread
36037917SReza.Sabdar@Sun.COM 	 * should process the messages.
36047917SReza.Sabdar@Sun.COM 	 *
36057917SReza.Sabdar@Sun.COM 	 * 2-way operations are multi-thread.  The main thread
36067917SReza.Sabdar@Sun.COM 	 * processes the messages.  We just need to wait and
36077917SReza.Sabdar@Sun.COM 	 * see if the mover state changes or the operation aborts.
36087917SReza.Sabdar@Sun.COM 	 */
36097917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
36107917SReza.Sabdar@Sun.COM 		/*
36117917SReza.Sabdar@Sun.COM 		 * Process messages until the state is changed by
36127917SReza.Sabdar@Sun.COM 		 * an abort, continue, or close request .
36137917SReza.Sabdar@Sun.COM 		 */
36147917SReza.Sabdar@Sun.COM 		for (; ; ) {
36157917SReza.Sabdar@Sun.COM 			if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
36167917SReza.Sabdar@Sun.COM 				return (-1);
36177917SReza.Sabdar@Sun.COM 
36187917SReza.Sabdar@Sun.COM 			if (session->ns_eof == TRUE)
36197917SReza.Sabdar@Sun.COM 				return (-1);
36207917SReza.Sabdar@Sun.COM 
36217917SReza.Sabdar@Sun.COM 			switch (session->ns_mover.md_state) {
36227917SReza.Sabdar@Sun.COM 			case NDMP_MOVER_STATE_ACTIVE:
36237917SReza.Sabdar@Sun.COM 				session->ns_tape.td_record_count = 0;
36247917SReza.Sabdar@Sun.COM 				return (0);
36257917SReza.Sabdar@Sun.COM 
36267917SReza.Sabdar@Sun.COM 			case NDMP_MOVER_STATE_PAUSED:
36277917SReza.Sabdar@Sun.COM 				continue;
36287917SReza.Sabdar@Sun.COM 
36297917SReza.Sabdar@Sun.COM 			default:
36307917SReza.Sabdar@Sun.COM 				return (-1);
36317917SReza.Sabdar@Sun.COM 			}
36327917SReza.Sabdar@Sun.COM 		}
36337917SReza.Sabdar@Sun.COM 
36347917SReza.Sabdar@Sun.COM 	} else {
36357917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_data_addr.addr_type ==
36367917SReza.Sabdar@Sun.COM 		    NDMP_ADDR_LOCAL) {
36377917SReza.Sabdar@Sun.COM 			rv = ndmpd_mover_wait_v3(session);
36387917SReza.Sabdar@Sun.COM 		} else {
36397917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
36407917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_data_addr.addr_type);
36417917SReza.Sabdar@Sun.COM 			rv = -1;
36427917SReza.Sabdar@Sun.COM 		}
36437917SReza.Sabdar@Sun.COM 	}
36447917SReza.Sabdar@Sun.COM 
36457917SReza.Sabdar@Sun.COM 	return (rv);
36467917SReza.Sabdar@Sun.COM }
36477917SReza.Sabdar@Sun.COM 
36487917SReza.Sabdar@Sun.COM 
36497917SReza.Sabdar@Sun.COM /*
36507917SReza.Sabdar@Sun.COM  * mover_tape_write_v3
36517917SReza.Sabdar@Sun.COM  *
36527917SReza.Sabdar@Sun.COM  * Writes a data record to tape. Detects and handles EOT conditions.
36537917SReza.Sabdar@Sun.COM  *
36547917SReza.Sabdar@Sun.COM  * Parameters:
36557917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
36567917SReza.Sabdar@Sun.COM  *   data    (input) - data to be written.
36577917SReza.Sabdar@Sun.COM  *   length  (input) - length of data to be written.
36587917SReza.Sabdar@Sun.COM  *
36597917SReza.Sabdar@Sun.COM  * Returns:
36607917SReza.Sabdar@Sun.COM  *    0 - operation aborted by client.
36617917SReza.Sabdar@Sun.COM  *   -1 - error.
36627917SReza.Sabdar@Sun.COM  *   otherwise - number of bytes written.
36637917SReza.Sabdar@Sun.COM  */
36647917SReza.Sabdar@Sun.COM static int
36657917SReza.Sabdar@Sun.COM mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
36667917SReza.Sabdar@Sun.COM {
36677917SReza.Sabdar@Sun.COM 	ssize_t n;
36687917SReza.Sabdar@Sun.COM 	int err;
36697917SReza.Sabdar@Sun.COM 
36707917SReza.Sabdar@Sun.COM 	for (; ; ) {
36717917SReza.Sabdar@Sun.COM 		/*
36727917SReza.Sabdar@Sun.COM 		 * Refer to the comment at the top of ndmpd_tape.c file for
36737917SReza.Sabdar@Sun.COM 		 * Mammoth2 tape drives.
36747917SReza.Sabdar@Sun.COM 		 */
36757917SReza.Sabdar@Sun.COM 		if (session->ns_tape.td_eom_seen) {
36767917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "eom_seen");
36777917SReza.Sabdar@Sun.COM 
36787917SReza.Sabdar@Sun.COM 			session->ns_tape.td_eom_seen = FALSE;
36797917SReza.Sabdar@Sun.COM 			/*
36807917SReza.Sabdar@Sun.COM 			 * End of media reached.
36817917SReza.Sabdar@Sun.COM 			 * Notify client and wait for the client to
36827917SReza.Sabdar@Sun.COM 			 * either abort the operation or continue the
36837917SReza.Sabdar@Sun.COM 			 * operation after changing the tape.
36847917SReza.Sabdar@Sun.COM 			 */
36857917SReza.Sabdar@Sun.COM 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
36867917SReza.Sabdar@Sun.COM 			    ++ndmp_log_msg_id,
36877917SReza.Sabdar@Sun.COM 			    "End of tape reached. Load next tape");
36887917SReza.Sabdar@Sun.COM 
36897917SReza.Sabdar@Sun.COM 			err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM);
36907917SReza.Sabdar@Sun.COM 
36917917SReza.Sabdar@Sun.COM 			/* Operation aborted or connection terminated? */
36927917SReza.Sabdar@Sun.COM 			if (err < 0)
36937917SReza.Sabdar@Sun.COM 				return (-1);
36947917SReza.Sabdar@Sun.COM 
36957917SReza.Sabdar@Sun.COM 			/* Retry the write to the new tape. */
36967917SReza.Sabdar@Sun.COM 			continue;
36977917SReza.Sabdar@Sun.COM 		}
36987917SReza.Sabdar@Sun.COM 
36997917SReza.Sabdar@Sun.COM 		/*
37007917SReza.Sabdar@Sun.COM 		 * Enforce mover window on write.
37017917SReza.Sabdar@Sun.COM 		 */
37027917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_position >=
37037917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_offset +
37047917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_length) {
37057917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
37067917SReza.Sabdar@Sun.COM 
37077917SReza.Sabdar@Sun.COM 			err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW);
37087917SReza.Sabdar@Sun.COM 			/* Operation aborted or connection terminated? */
37097917SReza.Sabdar@Sun.COM 			if (err < 0)
37107917SReza.Sabdar@Sun.COM 				return (-1);
37117917SReza.Sabdar@Sun.COM 
37127917SReza.Sabdar@Sun.COM 		}
37137917SReza.Sabdar@Sun.COM 
37147917SReza.Sabdar@Sun.COM 		n = write(session->ns_tape.td_fd, data, length);
37157917SReza.Sabdar@Sun.COM 		if (n < 0) {
37167917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
37177917SReza.Sabdar@Sun.COM 			return (-1);
37187917SReza.Sabdar@Sun.COM 		}
37197917SReza.Sabdar@Sun.COM 		NS_ADD(wtape, n);
37207917SReza.Sabdar@Sun.COM 
37217917SReza.Sabdar@Sun.COM 		if (n == 0 || n != length) {
37227917SReza.Sabdar@Sun.COM 			if (n != 0) {
37237917SReza.Sabdar@Sun.COM 				/*
37247917SReza.Sabdar@Sun.COM 				 * Backup one record since the record
37257917SReza.Sabdar@Sun.COM 				 * hits the EOM.
37267917SReza.Sabdar@Sun.COM 				 */
37277917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG, "Back up one record");
37287917SReza.Sabdar@Sun.COM 				(void) ndmp_mtioctl(session->ns_tape.td_fd,
37297917SReza.Sabdar@Sun.COM 				    MTBSR, 1);
37307917SReza.Sabdar@Sun.COM 
37317917SReza.Sabdar@Sun.COM 				/* setting logical EOM */
37327917SReza.Sabdar@Sun.COM 				ndmpd_write_eom(session->ns_tape.td_fd);
37337917SReza.Sabdar@Sun.COM 			}
37347917SReza.Sabdar@Sun.COM 
37357917SReza.Sabdar@Sun.COM 			/*
37367917SReza.Sabdar@Sun.COM 			 * End of media reached.
37377917SReza.Sabdar@Sun.COM 			 * Notify client and wait for the client to
37387917SReza.Sabdar@Sun.COM 			 * either abort the operation or continue the
37397917SReza.Sabdar@Sun.COM 			 * operation after changing the tape.
37407917SReza.Sabdar@Sun.COM 			 */
37417917SReza.Sabdar@Sun.COM 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
37427917SReza.Sabdar@Sun.COM 			    ++ndmp_log_msg_id,
37437917SReza.Sabdar@Sun.COM 			    "End of tape reached. Load next tape");
37447917SReza.Sabdar@Sun.COM 
37457917SReza.Sabdar@Sun.COM 			err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM);
37467917SReza.Sabdar@Sun.COM 
37477917SReza.Sabdar@Sun.COM 			/* Operation aborted or connection terminated? */
37487917SReza.Sabdar@Sun.COM 			if (err < 0)
37497917SReza.Sabdar@Sun.COM 				return (-1);
37507917SReza.Sabdar@Sun.COM 
37517917SReza.Sabdar@Sun.COM 			/* Retry the write to the new tape. */
37527917SReza.Sabdar@Sun.COM 			continue;
37537917SReza.Sabdar@Sun.COM 		}
37547917SReza.Sabdar@Sun.COM 
37557917SReza.Sabdar@Sun.COM 		session->ns_tape.td_record_count++;
37567917SReza.Sabdar@Sun.COM 		return (n);
37577917SReza.Sabdar@Sun.COM 	}
37587917SReza.Sabdar@Sun.COM }
37597917SReza.Sabdar@Sun.COM 
37607917SReza.Sabdar@Sun.COM 
37617917SReza.Sabdar@Sun.COM /*
37627917SReza.Sabdar@Sun.COM  * mover_tape_flush_v3
37637917SReza.Sabdar@Sun.COM  *
37647917SReza.Sabdar@Sun.COM  * Writes all remaining buffered data to tape. A partial record is
37657917SReza.Sabdar@Sun.COM  * padded out to a full record with zeros.
37667917SReza.Sabdar@Sun.COM  *
37677917SReza.Sabdar@Sun.COM  * Parameters:
37687917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
37697917SReza.Sabdar@Sun.COM  *   data    (input) - data to be written.
37707917SReza.Sabdar@Sun.COM  *   length  (input) - length of data to be written.
37717917SReza.Sabdar@Sun.COM  *
37727917SReza.Sabdar@Sun.COM  * Returns:
37737917SReza.Sabdar@Sun.COM  *   -1 - error.
37747917SReza.Sabdar@Sun.COM  *   otherwise - number of bytes written.
37757917SReza.Sabdar@Sun.COM  */
37767917SReza.Sabdar@Sun.COM static int
37777917SReza.Sabdar@Sun.COM mover_tape_flush_v3(ndmpd_session_t *session)
37787917SReza.Sabdar@Sun.COM {
37797917SReza.Sabdar@Sun.COM 	int n;
37807917SReza.Sabdar@Sun.COM 
37817917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_w_index == 0)
37827917SReza.Sabdar@Sun.COM 		return (0);
37837917SReza.Sabdar@Sun.COM 
37847917SReza.Sabdar@Sun.COM 	(void) memset((void*)&session->ns_mover.md_buf[session->
37857917SReza.Sabdar@Sun.COM 	    ns_mover.md_w_index], 0,
37867917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
37877917SReza.Sabdar@Sun.COM 
37887917SReza.Sabdar@Sun.COM 	n = mover_tape_write_v3(session, session->ns_mover.md_buf,
37897917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_record_size);
37907917SReza.Sabdar@Sun.COM 	if (n < 0) {
37917917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
37927917SReza.Sabdar@Sun.COM 		return (-1);
37937917SReza.Sabdar@Sun.COM 	}
37947917SReza.Sabdar@Sun.COM 
37957917SReza.Sabdar@Sun.COM 	session->ns_mover.md_w_index = 0;
37967917SReza.Sabdar@Sun.COM 	session->ns_mover.md_position += n;
37977917SReza.Sabdar@Sun.COM 	return (n);
37987917SReza.Sabdar@Sun.COM }
37997917SReza.Sabdar@Sun.COM 
38007917SReza.Sabdar@Sun.COM 
38017917SReza.Sabdar@Sun.COM /*
38027917SReza.Sabdar@Sun.COM  * ndmpd_local_write_v3
38037917SReza.Sabdar@Sun.COM  *
38047917SReza.Sabdar@Sun.COM  * Buffers and writes data to the tape device.
38057917SReza.Sabdar@Sun.COM  * A full tape record is buffered before being written.
38067917SReza.Sabdar@Sun.COM  *
38077917SReza.Sabdar@Sun.COM  * Parameters:
38087917SReza.Sabdar@Sun.COM  *   session    (input) - session pointer.
38097917SReza.Sabdar@Sun.COM  *   data       (input) - data to be written.
38107917SReza.Sabdar@Sun.COM  *   length     (input) - data length.
38117917SReza.Sabdar@Sun.COM  *
38127917SReza.Sabdar@Sun.COM  * Returns:
38137917SReza.Sabdar@Sun.COM  *   0 - data successfully written.
38147917SReza.Sabdar@Sun.COM  *  -1 - error.
38157917SReza.Sabdar@Sun.COM  */
38167917SReza.Sabdar@Sun.COM int
38177917SReza.Sabdar@Sun.COM ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
38187917SReza.Sabdar@Sun.COM {
38197917SReza.Sabdar@Sun.COM 	ulong_t count = 0;
38207917SReza.Sabdar@Sun.COM 	ssize_t n;
38217917SReza.Sabdar@Sun.COM 	ulong_t len;
38227917SReza.Sabdar@Sun.COM 
38237917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
38247917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
38257917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
38267917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
38277917SReza.Sabdar@Sun.COM 		return (-1);
38287917SReza.Sabdar@Sun.COM 	}
38297917SReza.Sabdar@Sun.COM 
38307917SReza.Sabdar@Sun.COM 	/*
38317917SReza.Sabdar@Sun.COM 	 * A length of 0 indicates that any buffered data should be
38327917SReza.Sabdar@Sun.COM 	 * flushed to tape.
38337917SReza.Sabdar@Sun.COM 	 */
38347917SReza.Sabdar@Sun.COM 	if (length == 0) {
38357917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_w_index == 0)
38367917SReza.Sabdar@Sun.COM 			return (0);
38377917SReza.Sabdar@Sun.COM 
38387917SReza.Sabdar@Sun.COM 		(void) memset((void*)&session->ns_mover.md_buf[session->
38397917SReza.Sabdar@Sun.COM 		    ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
38407917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_w_index);
38417917SReza.Sabdar@Sun.COM 
38427917SReza.Sabdar@Sun.COM 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
38437917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_record_size);
38447917SReza.Sabdar@Sun.COM 		if (n <= 0) {
38457917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
38467917SReza.Sabdar@Sun.COM 			    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
38477917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_MEDIA_ERROR));
38487917SReza.Sabdar@Sun.COM 			return (-1);
38497917SReza.Sabdar@Sun.COM 		}
38507917SReza.Sabdar@Sun.COM 
38517917SReza.Sabdar@Sun.COM 		session->ns_mover.md_position += n;
38527917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_written += n;
38537917SReza.Sabdar@Sun.COM 		session->ns_mover.md_record_num++;
38547917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = 0;
38557917SReza.Sabdar@Sun.COM 		return (0);
38567917SReza.Sabdar@Sun.COM 	}
38577917SReza.Sabdar@Sun.COM 
38587917SReza.Sabdar@Sun.COM 	/* Break the data into records. */
38597917SReza.Sabdar@Sun.COM 	while (count < length) {
38607917SReza.Sabdar@Sun.COM 		/*
38617917SReza.Sabdar@Sun.COM 		 * Determine if data needs to be buffered or
38627917SReza.Sabdar@Sun.COM 		 * can be written directly from user supplied location.
38637917SReza.Sabdar@Sun.COM 		 * We can fast path the write if there is no pending
38647917SReza.Sabdar@Sun.COM 		 * buffered data and there is at least a full records worth
38657917SReza.Sabdar@Sun.COM 		 * of data to be written.
38667917SReza.Sabdar@Sun.COM 		 */
38677917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_w_index == 0 &&
38687917SReza.Sabdar@Sun.COM 		    length - count >= session->ns_mover.md_record_size) {
38697917SReza.Sabdar@Sun.COM 			n = mover_tape_write_v3(session, &data[count],
38707917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_record_size);
38717917SReza.Sabdar@Sun.COM 			if (n <= 0) {
38727917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
38737917SReza.Sabdar@Sun.COM 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
38747917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_MEDIA_ERROR));
38757917SReza.Sabdar@Sun.COM 				return (-1);
38767917SReza.Sabdar@Sun.COM 			}
38777917SReza.Sabdar@Sun.COM 
38787917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position += n;
38797917SReza.Sabdar@Sun.COM 			session->ns_mover.md_data_written += n;
38807917SReza.Sabdar@Sun.COM 			session->ns_mover.md_record_num++;
38817917SReza.Sabdar@Sun.COM 			count += n;
38827917SReza.Sabdar@Sun.COM 			continue;
38837917SReza.Sabdar@Sun.COM 		}
38847917SReza.Sabdar@Sun.COM 
38857917SReza.Sabdar@Sun.COM 		/* Buffer the data */
38867917SReza.Sabdar@Sun.COM 		len = length - count;
38877917SReza.Sabdar@Sun.COM 		if (len > session->ns_mover.md_record_size -
38887917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_w_index)
38897917SReza.Sabdar@Sun.COM 			len = session->ns_mover.md_record_size -
38907917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_w_index;
38917917SReza.Sabdar@Sun.COM 
38927917SReza.Sabdar@Sun.COM 		(void) memcpy(&session->ns_mover.md_buf[session->
38937917SReza.Sabdar@Sun.COM 		    ns_mover.md_w_index], &data[count], len);
38947917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index += len;
38957917SReza.Sabdar@Sun.COM 		count += len;
38967917SReza.Sabdar@Sun.COM 
38977917SReza.Sabdar@Sun.COM 		/* Write the buffer if its full */
38987917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_w_index ==
38997917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_record_size) {
39007917SReza.Sabdar@Sun.COM 			n = mover_tape_write_v3(session,
39017917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_buf,
39027917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_record_size);
39037917SReza.Sabdar@Sun.COM 			if (n < 0) {
39047917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
39057917SReza.Sabdar@Sun.COM 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
39067917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_MEDIA_ERROR));
39077917SReza.Sabdar@Sun.COM 				return (-1);
39087917SReza.Sabdar@Sun.COM 			}
39097917SReza.Sabdar@Sun.COM 
39107917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position += n;
39117917SReza.Sabdar@Sun.COM 			session->ns_mover.md_data_written += n;
39127917SReza.Sabdar@Sun.COM 			session->ns_mover.md_record_num++;
39137917SReza.Sabdar@Sun.COM 			session->ns_mover.md_w_index = 0;
39147917SReza.Sabdar@Sun.COM 		}
39157917SReza.Sabdar@Sun.COM 	}
39167917SReza.Sabdar@Sun.COM 
39177917SReza.Sabdar@Sun.COM 	return (0);
39187917SReza.Sabdar@Sun.COM }
39197917SReza.Sabdar@Sun.COM 
39207917SReza.Sabdar@Sun.COM 
39217917SReza.Sabdar@Sun.COM /*
39227917SReza.Sabdar@Sun.COM  * mover_data_read_v3
39237917SReza.Sabdar@Sun.COM  *
39247917SReza.Sabdar@Sun.COM  * Reads backup data from the data connection and writes the
39257917SReza.Sabdar@Sun.COM  * received data to the tape device.
39267917SReza.Sabdar@Sun.COM  *
39277917SReza.Sabdar@Sun.COM  * Parameters:
39287917SReza.Sabdar@Sun.COM  *   cookie  (input) - session pointer.
39297917SReza.Sabdar@Sun.COM  *   fd      (input) - file descriptor.
39307917SReza.Sabdar@Sun.COM  *   mode    (input) - select mode.
39317917SReza.Sabdar@Sun.COM  *
39327917SReza.Sabdar@Sun.COM  * Returns:
39337917SReza.Sabdar@Sun.COM  *   void.
39347917SReza.Sabdar@Sun.COM  */
39357917SReza.Sabdar@Sun.COM /*ARGSUSED*/
39367917SReza.Sabdar@Sun.COM static void
39377917SReza.Sabdar@Sun.COM mover_data_read_v3(void *cookie, int fd, ulong_t mode)
39387917SReza.Sabdar@Sun.COM {
39397917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
39407917SReza.Sabdar@Sun.COM 	int n;
39417917SReza.Sabdar@Sun.COM 	ulong_t index;
39427917SReza.Sabdar@Sun.COM 
39437917SReza.Sabdar@Sun.COM 	n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
39447917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
39457917SReza.Sabdar@Sun.COM 
39467917SReza.Sabdar@Sun.COM 	/*
39477917SReza.Sabdar@Sun.COM 	 * Since this function is only called when select believes data
39487917SReza.Sabdar@Sun.COM 	 * is available to be read, a return of zero indicates the
39497917SReza.Sabdar@Sun.COM 	 * connection has been closed.
39507917SReza.Sabdar@Sun.COM 	 */
39517917SReza.Sabdar@Sun.COM 	if (n <= 0) {
39527917SReza.Sabdar@Sun.COM 		if (n < 0 && errno == EWOULDBLOCK) {
39537917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
39547917SReza.Sabdar@Sun.COM 			return;
39557917SReza.Sabdar@Sun.COM 		}
39567917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
39577917SReza.Sabdar@Sun.COM 
39587917SReza.Sabdar@Sun.COM 		/* Save the index since mover_tape_flush_v3 resets it. */
39597917SReza.Sabdar@Sun.COM 		index = session->ns_mover.md_w_index;
39607917SReza.Sabdar@Sun.COM 
39617917SReza.Sabdar@Sun.COM 		/* Flush any buffered data to tape. */
39627917SReza.Sabdar@Sun.COM 		if (mover_tape_flush_v3(session) > 0) {
39637917SReza.Sabdar@Sun.COM 			session->ns_mover.md_data_written += index;
39647917SReza.Sabdar@Sun.COM 			session->ns_mover.md_record_num++;
39657917SReza.Sabdar@Sun.COM 		}
39667917SReza.Sabdar@Sun.COM 
39677917SReza.Sabdar@Sun.COM 		if (n == 0)
39687917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
39697917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
39707917SReza.Sabdar@Sun.COM 		else
39717917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
39727917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
39737917SReza.Sabdar@Sun.COM 
39747917SReza.Sabdar@Sun.COM 		return;
39757917SReza.Sabdar@Sun.COM 	}
39767917SReza.Sabdar@Sun.COM 
39777917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "n %d", n);
39787917SReza.Sabdar@Sun.COM 
39797917SReza.Sabdar@Sun.COM 	session->ns_mover.md_w_index += n;
39807917SReza.Sabdar@Sun.COM 
39817917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
39827917SReza.Sabdar@Sun.COM 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
39837917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_record_size);
39847917SReza.Sabdar@Sun.COM 		if (n <= 0) {
39857917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
39867917SReza.Sabdar@Sun.COM 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
39877917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_MEDIA_ERROR));
39887917SReza.Sabdar@Sun.COM 			return;
39897917SReza.Sabdar@Sun.COM 		}
39907917SReza.Sabdar@Sun.COM 
39917917SReza.Sabdar@Sun.COM 		session->ns_mover.md_position += n;
39927917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = 0;
39937917SReza.Sabdar@Sun.COM 		session->ns_mover.md_data_written += n;
39947917SReza.Sabdar@Sun.COM 		session->ns_mover.md_record_num++;
39957917SReza.Sabdar@Sun.COM 	}
39967917SReza.Sabdar@Sun.COM }
39977917SReza.Sabdar@Sun.COM 
39987917SReza.Sabdar@Sun.COM /*
39997917SReza.Sabdar@Sun.COM  * mover_tape_read_v3
40007917SReza.Sabdar@Sun.COM  *
40017917SReza.Sabdar@Sun.COM  * Reads a data record from tape. Detects and handles EOT conditions.
40027917SReza.Sabdar@Sun.COM  *
40037917SReza.Sabdar@Sun.COM  * Parameters:
40047917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
40057917SReza.Sabdar@Sun.COM  *   data    (input) - location to read data to.
40067917SReza.Sabdar@Sun.COM  *
40077917SReza.Sabdar@Sun.COM  * Returns:
40087917SReza.Sabdar@Sun.COM  *   0 - operation aborted.
40097917SReza.Sabdar@Sun.COM  *   TAPE_READ_ERR - tape read IO error.
40107917SReza.Sabdar@Sun.COM  *   TAPE_NO_WRITER_ERR - no writer is running during tape read
40117917SReza.Sabdar@Sun.COM  *   otherwise - number of bytes read.
40127917SReza.Sabdar@Sun.COM  */
40137917SReza.Sabdar@Sun.COM static int
40147917SReza.Sabdar@Sun.COM mover_tape_read_v3(ndmpd_session_t *session, char *data)
40157917SReza.Sabdar@Sun.COM {
40167917SReza.Sabdar@Sun.COM 	ssize_t	 n;
40177917SReza.Sabdar@Sun.COM 	int err;
40187917SReza.Sabdar@Sun.COM 	int count;
40197917SReza.Sabdar@Sun.COM 
40207917SReza.Sabdar@Sun.COM 	count = session->ns_mover.md_record_size;
40217917SReza.Sabdar@Sun.COM 	for (; ; ) {
40227917SReza.Sabdar@Sun.COM 		n = read(session->ns_tape.td_fd, data, count);
40237917SReza.Sabdar@Sun.COM 		if (n < 0) {
40247917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
40257917SReza.Sabdar@Sun.COM 			return (TAPE_READ_ERR);
40267917SReza.Sabdar@Sun.COM 		}
40277917SReza.Sabdar@Sun.COM 		NS_ADD(rtape, n);
40287917SReza.Sabdar@Sun.COM 
40297917SReza.Sabdar@Sun.COM 		if (n == 0) {
40307917SReza.Sabdar@Sun.COM 			if (!is_writer_running_v3(session))
40317917SReza.Sabdar@Sun.COM 				return (TAPE_NO_WRITER_ERR);
40327917SReza.Sabdar@Sun.COM 
40337917SReza.Sabdar@Sun.COM 			/*
40347917SReza.Sabdar@Sun.COM 			 * End of media reached.
40357917SReza.Sabdar@Sun.COM 			 * Notify client and wait for the client to
40367917SReza.Sabdar@Sun.COM 			 * either abort the data operation or continue the
40377917SReza.Sabdar@Sun.COM 			 * operation after changing the tape.
40387917SReza.Sabdar@Sun.COM 			 */
40397917SReza.Sabdar@Sun.COM 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
40407917SReza.Sabdar@Sun.COM 			    ++ndmp_log_msg_id,
40417917SReza.Sabdar@Sun.COM 			    "End of tape reached. Load next tape");
40427917SReza.Sabdar@Sun.COM 
40437917SReza.Sabdar@Sun.COM 			err = mover_pause_v3(session, NDMP_MOVER_PAUSE_EOF);
40447917SReza.Sabdar@Sun.COM 
40457917SReza.Sabdar@Sun.COM 			/* Operation aborted or connection terminated? */
40467917SReza.Sabdar@Sun.COM 			if (err < 0) {
40477917SReza.Sabdar@Sun.COM 				/*
40487917SReza.Sabdar@Sun.COM 				 * Back up one record if it's read but not
40497917SReza.Sabdar@Sun.COM 				 * used.
40507917SReza.Sabdar@Sun.COM 				 */
40517917SReza.Sabdar@Sun.COM 				if (count != session->ns_mover.md_record_size)
40527917SReza.Sabdar@Sun.COM 					(void) ndmp_mtioctl(
40537917SReza.Sabdar@Sun.COM 					    session->ns_tape.td_fd, MTBSR, 1);
40547917SReza.Sabdar@Sun.COM 				return (0);
40557917SReza.Sabdar@Sun.COM 			}
40567917SReza.Sabdar@Sun.COM 
40577917SReza.Sabdar@Sun.COM 			/* Retry the read from the new tape. */
40587917SReza.Sabdar@Sun.COM 			continue;
40597917SReza.Sabdar@Sun.COM 		}
40607917SReza.Sabdar@Sun.COM 
40617917SReza.Sabdar@Sun.COM 		data += n;
40627917SReza.Sabdar@Sun.COM 		count -= n;
40637917SReza.Sabdar@Sun.COM 		if (count <= 0) {
40647917SReza.Sabdar@Sun.COM 			session->ns_mover.md_record_num++;
40657917SReza.Sabdar@Sun.COM 			session->ns_tape.td_record_count++;
40667917SReza.Sabdar@Sun.COM 			return (n);
40677917SReza.Sabdar@Sun.COM 		}
40687917SReza.Sabdar@Sun.COM 	}
40697917SReza.Sabdar@Sun.COM }
40707917SReza.Sabdar@Sun.COM 
40717917SReza.Sabdar@Sun.COM 
40727917SReza.Sabdar@Sun.COM /*
40737917SReza.Sabdar@Sun.COM  * mover_data_write_v3
40747917SReza.Sabdar@Sun.COM  *
40757917SReza.Sabdar@Sun.COM  * Reads backup data from the tape device and writes the
40767917SReza.Sabdar@Sun.COM  * data to the data connection.
40777917SReza.Sabdar@Sun.COM  * This function is called by ndmpd_select when the data connection
40787917SReza.Sabdar@Sun.COM  * is ready for more data to be written.
40797917SReza.Sabdar@Sun.COM  *
40807917SReza.Sabdar@Sun.COM  * Parameters:
40817917SReza.Sabdar@Sun.COM  *   cookie  (input) - session pointer.
40827917SReza.Sabdar@Sun.COM  *   fd      (input) - file descriptor.
40837917SReza.Sabdar@Sun.COM  *   mode    (input) - select mode.
40847917SReza.Sabdar@Sun.COM  *
40857917SReza.Sabdar@Sun.COM  * Returns:
40867917SReza.Sabdar@Sun.COM  *   void.
40877917SReza.Sabdar@Sun.COM  */
40887917SReza.Sabdar@Sun.COM /*ARGSUSED*/
40897917SReza.Sabdar@Sun.COM static void
40907917SReza.Sabdar@Sun.COM mover_data_write_v3(void *cookie, int fd, ulong_t mode)
40917917SReza.Sabdar@Sun.COM {
40927917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
40937917SReza.Sabdar@Sun.COM 	int n;
40947917SReza.Sabdar@Sun.COM 	ulong_t len;
40957917SReza.Sabdar@Sun.COM 	u_longlong_t wlen;
40967917SReza.Sabdar@Sun.COM 	ndmp_notify_mover_paused_request pause_request;
40977917SReza.Sabdar@Sun.COM 
40987917SReza.Sabdar@Sun.COM 	/*
40997917SReza.Sabdar@Sun.COM 	 * If the end of the mover window has been reached,
41007917SReza.Sabdar@Sun.COM 	 * then notify the client that a seek is needed.
41017917SReza.Sabdar@Sun.COM 	 * Remove the file handler to prevent this function from
41027917SReza.Sabdar@Sun.COM 	 * being called. The handler will be reinstalled in
41037917SReza.Sabdar@Sun.COM 	 * ndmpd_mover_continue.
41047917SReza.Sabdar@Sun.COM 	 */
41057917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
41067917SReza.Sabdar@Sun.COM 	    + session->ns_mover.md_window_length) {
41077917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
41087917SReza.Sabdar@Sun.COM 		    "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
41097917SReza.Sabdar@Sun.COM 
41107917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = 0;
41117917SReza.Sabdar@Sun.COM 		session->ns_mover.md_r_index = 0;
41127917SReza.Sabdar@Sun.COM 
41137917SReza.Sabdar@Sun.COM 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
41147917SReza.Sabdar@Sun.COM 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
41157917SReza.Sabdar@Sun.COM 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
41167917SReza.Sabdar@Sun.COM 		pause_request.seek_position =
41177917SReza.Sabdar@Sun.COM 		    long_long_to_quad(session->ns_mover.md_position);
41187917SReza.Sabdar@Sun.COM 		session->ns_mover.md_seek_position =
41197917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_position;
41207917SReza.Sabdar@Sun.COM 
41217917SReza.Sabdar@Sun.COM 		(void) ndmpd_remove_file_handler(session, fd);
41227917SReza.Sabdar@Sun.COM 
41237917SReza.Sabdar@Sun.COM 		if (ndmp_send_request(session->ns_connection,
41247917SReza.Sabdar@Sun.COM 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
41257917SReza.Sabdar@Sun.COM 		    (void *)&pause_request, 0) < 0) {
41267917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
41277917SReza.Sabdar@Sun.COM 			    "Sending notify_mover_paused request");
41287917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
41297917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
41307917SReza.Sabdar@Sun.COM 		}
41317917SReza.Sabdar@Sun.COM 		return;
41327917SReza.Sabdar@Sun.COM 	}
41337917SReza.Sabdar@Sun.COM 
41347917SReza.Sabdar@Sun.COM 	/*
41357917SReza.Sabdar@Sun.COM 	 * Read more data into the tape buffer if the buffer is empty.
41367917SReza.Sabdar@Sun.COM 	 */
41377917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_w_index == 0) {
41387917SReza.Sabdar@Sun.COM 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
41397917SReza.Sabdar@Sun.COM 
41407917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
41417917SReza.Sabdar@Sun.COM 		    "read %u bytes from tape", n);
41427917SReza.Sabdar@Sun.COM 
41437917SReza.Sabdar@Sun.COM 		if (n <= 0) {
41447917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session, (n == 0 ?
41457917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_ABORTED
41467917SReza.Sabdar@Sun.COM 			    : NDMP_MOVER_HALT_MEDIA_ERROR));
41477917SReza.Sabdar@Sun.COM 			return;
41487917SReza.Sabdar@Sun.COM 		}
41497917SReza.Sabdar@Sun.COM 
41507917SReza.Sabdar@Sun.COM 		/*
41517917SReza.Sabdar@Sun.COM 		 * Discard data if the current data stream position is
41527917SReza.Sabdar@Sun.COM 		 * prior to the seek position. This is necessary if a seek
41537917SReza.Sabdar@Sun.COM 		 * request set the seek pointer to a position that is not a
41547917SReza.Sabdar@Sun.COM 		 * record boundary. The seek request handler can only position
41557917SReza.Sabdar@Sun.COM 		 * to the start of a record.
41567917SReza.Sabdar@Sun.COM 		 */
41577917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_position <
41587917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_seek_position) {
41597917SReza.Sabdar@Sun.COM 			session->ns_mover.md_r_index =
41607917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_seek_position -
41617917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_position;
41627917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position =
41637917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_seek_position;
41647917SReza.Sabdar@Sun.COM 		}
41657917SReza.Sabdar@Sun.COM 
41667917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = n;
41677917SReza.Sabdar@Sun.COM 	}
41687917SReza.Sabdar@Sun.COM 
41697917SReza.Sabdar@Sun.COM 	/*
41707917SReza.Sabdar@Sun.COM 	 * The limit on the total amount of data to be sent can be
41717917SReza.Sabdar@Sun.COM 	 * dictated by either the end of the mover window or the end of the
41727917SReza.Sabdar@Sun.COM 	 * seek window.
41737917SReza.Sabdar@Sun.COM 	 * First determine which window applies and then determine if the
41747917SReza.Sabdar@Sun.COM 	 * send length needs to be less than a full record to avoid
41757917SReza.Sabdar@Sun.COM 	 * exceeding the window.
41767917SReza.Sabdar@Sun.COM 	 */
41777917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_position +
41787917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_bytes_left_to_read >
41797917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_window_offset +
41807917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_window_length)
41817917SReza.Sabdar@Sun.COM 		wlen = session->ns_mover.md_window_offset +
41827917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_length -
41837917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_position;
41847917SReza.Sabdar@Sun.COM 	else
41857917SReza.Sabdar@Sun.COM 		wlen = session->ns_mover.md_bytes_left_to_read;
41867917SReza.Sabdar@Sun.COM 
41877917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
41887917SReza.Sabdar@Sun.COM 
41897917SReza.Sabdar@Sun.COM 	/*
41907917SReza.Sabdar@Sun.COM 	 * Now limit the length to the amount of data in the buffer.
41917917SReza.Sabdar@Sun.COM 	 */
41927917SReza.Sabdar@Sun.COM 	if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
41937917SReza.Sabdar@Sun.COM 		wlen = session->ns_mover.md_w_index -
41947917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_r_index;
41957917SReza.Sabdar@Sun.COM 
41967917SReza.Sabdar@Sun.COM 	len = wlen & 0xffffffff;
41977917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG,
41987917SReza.Sabdar@Sun.COM 	    "buffer restrictions: wlen %llu len %u", wlen, len);
41997917SReza.Sabdar@Sun.COM 
42007917SReza.Sabdar@Sun.COM 	/*
42017917SReza.Sabdar@Sun.COM 	 * Write the data to the data connection.
42027917SReza.Sabdar@Sun.COM 	 */
42037917SReza.Sabdar@Sun.COM 	n = write(session->ns_mover.md_sock,
42047917SReza.Sabdar@Sun.COM 	    &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
42057917SReza.Sabdar@Sun.COM 
42067917SReza.Sabdar@Sun.COM 	if (n < 0) {
42077917SReza.Sabdar@Sun.COM 		if (errno == EWOULDBLOCK) {
42087917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
42097917SReza.Sabdar@Sun.COM 			return;
42107917SReza.Sabdar@Sun.COM 		}
42117917SReza.Sabdar@Sun.COM 
42127917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
42137917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
42147917SReza.Sabdar@Sun.COM 		return;
42157917SReza.Sabdar@Sun.COM 	}
42167917SReza.Sabdar@Sun.COM 
42177917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG,
42187917SReza.Sabdar@Sun.COM 	    "wrote %u of %u bytes to data connection position %llu r_index %lu",
42197917SReza.Sabdar@Sun.COM 	    n, len, session->ns_mover.md_position,
42207917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_r_index);
42217917SReza.Sabdar@Sun.COM 
42227917SReza.Sabdar@Sun.COM 	session->ns_mover.md_r_index += n;
42237917SReza.Sabdar@Sun.COM 	session->ns_mover.md_position += n;
42247917SReza.Sabdar@Sun.COM 	session->ns_mover.md_bytes_left_to_read -= n;
42257917SReza.Sabdar@Sun.COM 
42267917SReza.Sabdar@Sun.COM 	/*
42277917SReza.Sabdar@Sun.COM 	 * If all data in the buffer has been written,
42287917SReza.Sabdar@Sun.COM 	 * zero the buffer indices. The next call to this function
42297917SReza.Sabdar@Sun.COM 	 * will read more data from the tape device into the buffer.
42307917SReza.Sabdar@Sun.COM 	 */
42317917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
42327917SReza.Sabdar@Sun.COM 		session->ns_mover.md_r_index = 0;
42337917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = 0;
42347917SReza.Sabdar@Sun.COM 	}
42357917SReza.Sabdar@Sun.COM 
42367917SReza.Sabdar@Sun.COM 	/*
42377917SReza.Sabdar@Sun.COM 	 * If the read limit has been reached,
42387917SReza.Sabdar@Sun.COM 	 * then remove the file handler to prevent this
42397917SReza.Sabdar@Sun.COM 	 * function from getting called. The next mover_read request
42407917SReza.Sabdar@Sun.COM 	 * will reinstall the handler.
42417917SReza.Sabdar@Sun.COM 	 */
42427917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_bytes_left_to_read == 0)
42437917SReza.Sabdar@Sun.COM 		(void) ndmpd_remove_file_handler(session, fd);
42447917SReza.Sabdar@Sun.COM }
42457917SReza.Sabdar@Sun.COM 
42467917SReza.Sabdar@Sun.COM 
42477917SReza.Sabdar@Sun.COM /*
42487917SReza.Sabdar@Sun.COM  * accept_connection_v3
42497917SReza.Sabdar@Sun.COM  *
42507917SReza.Sabdar@Sun.COM  * Accept a data connection from a data server.
42517917SReza.Sabdar@Sun.COM  * Called by ndmpd_select when a connection is pending on
42527917SReza.Sabdar@Sun.COM  * the mover listen socket.
42537917SReza.Sabdar@Sun.COM  *
42547917SReza.Sabdar@Sun.COM  * Parameters:
42557917SReza.Sabdar@Sun.COM  *   cookie  (input) - session pointer.
42567917SReza.Sabdar@Sun.COM  *   fd      (input) - file descriptor.
42577917SReza.Sabdar@Sun.COM  *   mode    (input) - select mode.
42587917SReza.Sabdar@Sun.COM  *
42597917SReza.Sabdar@Sun.COM  * Returns:
42607917SReza.Sabdar@Sun.COM  *   void.
42617917SReza.Sabdar@Sun.COM  */
42627917SReza.Sabdar@Sun.COM /*ARGSUSED*/
42637917SReza.Sabdar@Sun.COM static void
42647917SReza.Sabdar@Sun.COM accept_connection_v3(void *cookie, int fd, ulong_t mode)
42657917SReza.Sabdar@Sun.COM {
42667917SReza.Sabdar@Sun.COM 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
42677917SReza.Sabdar@Sun.COM 	int from_len;
42687917SReza.Sabdar@Sun.COM 	struct sockaddr_in from;
42697917SReza.Sabdar@Sun.COM 	int flag = 1;
42707917SReza.Sabdar@Sun.COM 
42717917SReza.Sabdar@Sun.COM 	from_len = sizeof (from);
42727917SReza.Sabdar@Sun.COM 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
42737917SReza.Sabdar@Sun.COM 	    &from_len);
42747917SReza.Sabdar@Sun.COM 
42757917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
42767917SReza.Sabdar@Sun.COM 	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
42777917SReza.Sabdar@Sun.COM 
42787917SReza.Sabdar@Sun.COM 	(void) ndmpd_remove_file_handler(session, fd);
42797917SReza.Sabdar@Sun.COM 	(void) close(session->ns_mover.md_listen_sock);
42807917SReza.Sabdar@Sun.COM 	session->ns_mover.md_listen_sock = -1;
42817917SReza.Sabdar@Sun.COM 
42827917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_sock < 0) {
42837917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
42847917SReza.Sabdar@Sun.COM 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
42857917SReza.Sabdar@Sun.COM 		return;
42867917SReza.Sabdar@Sun.COM 	}
42877917SReza.Sabdar@Sun.COM 
42887917SReza.Sabdar@Sun.COM 	/*
42897917SReza.Sabdar@Sun.COM 	 * Save the peer address.
42907917SReza.Sabdar@Sun.COM 	 */
42917917SReza.Sabdar@Sun.COM 	session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
42927917SReza.Sabdar@Sun.COM 	session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
42937917SReza.Sabdar@Sun.COM 
42947917SReza.Sabdar@Sun.COM 	/*
42957917SReza.Sabdar@Sun.COM 	 * Set the parameter of the new socket.
42967917SReza.Sabdar@Sun.COM 	 */
42977917SReza.Sabdar@Sun.COM 	(void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE,
42987917SReza.Sabdar@Sun.COM 	    &flag, sizeof (flag));
42997917SReza.Sabdar@Sun.COM 
43007917SReza.Sabdar@Sun.COM 	ndmp_set_socket_nodelay(session->ns_mover.md_sock);
43017917SReza.Sabdar@Sun.COM 	if (ndmp_sbs > 0)
43027917SReza.Sabdar@Sun.COM 		ndmp_set_socket_snd_buf(session->ns_mover.md_sock,
43037917SReza.Sabdar@Sun.COM 		    ndmp_sbs*KILOBYTE);
43047917SReza.Sabdar@Sun.COM 	if (ndmp_rbs > 0)
43057917SReza.Sabdar@Sun.COM 		ndmp_set_socket_rcv_buf(session->ns_mover.md_sock,
43067917SReza.Sabdar@Sun.COM 		    ndmp_rbs*KILOBYTE);
43077917SReza.Sabdar@Sun.COM 
43087917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
43097917SReza.Sabdar@Sun.COM 
43107917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
43117917SReza.Sabdar@Sun.COM 		if (ndmpd_add_file_handler(session, (void*)session,
43127917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
43137917SReza.Sabdar@Sun.COM 		    HC_MOVER, mover_data_read_v3) < 0) {
43147917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
43157917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
43167917SReza.Sabdar@Sun.COM 			return;
43177917SReza.Sabdar@Sun.COM 		}
43187917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
43197917SReza.Sabdar@Sun.COM 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
43207917SReza.Sabdar@Sun.COM 		    ntohs(from.sin_port));
43217917SReza.Sabdar@Sun.COM 	} else {
43227917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
43237917SReza.Sabdar@Sun.COM 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
43247917SReza.Sabdar@Sun.COM 		    ntohs(from.sin_port));
43257917SReza.Sabdar@Sun.COM 	}
43267917SReza.Sabdar@Sun.COM 
43277917SReza.Sabdar@Sun.COM 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
43287917SReza.Sabdar@Sun.COM }
43297917SReza.Sabdar@Sun.COM 
43307917SReza.Sabdar@Sun.COM 
43317917SReza.Sabdar@Sun.COM /*
43327917SReza.Sabdar@Sun.COM  * create_listen_socket_v3
43337917SReza.Sabdar@Sun.COM  *
43347917SReza.Sabdar@Sun.COM  * Creates a socket for listening for accepting data connections.
43357917SReza.Sabdar@Sun.COM  *
43367917SReza.Sabdar@Sun.COM  * Parameters:
43377917SReza.Sabdar@Sun.COM  *   session (input)  - session pointer.
43387917SReza.Sabdar@Sun.COM  *   addr    (output) - location to store address of socket.
43397917SReza.Sabdar@Sun.COM  *   port    (output) - location to store port of socket.
43407917SReza.Sabdar@Sun.COM  *
43417917SReza.Sabdar@Sun.COM  * Returns:
43427917SReza.Sabdar@Sun.COM  *   0 - success.
43437917SReza.Sabdar@Sun.COM  *  -1 - error.
43447917SReza.Sabdar@Sun.COM  */
43457917SReza.Sabdar@Sun.COM static int
43467917SReza.Sabdar@Sun.COM create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
43477917SReza.Sabdar@Sun.COM {
43487917SReza.Sabdar@Sun.COM 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
43497917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_listen_sock < 0)
43507917SReza.Sabdar@Sun.COM 		return (-1);
43517917SReza.Sabdar@Sun.COM 
43527917SReza.Sabdar@Sun.COM 	/*
43537917SReza.Sabdar@Sun.COM 	 * Add a file handler for the listen socket.
43547917SReza.Sabdar@Sun.COM 	 * ndmpd_select will call accept_connection when a
43557917SReza.Sabdar@Sun.COM 	 * connection is ready to be accepted.
43567917SReza.Sabdar@Sun.COM 	 */
43577917SReza.Sabdar@Sun.COM 	if (ndmpd_add_file_handler(session, (void *) session,
43587917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
43597917SReza.Sabdar@Sun.COM 	    accept_connection_v3) < 0) {
43607917SReza.Sabdar@Sun.COM 		(void) close(session->ns_mover.md_listen_sock);
43617917SReza.Sabdar@Sun.COM 		session->ns_mover.md_listen_sock = -1;
43627917SReza.Sabdar@Sun.COM 		return (-1);
43637917SReza.Sabdar@Sun.COM 	}
43647917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "IP %s port %d",
43657917SReza.Sabdar@Sun.COM 	    inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
43667917SReza.Sabdar@Sun.COM 	return (0);
43677917SReza.Sabdar@Sun.COM }
43687917SReza.Sabdar@Sun.COM 
43697917SReza.Sabdar@Sun.COM 
43707917SReza.Sabdar@Sun.COM /*
43717917SReza.Sabdar@Sun.COM  * mover_connect_sock_v3
43727917SReza.Sabdar@Sun.COM  *
43737917SReza.Sabdar@Sun.COM  * Connect the mover to the specified address
43747917SReza.Sabdar@Sun.COM  *
43757917SReza.Sabdar@Sun.COM  * Parameters:
43767917SReza.Sabdar@Sun.COM  *   session (input)  - session pointer.
43777917SReza.Sabdar@Sun.COM  *   mode    (input)  - mover mode.
43787917SReza.Sabdar@Sun.COM  *   addr    (output) - location to store address of socket.
43797917SReza.Sabdar@Sun.COM  *   port    (output) - location to store port of socket.
43807917SReza.Sabdar@Sun.COM  *
43817917SReza.Sabdar@Sun.COM  * Returns:
43827917SReza.Sabdar@Sun.COM  *   error code.
43837917SReza.Sabdar@Sun.COM  */
43847917SReza.Sabdar@Sun.COM static ndmp_error
43857917SReza.Sabdar@Sun.COM mover_connect_sock_v3(ndmpd_session_t *session, ndmp_mover_mode mode,
43867917SReza.Sabdar@Sun.COM     ulong_t addr, ushort_t port)
43877917SReza.Sabdar@Sun.COM {
43887917SReza.Sabdar@Sun.COM 	int sock;
43897917SReza.Sabdar@Sun.COM 
43907917SReza.Sabdar@Sun.COM 	sock = ndmp_connect_sock_v3(addr, port);
43917917SReza.Sabdar@Sun.COM 	if (sock < 0)
43927917SReza.Sabdar@Sun.COM 		return (NDMP_CONNECT_ERR);
43937917SReza.Sabdar@Sun.COM 
43947917SReza.Sabdar@Sun.COM 	if (mode == NDMP_MOVER_MODE_READ) {
43957917SReza.Sabdar@Sun.COM 		if (ndmpd_add_file_handler(session, (void*)session, sock,
43967917SReza.Sabdar@Sun.COM 		    NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
43977917SReza.Sabdar@Sun.COM 			(void) close(sock);
43987917SReza.Sabdar@Sun.COM 			return (NDMP_CONNECT_ERR);
43997917SReza.Sabdar@Sun.COM 		}
44007917SReza.Sabdar@Sun.COM 	}
44017917SReza.Sabdar@Sun.COM 	session->ns_mover.md_sock = sock;
44027917SReza.Sabdar@Sun.COM 	session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
44037917SReza.Sabdar@Sun.COM 	session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
44047917SReza.Sabdar@Sun.COM 	session->ns_mover.md_data_addr.tcp_port_v3 = port;
44057917SReza.Sabdar@Sun.COM 	return (NDMP_NO_ERR);
44067917SReza.Sabdar@Sun.COM }
44077917SReza.Sabdar@Sun.COM 
44087917SReza.Sabdar@Sun.COM 
44097917SReza.Sabdar@Sun.COM /*
44107917SReza.Sabdar@Sun.COM  * ndmpd_local_read_v3
44117917SReza.Sabdar@Sun.COM  *
44127917SReza.Sabdar@Sun.COM  * Reads data from the local tape device.
44137917SReza.Sabdar@Sun.COM  * Full tape records are read and buffered.
44147917SReza.Sabdar@Sun.COM  *
44157917SReza.Sabdar@Sun.COM  * Parameters:
44167917SReza.Sabdar@Sun.COM  *   session (input) - session pointer.
44177917SReza.Sabdar@Sun.COM  *   data    (input) - location to store data.
44187917SReza.Sabdar@Sun.COM  *   length  (input) - data length.
44197917SReza.Sabdar@Sun.COM  *
44207917SReza.Sabdar@Sun.COM  * Returns:
44217917SReza.Sabdar@Sun.COM  *   1 - no read error but no writer running
44227917SReza.Sabdar@Sun.COM  *   0 - data successfully read.
44237917SReza.Sabdar@Sun.COM  *  -1 - error.
44247917SReza.Sabdar@Sun.COM  */
44257917SReza.Sabdar@Sun.COM int
44267917SReza.Sabdar@Sun.COM ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
44277917SReza.Sabdar@Sun.COM {
44287917SReza.Sabdar@Sun.COM 	ulong_t count;
44297917SReza.Sabdar@Sun.COM 	ulong_t len;
44307917SReza.Sabdar@Sun.COM 	ssize_t n;
44317917SReza.Sabdar@Sun.COM 
44327917SReza.Sabdar@Sun.COM 	count = 0;
44337917SReza.Sabdar@Sun.COM 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
44347917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
44357917SReza.Sabdar@Sun.COM 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
44367917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
44377917SReza.Sabdar@Sun.COM 		return (-1);
44387917SReza.Sabdar@Sun.COM 	}
44397917SReza.Sabdar@Sun.COM 
44407917SReza.Sabdar@Sun.COM 	/*
44417917SReza.Sabdar@Sun.COM 	 * Automatically increase the seek window if necessary.
44427917SReza.Sabdar@Sun.COM 	 * This is needed in the event the module attempts to read
44437917SReza.Sabdar@Sun.COM 	 * past a seek window set via a prior call to ndmpd_seek() or
44447917SReza.Sabdar@Sun.COM 	 * the module has not issued a seek. If no seek was issued then
44457917SReza.Sabdar@Sun.COM 	 * pretend that a seek was issued to read the entire tape.
44467917SReza.Sabdar@Sun.COM 	 */
44477917SReza.Sabdar@Sun.COM 	if (length > session->ns_mover.md_bytes_left_to_read) {
44487917SReza.Sabdar@Sun.COM 		/* ndmpd_seek() never called? */
44497917SReza.Sabdar@Sun.COM 		if (session->ns_data.dd_read_length == 0) {
44507917SReza.Sabdar@Sun.COM 			session->ns_mover.md_bytes_left_to_read = ~0LL;
44517917SReza.Sabdar@Sun.COM 			session->ns_data.dd_read_offset = 0LL;
44527917SReza.Sabdar@Sun.COM 			session->ns_data.dd_read_length = ~0LL;
44537917SReza.Sabdar@Sun.COM 		} else {
44547917SReza.Sabdar@Sun.COM 			session->ns_mover.md_bytes_left_to_read = length;
44557917SReza.Sabdar@Sun.COM 			session->ns_data.dd_read_offset =
44567917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_position;
44577917SReza.Sabdar@Sun.COM 			session->ns_data.dd_read_length = length;
44587917SReza.Sabdar@Sun.COM 		}
44597917SReza.Sabdar@Sun.COM 	}
44607917SReza.Sabdar@Sun.COM 
44617917SReza.Sabdar@Sun.COM 	/*
44627917SReza.Sabdar@Sun.COM 	 * Read as many records as necessary to satisfy the request.
44637917SReza.Sabdar@Sun.COM 	 */
44647917SReza.Sabdar@Sun.COM 	while (count < length) {
44657917SReza.Sabdar@Sun.COM 		/*
44667917SReza.Sabdar@Sun.COM 		 * If the end of the mover window has been reached,
44677917SReza.Sabdar@Sun.COM 		 * then notify the client that a new data window is needed.
44687917SReza.Sabdar@Sun.COM 		 */
44697917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_position >=
44707917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_offset +
44717917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_length) {
44727917SReza.Sabdar@Sun.COM 			if (mover_pause_v3(session,
44737917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_PAUSE_SEEK) < 0) {
44747917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
44757917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
44767917SReza.Sabdar@Sun.COM 				return (-1);
44777917SReza.Sabdar@Sun.COM 			}
44787917SReza.Sabdar@Sun.COM 			continue;
44797917SReza.Sabdar@Sun.COM 		}
44807917SReza.Sabdar@Sun.COM 
44817917SReza.Sabdar@Sun.COM 		len = length - count;
44827917SReza.Sabdar@Sun.COM 
44837917SReza.Sabdar@Sun.COM 		/*
44847917SReza.Sabdar@Sun.COM 		 * Prevent reading past the end of the window.
44857917SReza.Sabdar@Sun.COM 		 */
44867917SReza.Sabdar@Sun.COM 		if (len > session->ns_mover.md_window_offset +
44877917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_window_length -
44887917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_position)
44897917SReza.Sabdar@Sun.COM 			len = session->ns_mover.md_window_offset +
44907917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_window_length -
44917917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_position;
44927917SReza.Sabdar@Sun.COM 
44937917SReza.Sabdar@Sun.COM 		/*
44947917SReza.Sabdar@Sun.COM 		 * Copy from the data buffer first.
44957917SReza.Sabdar@Sun.COM 		 */
44967917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_w_index -
44977917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_r_index != 0) {
44987917SReza.Sabdar@Sun.COM 			/*
44997917SReza.Sabdar@Sun.COM 			 * Limit the copy to the amount of data in the buffer.
45007917SReza.Sabdar@Sun.COM 			 */
45017917SReza.Sabdar@Sun.COM 			if (len > session->ns_mover.md_w_index -
45027917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_r_index)
45037917SReza.Sabdar@Sun.COM 				len = session->ns_mover.md_w_index -
45047917SReza.Sabdar@Sun.COM 				    session->ns_mover.md_r_index;
45057917SReza.Sabdar@Sun.COM 			(void) memcpy((void*)&data[count],
45067917SReza.Sabdar@Sun.COM 			    &session->ns_mover.md_buf[session->
45077917SReza.Sabdar@Sun.COM 			    ns_mover.md_r_index], len);
45087917SReza.Sabdar@Sun.COM 			count += len;
45097917SReza.Sabdar@Sun.COM 			session->ns_mover.md_r_index += len;
45107917SReza.Sabdar@Sun.COM 			session->ns_mover.md_bytes_left_to_read -= len;
45117917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position += len;
45127917SReza.Sabdar@Sun.COM 			continue;
45137917SReza.Sabdar@Sun.COM 		}
45147917SReza.Sabdar@Sun.COM 
45157917SReza.Sabdar@Sun.COM 		/*
45167917SReza.Sabdar@Sun.COM 		 * Determine if data needs to be buffered or
45177917SReza.Sabdar@Sun.COM 		 * can be read directly to user supplied location.
45187917SReza.Sabdar@Sun.COM 		 * We can fast path the read if at least a full record
45197917SReza.Sabdar@Sun.COM 		 * needs to be read and there is no seek pending.
45207917SReza.Sabdar@Sun.COM 		 * This is done to eliminate a buffer copy.
45217917SReza.Sabdar@Sun.COM 		 */
45227917SReza.Sabdar@Sun.COM 		if (len >= session->ns_mover.md_record_size &&
45237917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_position >=
45247917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_seek_position) {
45257917SReza.Sabdar@Sun.COM 			n = mover_tape_read_v3(session, &data[count]);
45267917SReza.Sabdar@Sun.COM 			if (n <= 0) {
45277917SReza.Sabdar@Sun.COM 				if (n == TAPE_NO_WRITER_ERR)
45287917SReza.Sabdar@Sun.COM 					return (1);
45297917SReza.Sabdar@Sun.COM 
45307917SReza.Sabdar@Sun.COM 				ndmpd_mover_error(session,
45317917SReza.Sabdar@Sun.COM 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
45327917SReza.Sabdar@Sun.COM 				    NDMP_MOVER_HALT_MEDIA_ERROR));
45337917SReza.Sabdar@Sun.COM 				return ((n == 0) ? 1 : -1);
45347917SReza.Sabdar@Sun.COM 			}
45357917SReza.Sabdar@Sun.COM 
45367917SReza.Sabdar@Sun.COM 			count += n;
45377917SReza.Sabdar@Sun.COM 			session->ns_mover.md_bytes_left_to_read -= n;
45387917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position += n;
45397917SReza.Sabdar@Sun.COM 			continue;
45407917SReza.Sabdar@Sun.COM 		}
45417917SReza.Sabdar@Sun.COM 
45427917SReza.Sabdar@Sun.COM 		/* Read the next record into the buffer. */
45437917SReza.Sabdar@Sun.COM 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
45447917SReza.Sabdar@Sun.COM 		if (n <= 0) {
45457917SReza.Sabdar@Sun.COM 			if (n == TAPE_NO_WRITER_ERR)
45467917SReza.Sabdar@Sun.COM 				return (1);
45477917SReza.Sabdar@Sun.COM 
45487917SReza.Sabdar@Sun.COM 			ndmpd_mover_error(session,
45497917SReza.Sabdar@Sun.COM 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
45507917SReza.Sabdar@Sun.COM 			    NDMP_MOVER_HALT_MEDIA_ERROR));
45517917SReza.Sabdar@Sun.COM 			return ((n == 0) ? 1 : -1);
45527917SReza.Sabdar@Sun.COM 		}
45537917SReza.Sabdar@Sun.COM 
45547917SReza.Sabdar@Sun.COM 		session->ns_mover.md_w_index = n;
45557917SReza.Sabdar@Sun.COM 		session->ns_mover.md_r_index = 0;
45567917SReza.Sabdar@Sun.COM 
45577917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
45587917SReza.Sabdar@Sun.COM 
45597917SReza.Sabdar@Sun.COM 		/*
45607917SReza.Sabdar@Sun.COM 		 * Discard data if the current data stream position is
45617917SReza.Sabdar@Sun.COM 		 * prior to the seek position. This is necessary if a seek
45627917SReza.Sabdar@Sun.COM 		 * request set the seek pointer to a position that is not a
45637917SReza.Sabdar@Sun.COM 		 * record boundary. The seek request handler can only position
45647917SReza.Sabdar@Sun.COM 		 * to the start of a record.
45657917SReza.Sabdar@Sun.COM 		 */
45667917SReza.Sabdar@Sun.COM 		if (session->ns_mover.md_position <
45677917SReza.Sabdar@Sun.COM 		    session->ns_mover.md_seek_position) {
45687917SReza.Sabdar@Sun.COM 			session->ns_mover.md_r_index =
45697917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_seek_position -
45707917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_position;
45717917SReza.Sabdar@Sun.COM 			session->ns_mover.md_position =
45727917SReza.Sabdar@Sun.COM 			    session->ns_mover.md_seek_position;
45737917SReza.Sabdar@Sun.COM 		}
45747917SReza.Sabdar@Sun.COM 	}
45757917SReza.Sabdar@Sun.COM 
45767917SReza.Sabdar@Sun.COM 	return (0);
45777917SReza.Sabdar@Sun.COM }
4578