xref: /titanic_52/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c (revision f5b1cef2488dc579cb4312d49164f10debf8e97d)
12654012fSReza Sabdar /*
28c4f9701SJanice Chang  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
32654012fSReza Sabdar  */
42654012fSReza Sabdar 
52654012fSReza Sabdar /*
62654012fSReza Sabdar  * BSD 3 Clause License
72654012fSReza Sabdar  *
82654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
92654012fSReza Sabdar  *
102654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
112654012fSReza Sabdar  * modification, are permitted provided that the following conditions
122654012fSReza Sabdar  * are met:
132654012fSReza Sabdar  * 	- Redistributions of source code must retain the above copyright
142654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
152654012fSReza Sabdar  *
162654012fSReza Sabdar  * 	- Redistributions in binary form must reproduce the above copyright
172654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
182654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
192654012fSReza Sabdar  *	  distribution.
202654012fSReza Sabdar  *
212654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
222654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
232654012fSReza Sabdar  *	  products derived from this software without specific prior written
242654012fSReza Sabdar  *	  permission.
252654012fSReza Sabdar  *
262654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
272654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
282654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
292654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
302654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
312654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
322654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
332654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
342654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
352654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
362654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
372654012fSReza Sabdar  */
382654012fSReza Sabdar /* Copyright (c) 2007, The Storage Networking Industry Association. */
392654012fSReza Sabdar /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
409ee94b97SJan Kryl /* Copyright 2014 Nexenta Systems, Inc.  All rights reserved. */
412654012fSReza Sabdar 
422654012fSReza Sabdar #include <sys/ioctl.h>
432654012fSReza Sabdar #include <sys/types.h>
442654012fSReza Sabdar #include <sys/socket.h>
452654012fSReza Sabdar #include <sys/socketvar.h>
462654012fSReza Sabdar #include <netinet/in.h>
472654012fSReza Sabdar #include <arpa/inet.h>
482654012fSReza Sabdar #include <net/if.h>
492654012fSReza Sabdar #include <errno.h>
502654012fSReza Sabdar #include <fcntl.h>
512654012fSReza Sabdar #include <netdb.h>
522654012fSReza Sabdar #include <stdlib.h>
532654012fSReza Sabdar #include <unistd.h>
542654012fSReza Sabdar #include <string.h>
552654012fSReza Sabdar #include "ndmpd_common.h"
562654012fSReza Sabdar #include "ndmpd.h"
572654012fSReza Sabdar #include <sys/mtio.h>
582654012fSReza Sabdar 
592654012fSReza Sabdar /*
602654012fSReza Sabdar  * Maximum mover record size
612654012fSReza Sabdar  */
622654012fSReza Sabdar #define	MAX_MOVER_RECSIZE	(512*KILOBYTE)
632654012fSReza Sabdar 
642654012fSReza Sabdar static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
652654012fSReza Sabdar     ushort_t *port);
662654012fSReza Sabdar static int tape_read(ndmpd_session_t *session, char *data);
672654012fSReza Sabdar static int change_tape(ndmpd_session_t *session);
682654012fSReza Sabdar static int discard_data(ndmpd_session_t *session, ulong_t length);
692654012fSReza Sabdar static int mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf);
702654012fSReza Sabdar static int mover_socket_write_one_buf(ndmpd_session_t *session,
712654012fSReza Sabdar     tlm_buffer_t *buf);
722654012fSReza Sabdar static int start_mover_for_restore(ndmpd_session_t *session);
732654012fSReza Sabdar static int mover_socket_read_one_buf(ndmpd_session_t *session,
742654012fSReza Sabdar     tlm_buffer_t *buf, long read_size);
752654012fSReza Sabdar static int mover_tape_write_one_buf(ndmpd_session_t *session,
762654012fSReza Sabdar     tlm_buffer_t *buf);
772654012fSReza Sabdar static int start_mover_for_backup(ndmpd_session_t *session);
782654012fSReza Sabdar static boolean_t is_writer_running_v3(ndmpd_session_t *session);
792654012fSReza Sabdar static int mover_pause_v3(ndmpd_session_t *session,
802654012fSReza Sabdar     ndmp_mover_pause_reason reason);
812654012fSReza Sabdar static int mover_tape_write_v3(ndmpd_session_t *session, char *data,
822654012fSReza Sabdar     ssize_t length);
832654012fSReza Sabdar static int mover_tape_flush_v3(ndmpd_session_t *session);
842654012fSReza Sabdar static int mover_tape_read_v3(ndmpd_session_t *session, char *data);
852654012fSReza Sabdar static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
862654012fSReza Sabdar     ushort_t *port);
872654012fSReza Sabdar static void mover_data_read_v3(void *cookie, int fd, ulong_t mode);
882654012fSReza Sabdar static void accept_connection(void *cookie, int fd, ulong_t mode);
892654012fSReza Sabdar static void mover_data_write_v3(void *cookie, int fd, ulong_t mode);
902654012fSReza Sabdar static void accept_connection_v3(void *cookie, int fd, ulong_t mode);
9197f7c475SJan Kryl static ndmp_error mover_connect_sock(ndmpd_session_t *session,
922654012fSReza Sabdar     ndmp_mover_mode mode, ulong_t addr, ushort_t port);
932654012fSReza Sabdar static boolean_t is_writer_running(ndmpd_session_t *session);
9497f7c475SJan Kryl static int set_socket_nonblock(int sock);
952654012fSReza Sabdar 
962654012fSReza Sabdar 
972654012fSReza Sabdar int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
982654012fSReza Sabdar 
992654012fSReza Sabdar #define	TAPE_READ_ERR		-1
1002654012fSReza Sabdar #define	TAPE_NO_WRITER_ERR	-2
1012654012fSReza Sabdar 
1022654012fSReza Sabdar /*
10397f7c475SJan Kryl  * Set non-blocking mode for socket.
10497f7c475SJan Kryl  */
10597f7c475SJan Kryl static int
10697f7c475SJan Kryl set_socket_nonblock(int sock)
10797f7c475SJan Kryl {
10897f7c475SJan Kryl 	int flags;
10997f7c475SJan Kryl 
11097f7c475SJan Kryl 	flags = fcntl(sock, F_GETFL, 0);
11197f7c475SJan Kryl 	if (flags < 0)
11297f7c475SJan Kryl 		return (0);
11397f7c475SJan Kryl 	return (fcntl(sock, F_SETFL, flags|O_NONBLOCK) == 0);
11497f7c475SJan Kryl }
11597f7c475SJan Kryl 
11697f7c475SJan Kryl /*
1172654012fSReza Sabdar  * ************************************************************************
1182654012fSReza Sabdar  * NDMP V2 HANDLERS
1192654012fSReza Sabdar  * ************************************************************************
1202654012fSReza Sabdar  */
1212654012fSReza Sabdar 
1222654012fSReza Sabdar /*
1232654012fSReza Sabdar  * ndmpd_mover_get_state_v2
1242654012fSReza Sabdar  *
1252654012fSReza Sabdar  * This handler handles the mover_get_state request.
1262654012fSReza Sabdar  * Status information for the mover state machine is returned.
1272654012fSReza Sabdar  *
1282654012fSReza Sabdar  * Parameters:
1292654012fSReza Sabdar  *   connection (input) - connection handle.
1302654012fSReza Sabdar  *   body       (input) - request message body.
1312654012fSReza Sabdar  *
1322654012fSReza Sabdar  * Returns:
1332654012fSReza Sabdar  *   void
1342654012fSReza Sabdar  */
1352654012fSReza Sabdar /*ARGSUSED*/
1362654012fSReza Sabdar void
1372654012fSReza Sabdar ndmpd_mover_get_state_v2(ndmp_connection_t *connection, void *body)
1382654012fSReza Sabdar {
1392654012fSReza Sabdar 	ndmp_mover_get_state_reply_v2 reply;
1402654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1412654012fSReza Sabdar 
1422654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
1432654012fSReza Sabdar 	reply.state = session->ns_mover.md_state;
1442654012fSReza Sabdar 	reply.pause_reason = session->ns_mover.md_pause_reason;
1452654012fSReza Sabdar 	reply.halt_reason = session->ns_mover.md_halt_reason;
1462654012fSReza Sabdar 	reply.record_size = session->ns_mover.md_record_size;
1472654012fSReza Sabdar 	reply.record_num = session->ns_mover.md_record_num;
1482654012fSReza Sabdar 	reply.data_written =
1492654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_data_written);
1502654012fSReza Sabdar 	reply.seek_position =
1512654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_seek_position);
1522654012fSReza Sabdar 	reply.bytes_left_to_read =
1532654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
1542654012fSReza Sabdar 	reply.window_offset =
1552654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_offset);
1562654012fSReza Sabdar 	reply.window_length =
1572654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_length);
1582654012fSReza Sabdar 
1592654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
1602654012fSReza Sabdar 	    "sending tape_get_state reply");
1612654012fSReza Sabdar }
1622654012fSReza Sabdar 
1632654012fSReza Sabdar 
1642654012fSReza Sabdar /*
1652654012fSReza Sabdar  * ndmpd_mover_listen_v2
1662654012fSReza Sabdar  *
1672654012fSReza Sabdar  * This handler handles mover_listen requests.
1682654012fSReza Sabdar  *
1692654012fSReza Sabdar  * Parameters:
1702654012fSReza Sabdar  *   connection (input) - connection handle.
1712654012fSReza Sabdar  *   body       (input) - request message body.
1722654012fSReza Sabdar  *
1732654012fSReza Sabdar  * Returns:
1742654012fSReza Sabdar  *   void
1752654012fSReza Sabdar  */
1762654012fSReza Sabdar void
1772654012fSReza Sabdar ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
1782654012fSReza Sabdar {
1792654012fSReza Sabdar 	ndmp_mover_listen_request_v2 *request;
1802654012fSReza Sabdar 	ndmp_mover_listen_reply_v2 reply;
1812654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1822654012fSReza Sabdar 	ulong_t addr;
1832654012fSReza Sabdar 	ushort_t port;
1842654012fSReza Sabdar 
1852654012fSReza Sabdar 	request = (ndmp_mover_listen_request_v2 *)body;
1862654012fSReza Sabdar 
1872654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
1882654012fSReza Sabdar 	    session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1892654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
1902654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1912654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
1922654012fSReza Sabdar 		    "sending mover_listen reply");
1932654012fSReza Sabdar 		return;
1942654012fSReza Sabdar 	}
1952654012fSReza Sabdar 	session->ns_mover.md_mode = request->mode;
1962654012fSReza Sabdar 
1972654012fSReza Sabdar 	if (request->addr_type == NDMP_ADDR_LOCAL) {
1982654012fSReza Sabdar 		reply.mover.addr_type = NDMP_ADDR_LOCAL;
1992654012fSReza Sabdar 	} else {
2002654012fSReza Sabdar 		if (create_listen_socket_v2(session, &addr, &port) < 0) {
2012654012fSReza Sabdar 			reply.error = NDMP_IO_ERR;
2022654012fSReza Sabdar 			ndmp_send_reply(connection, (void *) &reply,
2032654012fSReza Sabdar 			    "sending mover_listen reply");
2042654012fSReza Sabdar 			return;
2052654012fSReza Sabdar 		}
2062654012fSReza Sabdar 		reply.mover.addr_type = NDMP_ADDR_TCP;
2072654012fSReza Sabdar 		reply.mover.ndmp_mover_addr_u.addr.ip_addr = htonl(addr);
2082654012fSReza Sabdar 		reply.mover.ndmp_mover_addr_u.addr.port = htons(port);
2092654012fSReza Sabdar 	}
2102654012fSReza Sabdar 
2112654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
2122654012fSReza Sabdar 
2132654012fSReza Sabdar 	/*
2142654012fSReza Sabdar 	 * ndmp window should always set by client during restore
2152654012fSReza Sabdar 	 */
2162654012fSReza Sabdar 
2172654012fSReza Sabdar 	/* Set the default window. */
2182654012fSReza Sabdar 	session->ns_mover.md_window_offset = 0;
2192654012fSReza Sabdar 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
2202654012fSReza Sabdar 	session->ns_mover.md_position = 0;
2212654012fSReza Sabdar 
2222654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
2232654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
2242654012fSReza Sabdar 	    "sending mover_listen reply");
2252654012fSReza Sabdar }
2262654012fSReza Sabdar 
2272654012fSReza Sabdar 
2282654012fSReza Sabdar /*
2292654012fSReza Sabdar  * ndmpd_mover_continue_v2
2302654012fSReza Sabdar  *
2312654012fSReza Sabdar  * This handler handles mover_continue requests.
2322654012fSReza Sabdar  *
2332654012fSReza Sabdar  * Parameters:
2342654012fSReza Sabdar  *   connection (input) - connection handle.
2352654012fSReza Sabdar  *   body       (input) - request message body.
2362654012fSReza Sabdar  *
2372654012fSReza Sabdar  * Returns:
2382654012fSReza Sabdar  *   void
2392654012fSReza Sabdar  */
2402654012fSReza Sabdar /*ARGSUSED*/
2412654012fSReza Sabdar void
2422654012fSReza Sabdar ndmpd_mover_continue_v2(ndmp_connection_t *connection, void *body)
2432654012fSReza Sabdar {
2442654012fSReza Sabdar 	ndmp_mover_continue_reply reply;
2452654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
2462654012fSReza Sabdar 
2472654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
2482654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
2492654012fSReza Sabdar 
2502654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
2512654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
2522654012fSReza Sabdar 		    "sending mover_continue reply");
2532654012fSReza Sabdar 		return;
2542654012fSReza Sabdar 	}
2552654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2562654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
2572654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
2582654012fSReza Sabdar 	    "sending mover_continue reply");
2592654012fSReza Sabdar }
2602654012fSReza Sabdar 
2612654012fSReza Sabdar 
2622654012fSReza Sabdar /*
2632654012fSReza Sabdar  * ndmpd_mover_abort_v2
2642654012fSReza Sabdar  *
2652654012fSReza Sabdar  * This handler handles mover_abort requests.
2662654012fSReza Sabdar  *
2672654012fSReza Sabdar  * Parameters:
2682654012fSReza Sabdar  *   connection (input) - connection handle.
2692654012fSReza Sabdar  *   body       (input) - request message body.
2702654012fSReza Sabdar  *
2712654012fSReza Sabdar  * Returns:
2722654012fSReza Sabdar  *   void
2732654012fSReza Sabdar  */
2742654012fSReza Sabdar /*ARGSUSED*/
2752654012fSReza Sabdar void
2762654012fSReza Sabdar ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
2772654012fSReza Sabdar {
2782654012fSReza Sabdar 	ndmp_mover_abort_reply reply;
2792654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
2802654012fSReza Sabdar 
2812654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
2822654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
2832654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
2842654012fSReza Sabdar 
2852654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
2862654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
2872654012fSReza Sabdar 		    "sending mover_abort reply");
2882654012fSReza Sabdar 		return;
2892654012fSReza Sabdar 	}
2902654012fSReza Sabdar 
2912654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
2922654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
2932654012fSReza Sabdar 	    "sending mover_abort reply");
2942654012fSReza Sabdar 
2952654012fSReza Sabdar 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
2962654012fSReza Sabdar 	ndmp_stop_buffer_worker(session);
2972654012fSReza Sabdar }
2982654012fSReza Sabdar 
2992654012fSReza Sabdar 
3002654012fSReza Sabdar /*
3012654012fSReza Sabdar  * ndmpd_mover_stop_v2
3022654012fSReza Sabdar  *
3032654012fSReza Sabdar  * This handler handles mover_stop requests.
3042654012fSReza Sabdar  *
3052654012fSReza Sabdar  * Parameters:
3062654012fSReza Sabdar  *   connection (input) - connection handle.
3072654012fSReza Sabdar  *   body       (input) - request message body.
3082654012fSReza Sabdar  *
3092654012fSReza Sabdar  * Returns:
3102654012fSReza Sabdar  *   void
3112654012fSReza Sabdar  */
3122654012fSReza Sabdar /*ARGSUSED*/
3132654012fSReza Sabdar void
3142654012fSReza Sabdar ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
3152654012fSReza Sabdar {
3162654012fSReza Sabdar 	ndmp_mover_stop_reply reply;
3172654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
3182654012fSReza Sabdar 
3192654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {
3202654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
3212654012fSReza Sabdar 
3222654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
3232654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
3242654012fSReza Sabdar 		    "sending mover_stop reply");
3252654012fSReza Sabdar 		return;
3262654012fSReza Sabdar 	}
3272654012fSReza Sabdar 
3282654012fSReza Sabdar 	ndmp_waitfor_op(session);
3292654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
3302654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
3312654012fSReza Sabdar 	    "sending mover_stop reply");
3322654012fSReza Sabdar 
3332654012fSReza Sabdar 	ndmp_lbr_cleanup(session);
3342654012fSReza Sabdar 	ndmpd_mover_cleanup(session);
3352654012fSReza Sabdar 	(void) ndmpd_mover_init(session);
3362654012fSReza Sabdar 	(void) ndmp_lbr_init(session);
3372654012fSReza Sabdar }
3382654012fSReza Sabdar 
3392654012fSReza Sabdar 
3402654012fSReza Sabdar /*
3412654012fSReza Sabdar  * ndmpd_mover_set_window_v2
3422654012fSReza Sabdar  *
3432654012fSReza Sabdar  * This handler handles mover_set_window requests.
3442654012fSReza Sabdar  *
3452654012fSReza Sabdar  *
3462654012fSReza Sabdar  * Parameters:
3472654012fSReza Sabdar  *   connection (input) - connection handle.
3482654012fSReza Sabdar  *   body       (input) - request message body.
3492654012fSReza Sabdar  *
3502654012fSReza Sabdar  * Returns:
3512654012fSReza Sabdar  *   void
3522654012fSReza Sabdar  */
3532654012fSReza Sabdar void
3542654012fSReza Sabdar ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
3552654012fSReza Sabdar {
3562654012fSReza Sabdar 	ndmp_mover_set_window_request *request;
3572654012fSReza Sabdar 	ndmp_mover_set_window_reply reply;
3582654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
3592654012fSReza Sabdar 
3602654012fSReza Sabdar 	request = (ndmp_mover_set_window_request *) body;
3612654012fSReza Sabdar 
3622654012fSReza Sabdar 	/*
3632654012fSReza Sabdar 	 * The NDMPv2 specification states that "a window can be set only
3642654012fSReza Sabdar 	 * when in the listen or paused state."
3652654012fSReza Sabdar 	 *
3662654012fSReza Sabdar 	 * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
3672654012fSReza Sabdar 	 * allowing it in the idle state as well.
3682654012fSReza Sabdar 	 */
3692654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
3702654012fSReza Sabdar 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
3712654012fSReza Sabdar 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
3722654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
3732654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
3742654012fSReza Sabdar 		    session->ns_mover.md_state);
3752654012fSReza Sabdar 	} else {
3762654012fSReza Sabdar 		if (quad_to_long_long(request->length) == 0) {
3772654012fSReza Sabdar 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
3782654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
3792654012fSReza Sabdar 			    quad_to_long_long(request->length));
3802654012fSReza Sabdar 		} else {
3812654012fSReza Sabdar 			reply.error = NDMP_NO_ERR;
3822654012fSReza Sabdar 			session->ns_mover.md_window_offset =
3832654012fSReza Sabdar 			    quad_to_long_long(request->offset);
3842654012fSReza Sabdar 			session->ns_mover.md_window_length =
3852654012fSReza Sabdar 			    quad_to_long_long(request->length);
3862654012fSReza Sabdar 			session->ns_mover.md_position =
3872654012fSReza Sabdar 			    session->ns_mover.md_window_offset;
3882654012fSReza Sabdar 		}
3892654012fSReza Sabdar 	}
3902654012fSReza Sabdar 
3912654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
3922654012fSReza Sabdar 	    "sending mover_set_window reply");
3932654012fSReza Sabdar }
3942654012fSReza Sabdar 
3952654012fSReza Sabdar 
3962654012fSReza Sabdar /*
3972654012fSReza Sabdar  * ndmpd_mover_read_v2
3982654012fSReza Sabdar  *
3992654012fSReza Sabdar  * This handler handles mover_read requests. If the requested offset is
4002654012fSReza Sabdar  * outside of the current window, the mover is paused and a notify_mover_paused
4012654012fSReza Sabdar  * request is sent notifying the client that a seek is required. If the
4022654012fSReza Sabdar  * requested offest is within the window but not within the current record,
4032654012fSReza Sabdar  * then the tape is positioned to the record containing the requested offest.
4042654012fSReza Sabdar  * The requested amount of data is then read from the tape device and written
4052654012fSReza Sabdar  * to the data connection.
4062654012fSReza Sabdar  *
4072654012fSReza Sabdar  * Parameters:
4082654012fSReza Sabdar  *   connection (input) - connection handle.
4092654012fSReza Sabdar  *   body       (input) - request message body.
4102654012fSReza Sabdar  *
4112654012fSReza Sabdar  * Returns:
4122654012fSReza Sabdar  *   void
4132654012fSReza Sabdar  */
4142654012fSReza Sabdar void
4152654012fSReza Sabdar ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
4162654012fSReza Sabdar {
4172654012fSReza Sabdar 	ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
4182654012fSReza Sabdar 	ndmp_mover_read_reply reply;
4192654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
4202654012fSReza Sabdar 	int err;
4212654012fSReza Sabdar 
4222654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
4232654012fSReza Sabdar 	    session->ns_mover.md_bytes_left_to_read != 0 ||
4242654012fSReza Sabdar 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
4252654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
4262654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
4272654012fSReza Sabdar 		ndmp_send_reply(connection, &reply,
4282654012fSReza Sabdar 		    "sending mover_read reply");
4292654012fSReza Sabdar 		return;
4302654012fSReza Sabdar 	}
4312654012fSReza Sabdar 	if (session->ns_tape.td_fd == -1) {
4322654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
4332654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
4342654012fSReza Sabdar 		ndmp_send_reply(connection, &reply,
4352654012fSReza Sabdar 		    "sending mover_read reply");
4362654012fSReza Sabdar 		return;
4372654012fSReza Sabdar 	}
4382654012fSReza Sabdar 
4392654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
4402654012fSReza Sabdar 	ndmp_send_reply(connection, &reply, "sending mover_read reply");
4412654012fSReza Sabdar 
4422654012fSReza Sabdar 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
4432654012fSReza Sabdar 	    quad_to_long_long(request->length));
4442654012fSReza Sabdar 	if (err < 0) {
4452654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4462654012fSReza Sabdar 		return;
4472654012fSReza Sabdar 	}
4482654012fSReza Sabdar 	/*
4492654012fSReza Sabdar 	 * Just return if we are waiting for the NDMP client to
4502654012fSReza Sabdar 	 * complete the seek.
4512654012fSReza Sabdar 	 */
4522654012fSReza Sabdar 	if (err == 1)
4532654012fSReza Sabdar 		return;
4542654012fSReza Sabdar 
4552654012fSReza Sabdar 	/*
4562654012fSReza Sabdar 	 * Start the mover for restore in the 3-way backups.
4572654012fSReza Sabdar 	 */
4582654012fSReza Sabdar 	if (start_mover_for_restore(session) < 0)
4592654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4602654012fSReza Sabdar }
4612654012fSReza Sabdar 
4622654012fSReza Sabdar 
4632654012fSReza Sabdar /*
4642654012fSReza Sabdar  * ndmpd_mover_close_v2
4652654012fSReza Sabdar  *
4662654012fSReza Sabdar  * This handler handles mover_close requests.
4672654012fSReza Sabdar  *
4682654012fSReza Sabdar  * Parameters:
4692654012fSReza Sabdar  *   connection (input) - connection handle.
4702654012fSReza Sabdar  *   body       (input) - request message body.
4712654012fSReza Sabdar  *
4722654012fSReza Sabdar  * Returns:
4732654012fSReza Sabdar  *   void
4742654012fSReza Sabdar  */
4752654012fSReza Sabdar /*ARGSUSED*/
4762654012fSReza Sabdar void
4772654012fSReza Sabdar ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
4782654012fSReza Sabdar {
4792654012fSReza Sabdar 	ndmp_mover_close_reply reply;
4802654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
4812654012fSReza Sabdar 
4822654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
4832654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
4842654012fSReza Sabdar 
4852654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
4862654012fSReza Sabdar 		ndmp_send_reply(connection, &reply,
4872654012fSReza Sabdar 		    "sending mover_close reply");
4882654012fSReza Sabdar 		return;
4892654012fSReza Sabdar 	}
4902654012fSReza Sabdar 	free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
4912654012fSReza Sabdar 
4922654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
4932654012fSReza Sabdar 	ndmp_send_reply(connection, &reply, "sending mover_close reply");
4942654012fSReza Sabdar 
4952654012fSReza Sabdar 	ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
4962654012fSReza Sabdar }
4972654012fSReza Sabdar 
4982654012fSReza Sabdar 
4992654012fSReza Sabdar /*
5002654012fSReza Sabdar  * ndmpd_mover_set_record_size_v2
5012654012fSReza Sabdar  *
5022654012fSReza Sabdar  * This handler handles mover_set_record_size requests.
5032654012fSReza Sabdar  *
5042654012fSReza Sabdar  * Parameters:
5052654012fSReza Sabdar  *   connection (input) - connection handle.
5062654012fSReza Sabdar  *   body       (input) - request message body.
5072654012fSReza Sabdar  *
5082654012fSReza Sabdar  * Returns:
5092654012fSReza Sabdar  *   void
5102654012fSReza Sabdar  */
5112654012fSReza Sabdar void
5122654012fSReza Sabdar ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
5132654012fSReza Sabdar {
5142654012fSReza Sabdar 	ndmp_mover_set_record_size_request *request;
5152654012fSReza Sabdar 	ndmp_mover_set_record_size_reply reply;
5162654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
5172654012fSReza Sabdar 
5182654012fSReza Sabdar 	request = (ndmp_mover_set_record_size_request *) body;
5192654012fSReza Sabdar 
5202654012fSReza Sabdar 	session->ns_mover.md_record_size = request->len;
5212654012fSReza Sabdar 	session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
5222654012fSReza Sabdar 	    request->len);
5232654012fSReza Sabdar 
5242654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
5252654012fSReza Sabdar 	ndmp_send_reply(connection, &reply,
5262654012fSReza Sabdar 	    "sending mover_set_record_size reply");
5272654012fSReza Sabdar }
5282654012fSReza Sabdar 
5292654012fSReza Sabdar 
5302654012fSReza Sabdar /*
5312654012fSReza Sabdar  * ************************************************************************
5322654012fSReza Sabdar  * NDMP V3 HANDLERS
5332654012fSReza Sabdar  * ************************************************************************
5342654012fSReza Sabdar  */
5352654012fSReza Sabdar 
5362654012fSReza Sabdar /*
5372654012fSReza Sabdar  * ndmpd_mover_get_state_v3
5382654012fSReza Sabdar  *
5392654012fSReza Sabdar  * This handler handles the ndmp_mover_get_state_request.
5402654012fSReza Sabdar  * Status information for the mover state machine is returned.
5412654012fSReza Sabdar  *
5422654012fSReza Sabdar  * Parameters:
5432654012fSReza Sabdar  *   connection (input) - connection handle.
5442654012fSReza Sabdar  *   body       (input) - request message body.
5452654012fSReza Sabdar  *
5462654012fSReza Sabdar  * Returns:
5472654012fSReza Sabdar  *   void
5482654012fSReza Sabdar  */
5492654012fSReza Sabdar /*ARGSUSED*/
5502654012fSReza Sabdar void
5512654012fSReza Sabdar ndmpd_mover_get_state_v3(ndmp_connection_t *connection, void *body)
5522654012fSReza Sabdar {
5532654012fSReza Sabdar 	ndmp_mover_get_state_reply_v3 reply;
5542654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
5552654012fSReza Sabdar 
5562654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
5572654012fSReza Sabdar 
5582654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
5592654012fSReza Sabdar 	reply.state = session->ns_mover.md_state;
5602654012fSReza Sabdar 	reply.pause_reason = session->ns_mover.md_pause_reason;
5612654012fSReza Sabdar 	reply.halt_reason = session->ns_mover.md_halt_reason;
5622654012fSReza Sabdar 	reply.record_size = session->ns_mover.md_record_size;
5632654012fSReza Sabdar 	reply.record_num = session->ns_mover.md_record_num;
5642654012fSReza Sabdar 	reply.data_written =
5652654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_data_written);
5662654012fSReza Sabdar 	reply.seek_position =
5672654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_seek_position);
5682654012fSReza Sabdar 	reply.bytes_left_to_read =
5692654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
5702654012fSReza Sabdar 	reply.window_offset =
5712654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_offset);
5722654012fSReza Sabdar 	reply.window_length =
5732654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_length);
5742654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
5752654012fSReza Sabdar 		ndmp_copy_addr_v3(&reply.data_connection_addr,
5762654012fSReza Sabdar 		    &session->ns_mover.md_data_addr);
5772654012fSReza Sabdar 
5782654012fSReza Sabdar 	ndmp_send_reply(connection, &reply,
5792654012fSReza Sabdar 	    "sending ndmp_mover_get_state reply");
5802654012fSReza Sabdar }
5812654012fSReza Sabdar 
5822654012fSReza Sabdar 
5832654012fSReza Sabdar /*
5842654012fSReza Sabdar  * ndmpd_mover_listen_v3
5852654012fSReza Sabdar  *
5862654012fSReza Sabdar  * This handler handles ndmp_mover_listen_requests.
5872654012fSReza Sabdar  * A TCP/IP socket is created that is used to listen for
5882654012fSReza Sabdar  * and accept data connections initiated by a remote
5892654012fSReza Sabdar  * data server.
5902654012fSReza Sabdar  *
5912654012fSReza Sabdar  * Parameters:
5922654012fSReza Sabdar  *   connection (input) - connection handle.
5932654012fSReza Sabdar  *   body       (input) - request message body.
5942654012fSReza Sabdar  *
5952654012fSReza Sabdar  * Returns:
5962654012fSReza Sabdar  *   void
5972654012fSReza Sabdar  */
5982654012fSReza Sabdar void
5992654012fSReza Sabdar ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
6002654012fSReza Sabdar {
6012654012fSReza Sabdar 	ndmp_mover_listen_request_v3 *request;
6022654012fSReza Sabdar 	ndmp_mover_listen_reply_v3 reply;
6032654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
6042654012fSReza Sabdar 	ulong_t addr;
6052654012fSReza Sabdar 	ushort_t port;
6062654012fSReza Sabdar 
6072654012fSReza Sabdar 	request = (ndmp_mover_listen_request_v3 *)body;
6082654012fSReza Sabdar 
6092654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
6102654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
6112654012fSReza Sabdar 
6122654012fSReza Sabdar 	if (request->mode != NDMP_MOVER_MODE_READ &&
6132654012fSReza Sabdar 	    request->mode != NDMP_MOVER_MODE_WRITE) {
6142654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6152654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
6162654012fSReza Sabdar 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
6172654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6182654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
6192654012fSReza Sabdar 		    request->addr_type);
6202654012fSReza Sabdar 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
6212654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
6222654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
6232654012fSReza Sabdar 		    "Invalid mover state to process listen request");
6242654012fSReza Sabdar 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
6252654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
6262654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
6272654012fSReza Sabdar 		    "Invalid data state to process listen request");
6282654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
6292654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
6302654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No tape device open");
6312654012fSReza Sabdar 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
6322654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
6332654012fSReza Sabdar 		reply.error = NDMP_PERMISSION_ERR;
6342654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
6352654012fSReza Sabdar 	}
6362654012fSReza Sabdar 
6372654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
6382654012fSReza Sabdar 		ndmp_send_reply(connection, &reply,
6392654012fSReza Sabdar 		    "error sending ndmp_mover_listen reply");
6402654012fSReza Sabdar 		return;
6412654012fSReza Sabdar 	}
6422654012fSReza Sabdar 
6432654012fSReza Sabdar 	switch (request->addr_type) {
6442654012fSReza Sabdar 	case NDMP_ADDR_LOCAL:
6452654012fSReza Sabdar 		reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
6462654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
6472654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
6482654012fSReza Sabdar 		break;
6492654012fSReza Sabdar 	case NDMP_ADDR_TCP:
6502654012fSReza Sabdar 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
6512654012fSReza Sabdar 			reply.error = NDMP_IO_ERR;
6522654012fSReza Sabdar 			break;
6532654012fSReza Sabdar 		}
6542654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
6552654012fSReza Sabdar 		reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
6562654012fSReza Sabdar 		reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
6572654012fSReza Sabdar 		reply.data_connection_addr.tcp_port_v3 = htons(port);
6582654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
6592654012fSReza Sabdar 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
6602654012fSReza Sabdar 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
6612654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
6622654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
6632654012fSReza Sabdar 		break;
6642654012fSReza Sabdar 	default:
6652654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
6662654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
6672654012fSReza Sabdar 		    request->addr_type);
6682654012fSReza Sabdar 	}
6692654012fSReza Sabdar 
6702654012fSReza Sabdar 	if (reply.error == NDMP_NO_ERR) {
6712654012fSReza Sabdar 		session->ns_mover.md_mode = request->mode;
6722654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
6732654012fSReza Sabdar 	}
6742654012fSReza Sabdar 
6752654012fSReza Sabdar 	ndmp_send_reply(connection, &reply,
6762654012fSReza Sabdar 	    "error sending ndmp_mover_listen reply");
6772654012fSReza Sabdar }
6782654012fSReza Sabdar 
6792654012fSReza Sabdar 
6802654012fSReza Sabdar /*
6812654012fSReza Sabdar  * ndmpd_mover_continue_v3
6822654012fSReza Sabdar  *
6832654012fSReza Sabdar  * This handler handles ndmp_mover_continue_requests.
6842654012fSReza Sabdar  *
6852654012fSReza Sabdar  * Parameters:
6862654012fSReza Sabdar  *   connection (input) - connection handle.
6872654012fSReza Sabdar  *   body       (input) - request message body.
6882654012fSReza Sabdar  *
6892654012fSReza Sabdar  * Returns:
6902654012fSReza Sabdar  *   void
6912654012fSReza Sabdar  */
6922654012fSReza Sabdar /*ARGSUSED*/
6932654012fSReza Sabdar void
6942654012fSReza Sabdar ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
6952654012fSReza Sabdar {
6962654012fSReza Sabdar 	ndmp_mover_continue_reply reply;
6972654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
698a23888a3SJan Kryl 	ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
6992654012fSReza Sabdar 	int ret;
7002654012fSReza Sabdar 
7012654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
7022654012fSReza Sabdar 
7032654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
7042654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
7052654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
7062654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
7072654012fSReza Sabdar 		    "sending mover_continue reply");
7082654012fSReza Sabdar 		return;
7092654012fSReza Sabdar 	}
7102654012fSReza Sabdar 
7112654012fSReza Sabdar 	if (session->ns_protocol_version == NDMPV4 &&
7122654012fSReza Sabdar 	    !session->ns_mover.md_pre_cond) {
7132654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Precondition check");
7142654012fSReza Sabdar 		reply.error = NDMP_PRECONDITION_ERR;
7152654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
7162654012fSReza Sabdar 		    "sending mover_continue reply");
7172654012fSReza Sabdar 		return;
7182654012fSReza Sabdar 	}
7192654012fSReza Sabdar 	/*
7202654012fSReza Sabdar 	 * Restore the file handler if the mover is remote to the data
7212654012fSReza Sabdar 	 * server and the handler was removed pending the continuation of a
7222654012fSReza Sabdar 	 * seek request. The handler is removed in mover_data_write().
7232654012fSReza Sabdar 	 */
7242654012fSReza Sabdar 	if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
7252654012fSReza Sabdar 	    session->ns_mover.md_sock != -1) {
7262654012fSReza Sabdar 		/*
7272654012fSReza Sabdar 		 * If we are here, it means that we needed DMA interference
7282654012fSReza Sabdar 		 * for seek. We should be on the right window, so we do not
7292654012fSReza Sabdar 		 * need the DMA interference anymore.
7302654012fSReza Sabdar 		 * We do another seek inside the Window to move to the
7312654012fSReza Sabdar 		 * exact position on the tape.
7322654012fSReza Sabdar 		 * If the resore is running without DAR the pause reason should
7332654012fSReza Sabdar 		 * not be seek.
7342654012fSReza Sabdar 		 */
7352654012fSReza Sabdar 		ret = ndmpd_mover_seek(session,
7362654012fSReza Sabdar 		    session->ns_mover.md_seek_position,
7372654012fSReza Sabdar 		    session->ns_mover.md_bytes_left_to_read);
7382654012fSReza Sabdar 		if (ret < 0) {
7392654012fSReza Sabdar 			ndmpd_mover_error(session,
7402654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
7412654012fSReza Sabdar 			return;
7422654012fSReza Sabdar 		}
7432654012fSReza Sabdar 
7442654012fSReza Sabdar 		if (!ret) {
7452654012fSReza Sabdar 			if (ndmpd_add_file_handler(session, (void*) session,
7462654012fSReza Sabdar 			    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
7472654012fSReza Sabdar 			    HC_MOVER, mover_data_write_v3) < 0)
7482654012fSReza Sabdar 				ndmpd_mover_error(session,
7492654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
7502654012fSReza Sabdar 		} else {
7512654012fSReza Sabdar 			/*
7522654012fSReza Sabdar 			 * This should not happen because we should be in the
7532654012fSReza Sabdar 			 * right window. This means that DMA does not follow
7542654012fSReza Sabdar 			 * the V3 spec.
7552654012fSReza Sabdar 			 */
7562654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "DMA Error.");
7572654012fSReza Sabdar 			ndmpd_mover_error(session,
7582654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
7592654012fSReza Sabdar 			return;
7602654012fSReza Sabdar 		}
7612654012fSReza Sabdar 	}
7622654012fSReza Sabdar 
763a23888a3SJan Kryl 	(void) mutex_lock(&nlp->nlp_mtx);
7642654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
7652654012fSReza Sabdar 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
766*f5b1cef2SJan Kryl 	/* The tape has been likely exchanged, reset tape block counter */
767*f5b1cef2SJan Kryl 	session->ns_tape.td_record_count = 0;
768a23888a3SJan Kryl 	(void) cond_broadcast(&nlp->nlp_cv);
769a23888a3SJan Kryl 	(void) mutex_unlock(&nlp->nlp_mtx);
7702654012fSReza Sabdar 
7712654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
7722654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
7732654012fSReza Sabdar 	    "sending mover_continue reply");
7742654012fSReza Sabdar }
7752654012fSReza Sabdar 
7762654012fSReza Sabdar 
7772654012fSReza Sabdar /*
7782654012fSReza Sabdar  * ndmpd_mover_abort_v3
7792654012fSReza Sabdar  *
7802654012fSReza Sabdar  * This handler handles mover_abort requests.
7812654012fSReza Sabdar  *
7822654012fSReza Sabdar  * Parameters:
7832654012fSReza Sabdar  *   connection (input) - connection handle.
7842654012fSReza Sabdar  *   body       (input) - request message body.
7852654012fSReza Sabdar  *
7862654012fSReza Sabdar  * Returns:
7872654012fSReza Sabdar  *   void
7882654012fSReza Sabdar  */
7892654012fSReza Sabdar /*ARGSUSED*/
7902654012fSReza Sabdar void
7912654012fSReza Sabdar ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
7922654012fSReza Sabdar {
7932654012fSReza Sabdar 	ndmp_mover_abort_reply reply;
7942654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
7952654012fSReza Sabdar 
7962654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
7972654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
7982654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
7992654012fSReza Sabdar 
8002654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
8012654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
8022654012fSReza Sabdar 		    "sending mover_abort reply");
8032654012fSReza Sabdar 		return;
8042654012fSReza Sabdar 	}
8052654012fSReza Sabdar 
8062654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
8072654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
8082654012fSReza Sabdar 	    "sending mover_abort reply");
8092654012fSReza Sabdar 
8102654012fSReza Sabdar 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
8112654012fSReza Sabdar }
8122654012fSReza Sabdar 
8132654012fSReza Sabdar 
8142654012fSReza Sabdar /*
8152654012fSReza Sabdar  * ndmpd_mover_set_window_v3
8162654012fSReza Sabdar  *
8172654012fSReza Sabdar  * This handler handles mover_set_window requests.
8182654012fSReza Sabdar  *
8192654012fSReza Sabdar  *
8202654012fSReza Sabdar  * Parameters:
8212654012fSReza Sabdar  *   connection (input) - connection handle.
8222654012fSReza Sabdar  *   body       (input) - request message body.
8232654012fSReza Sabdar  *
8242654012fSReza Sabdar  * Returns:
8252654012fSReza Sabdar  *   void
8262654012fSReza Sabdar  */
8272654012fSReza Sabdar void
8282654012fSReza Sabdar ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
8292654012fSReza Sabdar {
8302654012fSReza Sabdar 	ndmp_mover_set_window_request *request;
8312654012fSReza Sabdar 	ndmp_mover_set_window_reply reply;
8322654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
8332654012fSReza Sabdar 
8342654012fSReza Sabdar 	request = (ndmp_mover_set_window_request *) body;
8352654012fSReza Sabdar 
8362654012fSReza Sabdar 	/*
8372654012fSReza Sabdar 	 * Note: The spec says that the window can be set only in the listen
8382654012fSReza Sabdar 	 * and paused states.  We let this happen when mover is in the idle
8392654012fSReza Sabdar 	 * state as well.  I can't rememebr which NDMP client (net_backup 4.5
8402654012fSReza Sabdar 	 * or net_worker 6.1.1) forced us to do this!
8412654012fSReza Sabdar 	 */
8422654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
8432654012fSReza Sabdar 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
8442654012fSReza Sabdar 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
8452654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
8462654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
8472654012fSReza Sabdar 		    session->ns_mover.md_state);
8482654012fSReza Sabdar 	} else if (session->ns_mover.md_record_size == 0) {
8492654012fSReza Sabdar 		if (session->ns_protocol_version == NDMPV4)
8502654012fSReza Sabdar 			reply.error = NDMP_PRECONDITION_ERR;
8512654012fSReza Sabdar 		else
8522654012fSReza Sabdar 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
8532654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
8542654012fSReza Sabdar 	} else
8552654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
8562654012fSReza Sabdar 
8572654012fSReza Sabdar 	if (quad_to_long_long(request->length) == 0) {
8582654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
8592654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
8602654012fSReza Sabdar 		    quad_to_long_long(request->length));
8612654012fSReza Sabdar 	}
8622654012fSReza Sabdar 
8632654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
8642654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
8652654012fSReza Sabdar 		    "sending mover_set_window_v3 reply");
8662654012fSReza Sabdar 		return;
8672654012fSReza Sabdar 	}
8682654012fSReza Sabdar 
8692654012fSReza Sabdar 	session->ns_mover.md_pre_cond = TRUE;
8702654012fSReza Sabdar 	session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
8712654012fSReza Sabdar 	session->ns_mover.md_window_length = quad_to_long_long(request->length);
8722654012fSReza Sabdar 
8732654012fSReza Sabdar 	/*
8742654012fSReza Sabdar 	 * We have to update the position for DAR. DAR needs this
8752654012fSReza Sabdar 	 * information to position to the right index on tape,
8762654012fSReza Sabdar 	 * especially when we span the tapes.
8772654012fSReza Sabdar 	 */
8782654012fSReza Sabdar #ifdef	NO_POSITION_CHANGE
8792654012fSReza Sabdar 	/*
8802654012fSReza Sabdar 	 * Do not change the mover position if we are reading from
8812654012fSReza Sabdar 	 * the tape.  In this way, we can use the position+window_length
8822654012fSReza Sabdar 	 * to know how much we can write to a tape before pausing with
8832654012fSReza Sabdar 	 * EOW reason.
8842654012fSReza Sabdar 	 */
8852654012fSReza Sabdar 	if (session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE)
8862654012fSReza Sabdar #endif	/* NO_POSITION_CHANGE */
8872654012fSReza Sabdar 		session->ns_mover.md_position =
8882654012fSReza Sabdar 		    session->ns_mover.md_window_offset;
8892654012fSReza Sabdar 
8902654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
8912654012fSReza Sabdar 	    "sending mover_set_window_v3 reply");
8922654012fSReza Sabdar }
8932654012fSReza Sabdar 
8942654012fSReza Sabdar 
8952654012fSReza Sabdar /*
8962654012fSReza Sabdar  * ndmpd_mover_read_v3
8972654012fSReza Sabdar  *
8982654012fSReza Sabdar  * This handler handles ndmp_mover_read_requests.
8992654012fSReza Sabdar  * If the requested offset is outside of the current window, the mover
9002654012fSReza Sabdar  * is paused and a notify_mover_paused request is sent notifying the
9012654012fSReza Sabdar  * client that a seek is required. If the requested offest is within
9022654012fSReza Sabdar  * the window but not within the current record, then the tape is
9032654012fSReza Sabdar  * positioned to the record containing the requested offest. The requested
9042654012fSReza Sabdar  * amount of data is then read from the tape device and written to the
9052654012fSReza Sabdar  * data connection.
9062654012fSReza Sabdar  *
9072654012fSReza Sabdar  * Parameters:
9082654012fSReza Sabdar  *   connection (input) - connection handle.
9092654012fSReza Sabdar  *   body       (input) - request message body.
9102654012fSReza Sabdar  *
9112654012fSReza Sabdar  * Returns:
9122654012fSReza Sabdar  *   void
9132654012fSReza Sabdar  */
9142654012fSReza Sabdar void
9152654012fSReza Sabdar ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
9162654012fSReza Sabdar {
9172654012fSReza Sabdar 	ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
9182654012fSReza Sabdar 	ndmp_mover_read_reply reply;
9192654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
9202654012fSReza Sabdar 	int err;
9212654012fSReza Sabdar 
9222654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
9232654012fSReza Sabdar 
9242654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
9252654012fSReza Sabdar 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
9262654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
9272654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state");
9282654012fSReza Sabdar 	} else if (session->ns_mover.md_bytes_left_to_read != 0) {
9292654012fSReza Sabdar 		reply.error = NDMP_READ_IN_PROGRESS_ERR;
9302654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "In progress");
9312654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
9322654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
9332654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
9342654012fSReza Sabdar 	} else if (quad_to_long_long(request->length) == 0 ||
9352654012fSReza Sabdar 	    (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
9362654012fSReza Sabdar 	    quad_to_long_long(request->offset) != 0)) {
9372654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
9382654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Illegal args");
9392654012fSReza Sabdar 	} else {
9402654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
9412654012fSReza Sabdar 	}
9422654012fSReza Sabdar 
9432654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
9442654012fSReza Sabdar 	    "sending ndmp_mover_read_reply");
9452654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR)
9462654012fSReza Sabdar 		return;
9472654012fSReza Sabdar 
9482654012fSReza Sabdar 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
9492654012fSReza Sabdar 	    quad_to_long_long(request->length));
9502654012fSReza Sabdar 	if (err < 0) {
9512654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
9522654012fSReza Sabdar 		return;
9532654012fSReza Sabdar 	}
9542654012fSReza Sabdar 
9552654012fSReza Sabdar 	/*
9562654012fSReza Sabdar 	 * Just return if we are waiting for the DMA to complete the seek.
9572654012fSReza Sabdar 	 */
9582654012fSReza Sabdar 	if (err == 1)
9592654012fSReza Sabdar 		return;
9602654012fSReza Sabdar 
9612654012fSReza Sabdar 	/*
9622654012fSReza Sabdar 	 * Setup a handler function that will be called when
9632654012fSReza Sabdar 	 * data can be written to the data connection without blocking.
9642654012fSReza Sabdar 	 */
9652654012fSReza Sabdar 	if (ndmpd_add_file_handler(session, (void*)session,
9662654012fSReza Sabdar 	    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE, HC_MOVER,
9672654012fSReza Sabdar 	    mover_data_write_v3) < 0) {
9682654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
9692654012fSReza Sabdar 		return;
9702654012fSReza Sabdar 	}
9712654012fSReza Sabdar }
9722654012fSReza Sabdar 
9732654012fSReza Sabdar 
9742654012fSReza Sabdar /*
9752654012fSReza Sabdar  * ndmpd_mover_set_record_size_v3
9762654012fSReza Sabdar  *
9772654012fSReza Sabdar  * This handler handles mover_set_record_size requests.
9782654012fSReza Sabdar  *
9792654012fSReza Sabdar  * Parameters:
9802654012fSReza Sabdar  *   connection (input) - connection handle.
9812654012fSReza Sabdar  *   body       (input) - request message body.
9822654012fSReza Sabdar  *
9832654012fSReza Sabdar  * Returns:
9842654012fSReza Sabdar  *   void
9852654012fSReza Sabdar  */
9862654012fSReza Sabdar void
9872654012fSReza Sabdar ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
9882654012fSReza Sabdar {
9892654012fSReza Sabdar 	ndmp_mover_set_record_size_request *request;
9902654012fSReza Sabdar 	ndmp_mover_set_record_size_reply reply;
9912654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
9922654012fSReza Sabdar 	char *cp;
9932654012fSReza Sabdar 
9942654012fSReza Sabdar 	request = (ndmp_mover_set_record_size_request *) body;
9952654012fSReza Sabdar 
9962654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
9972654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
9982654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mover state %d",
9992654012fSReza Sabdar 		    session->ns_mover.md_state);
10002654012fSReza Sabdar 	} else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
10012654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10022654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
10032654012fSReza Sabdar 		    "Invalid argument %d, should be > 0 and <= %d",
10042654012fSReza Sabdar 		    request->len, ndmp_max_mover_recsize);
10052654012fSReza Sabdar 	} else if (request->len == session->ns_mover.md_record_size)
10062654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
10072654012fSReza Sabdar 	else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
10082654012fSReza Sabdar 		reply.error = NDMP_NO_MEM_ERR;
10092654012fSReza Sabdar 	} else {
10102654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
10112654012fSReza Sabdar 		session->ns_mover.md_buf = cp;
10122654012fSReza Sabdar 		session->ns_mover.md_record_size = request->len;
10132654012fSReza Sabdar 		session->ns_mover.md_window_offset = 0;
10142654012fSReza Sabdar 		session->ns_mover.md_window_length = 0;
10152654012fSReza Sabdar 	}
10162654012fSReza Sabdar 
10172654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
10182654012fSReza Sabdar 	    "sending mover_set_record_size reply");
10192654012fSReza Sabdar }
10202654012fSReza Sabdar 
10212654012fSReza Sabdar 
10222654012fSReza Sabdar /*
10232654012fSReza Sabdar  * ndmpd_mover_connect_v3
10242654012fSReza Sabdar  *   Request handler. Connects the mover to either a local
10252654012fSReza Sabdar  *   or remote data server.
10262654012fSReza Sabdar  *
10272654012fSReza Sabdar  * Parameters:
10282654012fSReza Sabdar  *   connection (input) - connection handle.
10292654012fSReza Sabdar  *   body       (input) - request message body.
10302654012fSReza Sabdar  *
10312654012fSReza Sabdar  * Returns:
10322654012fSReza Sabdar  *   void
10332654012fSReza Sabdar  */
10342654012fSReza Sabdar void
10352654012fSReza Sabdar ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
10362654012fSReza Sabdar {
10372654012fSReza Sabdar 	ndmp_mover_connect_request_v3 *request;
10382654012fSReza Sabdar 	ndmp_mover_connect_reply_v3 reply;
10392654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
10402654012fSReza Sabdar 
10412654012fSReza Sabdar 	request = (ndmp_mover_connect_request_v3*)body;
10422654012fSReza Sabdar 
10432654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
10442654012fSReza Sabdar 
10452654012fSReza Sabdar 	if (request->mode != NDMP_MOVER_MODE_READ &&
10462654012fSReza Sabdar 	    request->mode != NDMP_MOVER_MODE_WRITE) {
10472654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10482654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
10492654012fSReza Sabdar 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
10502654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10512654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
10522654012fSReza Sabdar 		    request->addr.addr_type);
10532654012fSReza Sabdar 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
10542654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
10552654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
10562654012fSReza Sabdar 		    session->ns_mover.md_state);
10572654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
10582654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
10592654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No tape device open");
10602654012fSReza Sabdar 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
10612654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
10622654012fSReza Sabdar 		reply.error = NDMP_WRITE_PROTECT_ERR;
10632654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
10642654012fSReza Sabdar 	} else
10652654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
10662654012fSReza Sabdar 
10672654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
10682654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
10692654012fSReza Sabdar 		    "sending ndmp_mover_connect reply");
10702654012fSReza Sabdar 		return;
10712654012fSReza Sabdar 	}
10722654012fSReza Sabdar 
10732654012fSReza Sabdar 	switch (request->addr.addr_type) {
10742654012fSReza Sabdar 	case NDMP_ADDR_LOCAL:
10752654012fSReza Sabdar 		/*
10762654012fSReza Sabdar 		 * Verify that the data server is listening for a
10772654012fSReza Sabdar 		 * local connection.
10782654012fSReza Sabdar 		 */
10792654012fSReza Sabdar 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
10802654012fSReza Sabdar 		    session->ns_data.dd_listen_sock != -1) {
10812654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
10822654012fSReza Sabdar 			    "Data server is not in local listen state");
10832654012fSReza Sabdar 			reply.error = NDMP_ILLEGAL_STATE_ERR;
10842654012fSReza Sabdar 		} else
10852654012fSReza Sabdar 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
10862654012fSReza Sabdar 		break;
10872654012fSReza Sabdar 
10882654012fSReza Sabdar 	case NDMP_ADDR_TCP:
108997f7c475SJan Kryl 		reply.error = mover_connect_sock(session, request->mode,
10902654012fSReza Sabdar 		    request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
10912654012fSReza Sabdar 		break;
10922654012fSReza Sabdar 
10932654012fSReza Sabdar 	default:
10942654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
10952654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
10962654012fSReza Sabdar 		    request->addr.addr_type);
10972654012fSReza Sabdar 	}
10982654012fSReza Sabdar 
10992654012fSReza Sabdar 	if (reply.error == NDMP_NO_ERR) {
11002654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type =
11012654012fSReza Sabdar 		    request->addr.addr_type;
11022654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
11032654012fSReza Sabdar 		session->ns_mover.md_mode = request->mode;
11042654012fSReza Sabdar 	}
11052654012fSReza Sabdar 
11062654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
11072654012fSReza Sabdar 	    "sending ndmp_mover_connect reply");
11082654012fSReza Sabdar }
11092654012fSReza Sabdar 
11102654012fSReza Sabdar 
11112654012fSReza Sabdar /*
11122654012fSReza Sabdar  * ************************************************************************
11132654012fSReza Sabdar  * NDMP V4 HANDLERS
11142654012fSReza Sabdar  * ************************************************************************
11152654012fSReza Sabdar  */
11162654012fSReza Sabdar 
11172654012fSReza Sabdar /*
11182654012fSReza Sabdar  * ndmpd_mover_get_state_v4
11192654012fSReza Sabdar  *
11202654012fSReza Sabdar  * This handler handles the ndmp_mover_get_state_request.
11212654012fSReza Sabdar  * Status information for the mover state machine is returned.
11222654012fSReza Sabdar  *
11232654012fSReza Sabdar  * Parameters:
11242654012fSReza Sabdar  *   connection (input) - connection handle.
11252654012fSReza Sabdar  *   body       (input) - request message body.
11262654012fSReza Sabdar  *
11272654012fSReza Sabdar  * Returns:
11282654012fSReza Sabdar  *   void
11292654012fSReza Sabdar  */
11302654012fSReza Sabdar /*ARGSUSED*/
11312654012fSReza Sabdar void
11322654012fSReza Sabdar ndmpd_mover_get_state_v4(ndmp_connection_t *connection, void *body)
11332654012fSReza Sabdar {
11342654012fSReza Sabdar 	ndmp_mover_get_state_reply_v4 reply;
11352654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
11362654012fSReza Sabdar 
11372654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
11382654012fSReza Sabdar 
11392654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
11402654012fSReza Sabdar 	reply.state = session->ns_mover.md_state;
11412654012fSReza Sabdar 	reply.mode = session->ns_mover.md_mode;
11422654012fSReza Sabdar 	reply.pause_reason = session->ns_mover.md_pause_reason;
11432654012fSReza Sabdar 	reply.halt_reason = session->ns_mover.md_halt_reason;
11442654012fSReza Sabdar 	reply.record_size = session->ns_mover.md_record_size;
11452654012fSReza Sabdar 	reply.record_num = session->ns_mover.md_record_num;
11462654012fSReza Sabdar 	reply.bytes_moved =
11472654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_data_written);
11482654012fSReza Sabdar 	reply.seek_position =
11492654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_seek_position);
11502654012fSReza Sabdar 	reply.bytes_left_to_read =
11512654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
11522654012fSReza Sabdar 	reply.window_offset =
11532654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_offset);
11542654012fSReza Sabdar 	reply.window_length =
11552654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_window_length);
11562654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
11572654012fSReza Sabdar 		ndmp_copy_addr_v4(&reply.data_connection_addr,
11582654012fSReza Sabdar 		    &session->ns_mover.md_data_addr_v4);
11592654012fSReza Sabdar 
11602654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
11612654012fSReza Sabdar 	    "sending ndmp_mover_get_state reply");
11622654012fSReza Sabdar 	free(reply.data_connection_addr.tcp_addr_v4);
11632654012fSReza Sabdar }
11642654012fSReza Sabdar 
11652654012fSReza Sabdar 
11662654012fSReza Sabdar /*
11672654012fSReza Sabdar  * ndmpd_mover_listen_v4
11682654012fSReza Sabdar  *
11692654012fSReza Sabdar  * This handler handles ndmp_mover_listen_requests.
11702654012fSReza Sabdar  * A TCP/IP socket is created that is used to listen for
11712654012fSReza Sabdar  * and accept data connections initiated by a remote
11722654012fSReza Sabdar  * data server.
11732654012fSReza Sabdar  *
11742654012fSReza Sabdar  * Parameters:
11752654012fSReza Sabdar  *   connection (input) - connection handle.
11762654012fSReza Sabdar  *   body       (input) - request message body.
11772654012fSReza Sabdar  *
11782654012fSReza Sabdar  * Returns:
11792654012fSReza Sabdar  *   void
11802654012fSReza Sabdar  */
11812654012fSReza Sabdar void
11822654012fSReza Sabdar ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
11832654012fSReza Sabdar {
11842654012fSReza Sabdar 	ndmp_mover_listen_request_v4 *request;
11852654012fSReza Sabdar 
11862654012fSReza Sabdar 	ndmp_mover_listen_reply_v4 reply;
11872654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
11882654012fSReza Sabdar 	ulong_t addr;
11892654012fSReza Sabdar 	ushort_t port;
11902654012fSReza Sabdar 
11912654012fSReza Sabdar 	request = (ndmp_mover_listen_request_v4 *)body;
11922654012fSReza Sabdar 
11932654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
11942654012fSReza Sabdar 	reply.error = NDMP_NO_ERR;
11952654012fSReza Sabdar 
11962654012fSReza Sabdar 	if (request->mode != NDMP_MOVER_MODE_READ &&
11972654012fSReza Sabdar 	    request->mode != NDMP_MOVER_MODE_WRITE) {
11982654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
11992654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
12002654012fSReza Sabdar 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
12012654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
12022654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
12032654012fSReza Sabdar 		    request->addr_type);
12042654012fSReza Sabdar 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
12052654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
12062654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
12072654012fSReza Sabdar 		    "Invalid mover state to process listen request");
12082654012fSReza Sabdar 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
12092654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
12102654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
12112654012fSReza Sabdar 		    "Invalid data state to process listen request");
12122654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
12132654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
12142654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No tape device open");
12152654012fSReza Sabdar 	} else if (session->ns_mover.md_record_size == 0) {
12162654012fSReza Sabdar 		reply.error = NDMP_PRECONDITION_ERR;
12172654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
12182654012fSReza Sabdar 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
12192654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
12202654012fSReza Sabdar 		reply.error = NDMP_PERMISSION_ERR;
12212654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
12222654012fSReza Sabdar 	}
12232654012fSReza Sabdar 
12242654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
12252654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
12262654012fSReza Sabdar 		    "error sending ndmp_mover_listen reply");
12272654012fSReza Sabdar 		return;
12282654012fSReza Sabdar 	}
12292654012fSReza Sabdar 
12302654012fSReza Sabdar 	switch (request->addr_type) {
12312654012fSReza Sabdar 	case NDMP_ADDR_LOCAL:
12322654012fSReza Sabdar 		reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
12332654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
12342654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
12352654012fSReza Sabdar 		break;
12362654012fSReza Sabdar 	case NDMP_ADDR_TCP:
12372654012fSReza Sabdar 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
12382654012fSReza Sabdar 			reply.error = NDMP_IO_ERR;
12392654012fSReza Sabdar 			break;
12402654012fSReza Sabdar 		}
12412654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
12422654012fSReza Sabdar 
12432654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
12442654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
12452654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
12462654012fSReza Sabdar 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
12472654012fSReza Sabdar 
12482654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
12492654012fSReza Sabdar 		session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
12502654012fSReza Sabdar 
12512654012fSReza Sabdar 		ndmp_copy_addr_v4(&reply.connect_addr,
12522654012fSReza Sabdar 		    &session->ns_mover.md_data_addr_v4);
12532654012fSReza Sabdar 
12542654012fSReza Sabdar 		/* For compatibility with V3 */
12552654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
12562654012fSReza Sabdar 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
12572654012fSReza Sabdar 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
12582654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
12592654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
12602654012fSReza Sabdar 		break;
12612654012fSReza Sabdar 	default:
12622654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
12632654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
12642654012fSReza Sabdar 		    request->addr_type);
12652654012fSReza Sabdar 	}
12662654012fSReza Sabdar 
12672654012fSReza Sabdar 	if (reply.error == NDMP_NO_ERR) {
12682654012fSReza Sabdar 		session->ns_mover.md_mode = request->mode;
12692654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
12702654012fSReza Sabdar 	}
12712654012fSReza Sabdar 
12722654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
12732654012fSReza Sabdar 	    "error sending ndmp_mover_listen reply");
12742654012fSReza Sabdar 	free(reply.connect_addr.tcp_addr_v4);
12752654012fSReza Sabdar }
12762654012fSReza Sabdar 
12772654012fSReza Sabdar /*
12782654012fSReza Sabdar  * ndmpd_mover_connect_v4
12792654012fSReza Sabdar  *   Request handler. Connects the mover to either a local
12802654012fSReza Sabdar  *   or remote data server.
12812654012fSReza Sabdar  *
12822654012fSReza Sabdar  * Parameters:
12832654012fSReza Sabdar  *   connection (input) - connection handle.
12842654012fSReza Sabdar  *   body       (input) - request message body.
12852654012fSReza Sabdar  *
12862654012fSReza Sabdar  * Returns:
12872654012fSReza Sabdar  *   void
12882654012fSReza Sabdar  */
12892654012fSReza Sabdar void
12902654012fSReza Sabdar ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
12912654012fSReza Sabdar {
12922654012fSReza Sabdar 	ndmp_mover_connect_request_v4 *request;
12932654012fSReza Sabdar 	ndmp_mover_connect_reply_v4 reply;
12942654012fSReza Sabdar 	ndmpd_session_t *session = ndmp_get_client_data(connection);
12952654012fSReza Sabdar 
12962654012fSReza Sabdar 	request = (ndmp_mover_connect_request_v4 *)body;
12972654012fSReza Sabdar 	(void) memset((void*)&reply, 0, sizeof (reply));
12982654012fSReza Sabdar 
12992654012fSReza Sabdar 	if (request->mode != NDMP_MOVER_MODE_READ &&
13002654012fSReza Sabdar 	    request->mode != NDMP_MOVER_MODE_WRITE) {
13012654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
13022654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
13032654012fSReza Sabdar 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
13042654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
13052654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
13062654012fSReza Sabdar 		    request->addr.addr_type);
13072654012fSReza Sabdar 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
13082654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_STATE_ERR;
13092654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
13102654012fSReza Sabdar 		    session->ns_mover.md_state);
13112654012fSReza Sabdar 	} else if (session->ns_tape.td_fd == -1) {
13122654012fSReza Sabdar 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
13132654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No tape device open");
13142654012fSReza Sabdar 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
13152654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
13162654012fSReza Sabdar 		reply.error = NDMP_PERMISSION_ERR;
13172654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
13182654012fSReza Sabdar 	} else if (session->ns_mover.md_record_size == 0) {
13192654012fSReza Sabdar 		reply.error = NDMP_PRECONDITION_ERR;
13202654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
13212654012fSReza Sabdar 	} else
13222654012fSReza Sabdar 		reply.error = NDMP_NO_ERR;
13232654012fSReza Sabdar 
13242654012fSReza Sabdar 	if (reply.error != NDMP_NO_ERR) {
13252654012fSReza Sabdar 		ndmp_send_reply(connection, (void *) &reply,
13262654012fSReza Sabdar 		    "sending ndmp_mover_connect reply");
13272654012fSReza Sabdar 		return;
13282654012fSReza Sabdar 	}
13292654012fSReza Sabdar 
13302654012fSReza Sabdar 	switch (request->addr.addr_type) {
13312654012fSReza Sabdar 	case NDMP_ADDR_LOCAL:
13322654012fSReza Sabdar 		/*
13332654012fSReza Sabdar 		 * Verify that the data server is listening for a
13342654012fSReza Sabdar 		 * local connection.
13352654012fSReza Sabdar 		 */
13362654012fSReza Sabdar 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
13372654012fSReza Sabdar 		    session->ns_data.dd_listen_sock != -1) {
13382654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
13392654012fSReza Sabdar 			    "Data server is not in local listen state");
13402654012fSReza Sabdar 			reply.error = NDMP_ILLEGAL_STATE_ERR;
13412654012fSReza Sabdar 		} else
13422654012fSReza Sabdar 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
13432654012fSReza Sabdar 		break;
13442654012fSReza Sabdar 
13452654012fSReza Sabdar 	case NDMP_ADDR_TCP:
134697f7c475SJan Kryl 		reply.error = mover_connect_sock(session, request->mode,
13472654012fSReza Sabdar 		    request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
13482654012fSReza Sabdar 		break;
13492654012fSReza Sabdar 
13502654012fSReza Sabdar 	default:
13512654012fSReza Sabdar 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
13522654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
13532654012fSReza Sabdar 		    request->addr.addr_type);
13542654012fSReza Sabdar 	}
13552654012fSReza Sabdar 
13562654012fSReza Sabdar 	if (reply.error == NDMP_NO_ERR) {
13572654012fSReza Sabdar 		session->ns_mover.md_data_addr.addr_type =
13582654012fSReza Sabdar 		    request->addr.addr_type;
13592654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
13602654012fSReza Sabdar 		session->ns_mover.md_mode = request->mode;
13612654012fSReza Sabdar 	}
13622654012fSReza Sabdar 
13632654012fSReza Sabdar 	ndmp_send_reply(connection, (void *) &reply,
13642654012fSReza Sabdar 	    "sending ndmp_mover_connect reply");
13652654012fSReza Sabdar }
13662654012fSReza Sabdar 
13672654012fSReza Sabdar 
13682654012fSReza Sabdar 
13692654012fSReza Sabdar /*
13702654012fSReza Sabdar  * ************************************************************************
13712654012fSReza Sabdar  * LOCALS
13722654012fSReza Sabdar  * ************************************************************************
13732654012fSReza Sabdar  */
13742654012fSReza Sabdar 
13752654012fSReza Sabdar /*
13762654012fSReza Sabdar  * ndmpd_local_write
13772654012fSReza Sabdar  *
13782654012fSReza Sabdar  * Writes data to the mover.
13792654012fSReza Sabdar  * Buffers and write data to the tape device.
13802654012fSReza Sabdar  * A full tape record is buffered before being written.
13812654012fSReza Sabdar  *
13822654012fSReza Sabdar  * Parameters:
13832654012fSReza Sabdar  *   session    (input) - session pointer.
13842654012fSReza Sabdar  *   data       (input) - data to be written.
13852654012fSReza Sabdar  *   length     (input) - data length.
13862654012fSReza Sabdar  *
13872654012fSReza Sabdar  * Returns:
13882654012fSReza Sabdar  *   0 - data successfully written.
13892654012fSReza Sabdar  *  -1 - error.
13902654012fSReza Sabdar  */
13912654012fSReza Sabdar int
13922654012fSReza Sabdar ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
13932654012fSReza Sabdar {
13942654012fSReza Sabdar 	ulong_t count = 0;
13952654012fSReza Sabdar 	ssize_t n;
13962654012fSReza Sabdar 	ulong_t len;
13972654012fSReza Sabdar 
13982654012fSReza Sabdar 	/*
13992654012fSReza Sabdar 	 * A length of 0 indicates that any buffered data should be
14002654012fSReza Sabdar 	 * flushed to tape.
14012654012fSReza Sabdar 	 */
14022654012fSReza Sabdar 	if (length == 0) {
14032654012fSReza Sabdar 		if (session->ns_mover.md_w_index == 0)
14042654012fSReza Sabdar 			return (0);
14052654012fSReza Sabdar 
14062654012fSReza Sabdar 		(void) memset(
14072654012fSReza Sabdar 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
14082654012fSReza Sabdar 		    0, session->ns_mover.md_record_size -
14092654012fSReza Sabdar 		    session->ns_mover.md_w_index);
14102654012fSReza Sabdar 
14119ee94b97SJan Kryl 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
14122654012fSReza Sabdar 		    session->ns_mover.md_record_size);
14132654012fSReza Sabdar 		if (n <= 0) {
14142654012fSReza Sabdar 			ndmpd_mover_error(session,
14152654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14162654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
14172654012fSReza Sabdar 			return (-1);
14182654012fSReza Sabdar 		}
14192654012fSReza Sabdar 		session->ns_mover.md_position += n;
14202654012fSReza Sabdar 		session->ns_mover.md_data_written +=
14212654012fSReza Sabdar 		    session->ns_mover.md_w_index;
14222654012fSReza Sabdar 		session->ns_mover.md_record_num++;
14232654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
14242654012fSReza Sabdar 		return (0);
14252654012fSReza Sabdar 	}
14262654012fSReza Sabdar 	/* Break the data into records. */
14272654012fSReza Sabdar 	while (count < length) {
14282654012fSReza Sabdar 		/*
14292654012fSReza Sabdar 		 * Determine if data needs to be buffered or
14302654012fSReza Sabdar 		 * can be written directly from user supplied location.
14312654012fSReza Sabdar 		 * We can fast path the write if there is no pending
14322654012fSReza Sabdar 		 * buffered data and there is at least a full record's worth
14332654012fSReza Sabdar 		 * of data to be written.
14342654012fSReza Sabdar 		 */
14352654012fSReza Sabdar 		if (session->ns_mover.md_w_index == 0 &&
14362654012fSReza Sabdar 		    length - count >= session->ns_mover.md_record_size) {
14379ee94b97SJan Kryl 			n = mover_tape_write_v3(session, &data[count],
14382654012fSReza Sabdar 			    session->ns_mover.md_record_size);
14392654012fSReza Sabdar 			if (n <= 0) {
14402654012fSReza Sabdar 				ndmpd_mover_error(session,
14412654012fSReza Sabdar 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14422654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
14432654012fSReza Sabdar 				return (-1);
14442654012fSReza Sabdar 			}
14452654012fSReza Sabdar 			session->ns_mover.md_position += n;
14462654012fSReza Sabdar 			session->ns_mover.md_data_written += n;
14472654012fSReza Sabdar 			session->ns_mover.md_record_num++;
14482654012fSReza Sabdar 			count += n;
14492654012fSReza Sabdar 			continue;
14502654012fSReza Sabdar 		}
14512654012fSReza Sabdar 		/* Buffer the data */
14522654012fSReza Sabdar 		len = length - count;
14532654012fSReza Sabdar 		if (len > session->ns_mover.md_record_size -
14542654012fSReza Sabdar 		    session->ns_mover.md_w_index)
14552654012fSReza Sabdar 			len = session->ns_mover.md_record_size -
14562654012fSReza Sabdar 			    session->ns_mover.md_w_index;
14572654012fSReza Sabdar 
14582654012fSReza Sabdar 		(void) memcpy(
14592654012fSReza Sabdar 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
14602654012fSReza Sabdar 		    &data[count], len);
14612654012fSReza Sabdar 		session->ns_mover.md_w_index += len;
14622654012fSReza Sabdar 		count += len;
14632654012fSReza Sabdar 
14642654012fSReza Sabdar 		/* Write the buffer if its full */
14652654012fSReza Sabdar 		if (session->ns_mover.md_w_index ==
14662654012fSReza Sabdar 		    session->ns_mover.md_record_size) {
14679ee94b97SJan Kryl 			n = mover_tape_write_v3(session,
14689ee94b97SJan Kryl 			    session->ns_mover.md_buf,
14692654012fSReza Sabdar 			    session->ns_mover.md_record_size);
14709ee94b97SJan Kryl 			if (n <= 0) {
14712654012fSReza Sabdar 				ndmpd_mover_error(session,
14722654012fSReza Sabdar 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
14732654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
14742654012fSReza Sabdar 				return (-1);
14752654012fSReza Sabdar 			}
14762654012fSReza Sabdar 			session->ns_mover.md_position += n;
14772654012fSReza Sabdar 			session->ns_mover.md_data_written += n;
14782654012fSReza Sabdar 			session->ns_mover.md_record_num++;
14792654012fSReza Sabdar 			session->ns_mover.md_w_index = 0;
14802654012fSReza Sabdar 		}
14812654012fSReza Sabdar 	}
14822654012fSReza Sabdar 
14832654012fSReza Sabdar 	return (0);
14842654012fSReza Sabdar }
14852654012fSReza Sabdar 
14862654012fSReza Sabdar 
14872654012fSReza Sabdar /*
14882654012fSReza Sabdar  * ndmpd_remote_write
14892654012fSReza Sabdar  *
14902654012fSReza Sabdar  * Writes data to the remote mover.
14912654012fSReza Sabdar  *
14922654012fSReza Sabdar  * Parameters:
14932654012fSReza Sabdar  *   session    (input) - session pointer.
14942654012fSReza Sabdar  *   data       (input) - data to be written.
14952654012fSReza Sabdar  *   length     (input) - data length.
14962654012fSReza Sabdar  *
14972654012fSReza Sabdar  * Returns:
14982654012fSReza Sabdar  *   0 - data successfully written.
14992654012fSReza Sabdar  *  -1 - error.
15002654012fSReza Sabdar  */
15012654012fSReza Sabdar int
15022654012fSReza Sabdar ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
15032654012fSReza Sabdar {
15042654012fSReza Sabdar 	ssize_t n;
15052654012fSReza Sabdar 	ulong_t count = 0;
15062654012fSReza Sabdar 
15072654012fSReza Sabdar 	while (count < length) {
15082654012fSReza Sabdar 		if (session->ns_eof == TRUE ||
15092654012fSReza Sabdar 		    session->ns_data.dd_abort == TRUE)
15102654012fSReza Sabdar 			return (-1);
15112654012fSReza Sabdar 
15122654012fSReza Sabdar 		if ((n = write(session->ns_data.dd_sock, &data[count],
15132654012fSReza Sabdar 		    length - count)) < 0) {
15142654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Socket write error: %m.");
15152654012fSReza Sabdar 			return (-1);
15162654012fSReza Sabdar 		}
15172654012fSReza Sabdar 		count += n;
15182654012fSReza Sabdar 	}
15192654012fSReza Sabdar 
15202654012fSReza Sabdar 	return (0);
15212654012fSReza Sabdar }
15222654012fSReza Sabdar 
15232654012fSReza Sabdar /*
15242654012fSReza Sabdar  * ndmpd_local_read
15252654012fSReza Sabdar  *
15262654012fSReza Sabdar  * Reads data from the local tape device.
15272654012fSReza Sabdar  * Full tape records are read and buffered.
15282654012fSReza Sabdar  *
15292654012fSReza Sabdar  * Parameters:
15302654012fSReza Sabdar  *   session (input) - session pointer.
15312654012fSReza Sabdar  *   data    (input) - location to store data.
15322654012fSReza Sabdar  *   length  (input) - data length.
15332654012fSReza Sabdar  *
15342654012fSReza Sabdar  * Returns:
15352654012fSReza Sabdar  *   0 - data successfully read.
15362654012fSReza Sabdar  *  -1 - error.
15372654012fSReza Sabdar  *   1 - session terminated or operation aborted.
15382654012fSReza Sabdar  */
15392654012fSReza Sabdar int
15402654012fSReza Sabdar ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
15412654012fSReza Sabdar {
15422654012fSReza Sabdar 	ulong_t count = 0;
15432654012fSReza Sabdar 	ssize_t n;
15442654012fSReza Sabdar 	ulong_t len;
15452654012fSReza Sabdar 	ndmp_notify_mover_paused_request pause_request;
15462654012fSReza Sabdar 
15472654012fSReza Sabdar 	/*
15482654012fSReza Sabdar 	 * Automatically increase the seek window if necessary.
15492654012fSReza Sabdar 	 * This is needed in the event the module attempts to read
15502654012fSReza Sabdar 	 * past a seek window set via a prior call to ndmpd_seek() or
15512654012fSReza Sabdar 	 * the module has not issued a seek. If no seek was issued then
15522654012fSReza Sabdar 	 * pretend that a seek was issued to read the entire tape.
15532654012fSReza Sabdar 	 */
15542654012fSReza Sabdar 	if (length > session->ns_mover.md_bytes_left_to_read) {
15552654012fSReza Sabdar 		/* ndmpd_seek() never called? */
15562654012fSReza Sabdar 		if (session->ns_data.dd_read_length == 0) {
15572654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read = ~0LL;
15582654012fSReza Sabdar 			session->ns_data.dd_read_offset = 0LL;
15592654012fSReza Sabdar 			session->ns_data.dd_read_length = ~0LL;
15602654012fSReza Sabdar 		} else {
15612654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read = length;
15622654012fSReza Sabdar 			session->ns_data.dd_read_offset =
15632654012fSReza Sabdar 			    session->ns_mover.md_position;
15642654012fSReza Sabdar 			session->ns_data.dd_read_length = length;
15652654012fSReza Sabdar 		}
15662654012fSReza Sabdar 	}
15672654012fSReza Sabdar 	/*
15682654012fSReza Sabdar 	 * Read as many records as necessary to satisfy the request.
15692654012fSReza Sabdar 	 */
15702654012fSReza Sabdar 	while (count < length) {
15712654012fSReza Sabdar 		/*
15722654012fSReza Sabdar 		 * If the end of the mover window has been reached,
15732654012fSReza Sabdar 		 * then notify the client that a new data window is needed.
15742654012fSReza Sabdar 		 */
15752654012fSReza Sabdar 		if (session->ns_mover.md_position >=
15762654012fSReza Sabdar 		    session->ns_mover.md_window_offset +
15772654012fSReza Sabdar 		    session->ns_mover.md_window_length) {
15782654012fSReza Sabdar 
15792654012fSReza Sabdar 			session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
15802654012fSReza Sabdar 			session->ns_mover.md_pause_reason =
15812654012fSReza Sabdar 			    NDMP_MOVER_PAUSE_SEEK;
15822654012fSReza Sabdar 			pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
15832654012fSReza Sabdar 			pause_request.seek_position =
15842654012fSReza Sabdar 			    long_long_to_quad(session->ns_mover.md_position);
15852654012fSReza Sabdar 
15862654012fSReza Sabdar 			if (ndmp_send_request(session->ns_connection,
15872654012fSReza Sabdar 			    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
15882654012fSReza Sabdar 			    (void *) &pause_request, 0) < 0) {
15892654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
15902654012fSReza Sabdar 				    "Sending notify_mover_paused request");
15912654012fSReza Sabdar 				ndmpd_mover_error(session,
15922654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
15932654012fSReza Sabdar 				return (-1);
15942654012fSReza Sabdar 			}
15952654012fSReza Sabdar 			/*
15968c4f9701SJanice Chang 			 * Wait until the state is changed by
15972654012fSReza Sabdar 			 * an abort or continue request.
15982654012fSReza Sabdar 			 */
1599a23888a3SJan Kryl 			if (ndmp_wait_for_mover(session) != 0)
16002654012fSReza Sabdar 				return (1);
16012654012fSReza Sabdar 		}
16022654012fSReza Sabdar 		len = length - count;
16032654012fSReza Sabdar 
16042654012fSReza Sabdar 		/*
16052654012fSReza Sabdar 		 * Prevent reading past the end of the window.
16062654012fSReza Sabdar 		 */
16072654012fSReza Sabdar 		if (len >
16082654012fSReza Sabdar 		    session->ns_mover.md_window_offset +
16092654012fSReza Sabdar 		    session->ns_mover.md_window_length -
16102654012fSReza Sabdar 		    session->ns_mover.md_position)
16112654012fSReza Sabdar 			len = session->ns_mover.md_window_offset +
16122654012fSReza Sabdar 			    session->ns_mover.md_window_length -
16132654012fSReza Sabdar 			    session->ns_mover.md_position;
16142654012fSReza Sabdar 
16152654012fSReza Sabdar 		/*
16162654012fSReza Sabdar 		 * Copy from the data buffer first.
16172654012fSReza Sabdar 		 */
16182654012fSReza Sabdar 		if (session->ns_mover.md_w_index -
16192654012fSReza Sabdar 		    session->ns_mover.md_r_index != 0) {
16202654012fSReza Sabdar 			/*
16212654012fSReza Sabdar 			 * Limit the copy to the amount of data in the buffer.
16222654012fSReza Sabdar 			 */
16232654012fSReza Sabdar 			if (len > session->ns_mover.md_w_index -
16242654012fSReza Sabdar 			    session->ns_mover.md_r_index)
16252654012fSReza Sabdar 				len = session->ns_mover.md_w_index
16262654012fSReza Sabdar 				    - session->ns_mover.md_r_index;
16272654012fSReza Sabdar 
16282654012fSReza Sabdar 			(void) memcpy((void *) &data[count],
16292654012fSReza Sabdar 			    &session->ns_mover.md_buf[session->
16302654012fSReza Sabdar 			    ns_mover.md_r_index], len);
16312654012fSReza Sabdar 			count += len;
16322654012fSReza Sabdar 			session->ns_mover.md_r_index += len;
16332654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read -= len;
16342654012fSReza Sabdar 			session->ns_mover.md_position += len;
16352654012fSReza Sabdar 			continue;
16362654012fSReza Sabdar 		}
16372654012fSReza Sabdar 		/*
16382654012fSReza Sabdar 		 * Determine if data needs to be buffered or
16392654012fSReza Sabdar 		 * can be read directly to user supplied location.
16402654012fSReza Sabdar 		 * We can fast path the read if at least a full record
16412654012fSReza Sabdar 		 * needs to be read and there is no seek pending.
16422654012fSReza Sabdar 		 * This is done to eliminate a buffer copy.
16432654012fSReza Sabdar 		 */
16442654012fSReza Sabdar 		if (len >= session->ns_mover.md_record_size &&
16452654012fSReza Sabdar 		    session->ns_mover.md_position >=
16462654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
16472654012fSReza Sabdar 			n = tape_read(session, &data[count]);
16482654012fSReza Sabdar 			if (n <= 0) {
16492654012fSReza Sabdar 				if (n == TAPE_NO_WRITER_ERR)
16502654012fSReza Sabdar 					return (1);
16512654012fSReza Sabdar 
16522654012fSReza Sabdar 				ndmpd_mover_error(session,
16532654012fSReza Sabdar 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
16542654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
16552654012fSReza Sabdar 				return (n == 0) ? (1) : (-1);
16562654012fSReza Sabdar 			}
16572654012fSReza Sabdar 			count += n;
16582654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read -= n;
16592654012fSReza Sabdar 			session->ns_mover.md_position += n;
16602654012fSReza Sabdar 			continue;
16612654012fSReza Sabdar 		}
16622654012fSReza Sabdar 		/* Read the next record into the buffer. */
16632654012fSReza Sabdar 		n = tape_read(session, session->ns_mover.md_buf);
16642654012fSReza Sabdar 		if (n <= 0) {
16652654012fSReza Sabdar 			if (n == TAPE_NO_WRITER_ERR)
16662654012fSReza Sabdar 				return (1);
16672654012fSReza Sabdar 
16682654012fSReza Sabdar 			ndmpd_mover_error(session,
16692654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
16702654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
16712654012fSReza Sabdar 			return (n == 0) ? (1) : (-1);
16722654012fSReza Sabdar 		}
16732654012fSReza Sabdar 		session->ns_mover.md_w_index = n;
16742654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
16752654012fSReza Sabdar 
16762654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
16772654012fSReza Sabdar 
16782654012fSReza Sabdar 		/*
16792654012fSReza Sabdar 		 * Discard data if the current data stream position is
16802654012fSReza Sabdar 		 * prior to the seek position. This is necessary if a seek
16812654012fSReza Sabdar 		 * request set the seek pointer to a position that is not a
16822654012fSReza Sabdar 		 * record boundary. The seek request handler can only position
16832654012fSReza Sabdar 		 * to the start of a record.
16842654012fSReza Sabdar 		 */
16852654012fSReza Sabdar 		if (session->ns_mover.md_position <
16862654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
16872654012fSReza Sabdar 			session->ns_mover.md_r_index =
16882654012fSReza Sabdar 			    session->ns_mover.md_seek_position -
16892654012fSReza Sabdar 			    session->ns_mover.md_position;
16902654012fSReza Sabdar 			session->ns_mover.md_position =
16912654012fSReza Sabdar 			    session->ns_mover.md_seek_position;
16922654012fSReza Sabdar 		}
16932654012fSReza Sabdar 	}
16942654012fSReza Sabdar 
16952654012fSReza Sabdar 	return (0);
16962654012fSReza Sabdar }
16972654012fSReza Sabdar 
16982654012fSReza Sabdar 
16992654012fSReza Sabdar /*
17002654012fSReza Sabdar  * ndmpd_remote_read
17012654012fSReza Sabdar  *
17022654012fSReza Sabdar  * Reads data from the remote mover.
17032654012fSReza Sabdar  *
17042654012fSReza Sabdar  * Parameters:
17052654012fSReza Sabdar  *   session (input) - session pointer.
17062654012fSReza Sabdar  *   data    (input) - data to be written.
17072654012fSReza Sabdar  *   length  (input) - data length.
17082654012fSReza Sabdar  *
17092654012fSReza Sabdar  * Returns:
17102654012fSReza Sabdar  *   0 - data successfully read.
17112654012fSReza Sabdar  *  -1 - error.
17122654012fSReza Sabdar  *   1 - session terminated or operation aborted.
17132654012fSReza Sabdar  */
17142654012fSReza Sabdar int
17152654012fSReza Sabdar ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
17162654012fSReza Sabdar {
17172654012fSReza Sabdar 	ulong_t count = 0;
17182654012fSReza Sabdar 	ssize_t n;
17192654012fSReza Sabdar 	ulong_t len;
17202654012fSReza Sabdar 	ndmp_notify_data_read_request request;
17212654012fSReza Sabdar 
17222654012fSReza Sabdar 	while (count < length) {
17232654012fSReza Sabdar 		len = length - count;
17242654012fSReza Sabdar 
17252654012fSReza Sabdar 		/*
17262654012fSReza Sabdar 		 * If the end of the seek window has been reached then
17272654012fSReza Sabdar 		 * send an ndmp_read request to the client.
17282654012fSReza Sabdar 		 * The NDMP client will then send a mover_data_read request to
17292654012fSReza Sabdar 		 * the remote mover and the mover will send more data.
17302654012fSReza Sabdar 		 * This condition can occur if the module attempts to read past
17312654012fSReza Sabdar 		 * a seek window set via a prior call to ndmpd_seek() or
17322654012fSReza Sabdar 		 * the module has not issued a seek. If no seek was issued then
17332654012fSReza Sabdar 		 * pretend that a seek was issued to read the entire tape.
17342654012fSReza Sabdar 		 */
17352654012fSReza Sabdar 		if (session->ns_mover.md_bytes_left_to_read == 0) {
17362654012fSReza Sabdar 			/* ndmpd_seek() never called? */
17372654012fSReza Sabdar 			if (session->ns_data.dd_read_length == 0) {
17382654012fSReza Sabdar 				session->ns_mover.md_bytes_left_to_read = ~0LL;
17392654012fSReza Sabdar 				session->ns_data.dd_read_offset = 0LL;
17402654012fSReza Sabdar 				session->ns_data.dd_read_length = ~0LL;
17412654012fSReza Sabdar 			} else {
17422654012fSReza Sabdar 				session->ns_mover.md_bytes_left_to_read = len;
17432654012fSReza Sabdar 				session->ns_data.dd_read_offset =
17442654012fSReza Sabdar 				    session->ns_mover.md_position;
17452654012fSReza Sabdar 				session->ns_data.dd_read_length = len;
17462654012fSReza Sabdar 			}
17472654012fSReza Sabdar 
17482654012fSReza Sabdar 			request.offset =
17492654012fSReza Sabdar 			    long_long_to_quad(session->ns_data.dd_read_offset);
17502654012fSReza Sabdar 			request.length =
17512654012fSReza Sabdar 			    long_long_to_quad(session->ns_data.dd_read_length);
17522654012fSReza Sabdar 
17537bc22e45SReza Sabdar 			if (ndmp_send_request_lock(session->ns_connection,
17542654012fSReza Sabdar 			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
17552654012fSReza Sabdar 			    (void *) &request, 0) < 0) {
17562654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
17572654012fSReza Sabdar 				    "Sending notify_data_read request");
17582654012fSReza Sabdar 				return (-1);
17592654012fSReza Sabdar 			}
17602654012fSReza Sabdar 		}
17612654012fSReza Sabdar 		if (session->ns_eof == TRUE ||
17622654012fSReza Sabdar 		    session->ns_data.dd_abort == TRUE)
17632654012fSReza Sabdar 			return (1);
17642654012fSReza Sabdar 
17652654012fSReza Sabdar 		/*
17662654012fSReza Sabdar 		 * If the module called ndmpd_seek() prior to reading all of the
17672654012fSReza Sabdar 		 * data that the remote mover was requested to send, then the
17682654012fSReza Sabdar 		 * excess data from the seek has to be discardd.
17692654012fSReza Sabdar 		 */
17702654012fSReza Sabdar 		if (session->ns_mover.md_discard_length != 0) {
17712654012fSReza Sabdar 			n = discard_data(session,
17722654012fSReza Sabdar 			    (ulong_t)session->ns_mover.md_discard_length);
17732654012fSReza Sabdar 			if (n < 0)
17742654012fSReza Sabdar 				return (-1);
17752654012fSReza Sabdar 			session->ns_mover.md_discard_length -= n;
17762654012fSReza Sabdar 			continue;
17772654012fSReza Sabdar 		}
17782654012fSReza Sabdar 		/*
17792654012fSReza Sabdar 		 * Don't attempt to read more data than the remote is sending.
17802654012fSReza Sabdar 		 */
17812654012fSReza Sabdar 		if (len > session->ns_mover.md_bytes_left_to_read)
17822654012fSReza Sabdar 			len = session->ns_mover.md_bytes_left_to_read;
17832654012fSReza Sabdar 
17842654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "len: %u", len);
17852654012fSReza Sabdar 
17862654012fSReza Sabdar 		if ((n = read(session->ns_data.dd_sock, &data[count],
17872654012fSReza Sabdar 		    len)) < 0) {
17882654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
17892654012fSReza Sabdar 			return (-1);
17902654012fSReza Sabdar 		}
17912654012fSReza Sabdar 		/* read returns 0 if the connection was closed */
17922654012fSReza Sabdar 		if (n == 0)
17932654012fSReza Sabdar 			return (-1);
17942654012fSReza Sabdar 
17952654012fSReza Sabdar 		count += n;
17962654012fSReza Sabdar 		session->ns_mover.md_bytes_left_to_read -= n;
17972654012fSReza Sabdar 		session->ns_mover.md_position += n;
17982654012fSReza Sabdar 	}
17992654012fSReza Sabdar 
18002654012fSReza Sabdar 	return (0);
18012654012fSReza Sabdar }
18022654012fSReza Sabdar 
18032654012fSReza Sabdar /* *** ndmpd internal functions ***************************************** */
18042654012fSReza Sabdar 
18052654012fSReza Sabdar /*
18062654012fSReza Sabdar  * ndmpd_mover_init
18072654012fSReza Sabdar  *
18082654012fSReza Sabdar  * Initialize mover specific session variables.
18092654012fSReza Sabdar  * Don't initialize variables such as record_size that need to
18102654012fSReza Sabdar  * persist across data operations. A client may open a connection and
18112654012fSReza Sabdar  * do multiple backups after setting the record_size.
18122654012fSReza Sabdar  *
18132654012fSReza Sabdar  * Parameters:
18142654012fSReza Sabdar  *   session (input) - session pointer.
18152654012fSReza Sabdar  *
18162654012fSReza Sabdar  * Returns:
18172654012fSReza Sabdar  *   0 - success.
18182654012fSReza Sabdar  *  -1 - error.
18192654012fSReza Sabdar  */
18202654012fSReza Sabdar int
18212654012fSReza Sabdar ndmpd_mover_init(ndmpd_session_t *session)
18222654012fSReza Sabdar {
18232654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
18242654012fSReza Sabdar 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
18252654012fSReza Sabdar 	session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
18262654012fSReza Sabdar 	session->ns_mover.md_data_written = 0LL;
18272654012fSReza Sabdar 	session->ns_mover.md_seek_position = 0LL;
18282654012fSReza Sabdar 	session->ns_mover.md_bytes_left_to_read = 0LL;
18292654012fSReza Sabdar 	session->ns_mover.md_window_offset = 0LL;
18302654012fSReza Sabdar 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
18312654012fSReza Sabdar 	session->ns_mover.md_position = 0LL;
18322654012fSReza Sabdar 	session->ns_mover.md_discard_length = 0;
18332654012fSReza Sabdar 	session->ns_mover.md_record_num = 0;
18342654012fSReza Sabdar 	session->ns_mover.md_record_size = 0;
18352654012fSReza Sabdar 	session->ns_mover.md_listen_sock = -1;
18362654012fSReza Sabdar 	session->ns_mover.md_pre_cond = FALSE;
18372654012fSReza Sabdar 	session->ns_mover.md_sock = -1;
18382654012fSReza Sabdar 	session->ns_mover.md_r_index = 0;
18392654012fSReza Sabdar 	session->ns_mover.md_w_index = 0;
18402654012fSReza Sabdar 	session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
18412654012fSReza Sabdar 	if (!session->ns_mover.md_buf)
18422654012fSReza Sabdar 		return (-1);
18432654012fSReza Sabdar 
18442654012fSReza Sabdar 	if (ndmp_get_version(session->ns_connection) == NDMPV3) {
18452654012fSReza Sabdar 		session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
18462654012fSReza Sabdar 		(void) memset(&session->ns_mover.md_data_addr, 0,
18472654012fSReza Sabdar 		    sizeof (ndmp_addr_v3));
18482654012fSReza Sabdar 	}
18492654012fSReza Sabdar 	return (0);
18502654012fSReza Sabdar }
18512654012fSReza Sabdar 
18522654012fSReza Sabdar 
18532654012fSReza Sabdar /*
18542654012fSReza Sabdar  * ndmpd_mover_shut_down
18552654012fSReza Sabdar  *
18562654012fSReza Sabdar  * Shutdown the mover. It closes all the sockets.
18572654012fSReza Sabdar  *
18582654012fSReza Sabdar  * Parameters:
18592654012fSReza Sabdar  *   session (input) - session pointer.
18602654012fSReza Sabdar  *
18612654012fSReza Sabdar  * Returns:
18622654012fSReza Sabdar  *   void
18632654012fSReza Sabdar  */
18642654012fSReza Sabdar void
18652654012fSReza Sabdar ndmpd_mover_shut_down(ndmpd_session_t *session)
18662654012fSReza Sabdar {
1867a23888a3SJan Kryl 	ndmp_lbr_params_t *nlp;
1868a23888a3SJan Kryl 
1869a23888a3SJan Kryl 	if ((nlp = ndmp_get_nlp(session)) == NULL)
1870a23888a3SJan Kryl 		return;
1871a23888a3SJan Kryl 
1872a23888a3SJan Kryl 	(void) mutex_lock(&nlp->nlp_mtx);
18732654012fSReza Sabdar 	if (session->ns_mover.md_listen_sock != -1) {
18742654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
18752654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
18762654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
18772654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
18782654012fSReza Sabdar 		(void) close(session->ns_mover.md_listen_sock);
18792654012fSReza Sabdar 		session->ns_mover.md_listen_sock = -1;
18802654012fSReza Sabdar 	}
18812654012fSReza Sabdar 	if (session->ns_mover.md_sock != -1) {
18822654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
18832654012fSReza Sabdar 		    session->ns_mover.md_sock);
18842654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
18852654012fSReza Sabdar 		    session->ns_mover.md_sock);
18862654012fSReza Sabdar 		(void) close(session->ns_mover.md_sock);
18872654012fSReza Sabdar 		session->ns_mover.md_sock = -1;
18882654012fSReza Sabdar 	}
1889a23888a3SJan Kryl 	(void) cond_broadcast(&nlp->nlp_cv);
1890a23888a3SJan Kryl 	(void) mutex_unlock(&nlp->nlp_mtx);
18912654012fSReza Sabdar }
18922654012fSReza Sabdar 
18932654012fSReza Sabdar 
18942654012fSReza Sabdar /*
18952654012fSReza Sabdar  * ndmpd_mover_cleanup
18962654012fSReza Sabdar  *
18972654012fSReza Sabdar  * Parameters:
18982654012fSReza Sabdar  *   session (input) - session pointer.
18992654012fSReza Sabdar  *
19002654012fSReza Sabdar  * Returns:
19012654012fSReza Sabdar  *   void
19022654012fSReza Sabdar  */
19032654012fSReza Sabdar void
19042654012fSReza Sabdar ndmpd_mover_cleanup(ndmpd_session_t *session)
19052654012fSReza Sabdar {
19062654012fSReza Sabdar 	NDMP_FREE(session->ns_mover.md_buf);
19072654012fSReza Sabdar }
19082654012fSReza Sabdar 
19092654012fSReza Sabdar 
19102654012fSReza Sabdar /*
19112654012fSReza Sabdar  * ndmpd_mover_connect
19122654012fSReza Sabdar  *   Create a connection to the specified mover.
19132654012fSReza Sabdar  *
19142654012fSReza Sabdar  * Parameters:
19152654012fSReza Sabdar  *   session (input) - session pointer
19162654012fSReza Sabdar  *
19172654012fSReza Sabdar  * Returns:
19182654012fSReza Sabdar  *   error code.
19192654012fSReza Sabdar  */
19202654012fSReza Sabdar ndmp_error
19212654012fSReza Sabdar ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
19222654012fSReza Sabdar {
19232654012fSReza Sabdar 	ndmp_mover_addr *mover = &session->ns_data.dd_mover;
19242654012fSReza Sabdar 	struct sockaddr_in sin;
19252654012fSReza Sabdar 	int sock = -1;
19262654012fSReza Sabdar 
19272654012fSReza Sabdar 	if (mover->addr_type == NDMP_ADDR_TCP) {
19282654012fSReza Sabdar 		if (mover->ndmp_mover_addr_u.addr.ip_addr) {
19292654012fSReza Sabdar 			(void) memset((void *) &sin, 0, sizeof (sin));
19302654012fSReza Sabdar 			sin.sin_family = AF_INET;
19312654012fSReza Sabdar 			sin.sin_addr.s_addr =
19322654012fSReza Sabdar 			    htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
19332654012fSReza Sabdar 			sin.sin_port =
19342654012fSReza Sabdar 			    htons(mover->ndmp_mover_addr_u.addr.port);
19352654012fSReza Sabdar 
19362654012fSReza Sabdar 			/*
19372654012fSReza Sabdar 			 * If the address type is TCP but both the address and
19382654012fSReza Sabdar 			 * the port number are zero, we have to use a different
19392654012fSReza Sabdar 			 * socket than the mover socket. This can happen when
19402654012fSReza Sabdar 			 * using NDMP disk to disk copy (AKA D2D copy).
19412654012fSReza Sabdar 			 * The NDMPCopy client will send a zero address to
19422654012fSReza Sabdar 			 * direct the server to use the mover socket as the
19432654012fSReza Sabdar 			 * data socket to receive the recovery data.
19442654012fSReza Sabdar 			 */
19452654012fSReza Sabdar 			if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
19462654012fSReza Sabdar 				session->ns_data.dd_sock =
19472654012fSReza Sabdar 				    session->ns_mover.md_sock;
19482654012fSReza Sabdar 				return (NDMP_NO_ERR);
19492654012fSReza Sabdar 			}
19502654012fSReza Sabdar 
19512654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
19522654012fSReza Sabdar 			    mover->ndmp_mover_addr_u.addr.ip_addr,
19532654012fSReza Sabdar 			    (ulong_t)sin.sin_port);
19542654012fSReza Sabdar 
19552654012fSReza Sabdar 			if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
19562654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Socket error: %m");
19572654012fSReza Sabdar 				return (NDMP_IO_ERR);
19582654012fSReza Sabdar 			}
19592654012fSReza Sabdar 			if (connect(sock, (struct sockaddr *)&sin,
19602654012fSReza Sabdar 			    sizeof (sin)) < 0) {
19612654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Connect error: %m");
19622654012fSReza Sabdar 				(void) close(sock);
19632654012fSReza Sabdar 				return (NDMP_IO_ERR);
19642654012fSReza Sabdar 			}
196597f7c475SJan Kryl 			set_socket_options(sock);
19662654012fSReza Sabdar 		} else {
19672654012fSReza Sabdar 			if ((session->ns_mover.md_state !=
19682654012fSReza Sabdar 			    NDMP_MOVER_STATE_ACTIVE) ||
19692654012fSReza Sabdar 			    (session->ns_mover.md_sock == -1)) {
19702654012fSReza Sabdar 
19712654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
19722654012fSReza Sabdar 				    "Not in active  state mover"
19732654012fSReza Sabdar 				    "  state = %d or Invalid mover sock=%d",
19742654012fSReza Sabdar 				    session->ns_mover.md_state,
19752654012fSReza Sabdar 				    session->ns_mover.md_sock);
19762654012fSReza Sabdar 				return (NDMP_ILLEGAL_STATE_ERR);
19772654012fSReza Sabdar 			}
19782654012fSReza Sabdar 
19792654012fSReza Sabdar 			sock = session->ns_mover.md_sock;
19802654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
19812654012fSReza Sabdar 			    "session: 0x%x setting data sock fd: %d to be"
19822654012fSReza Sabdar 			    " same as listen_sock", session, sock);
19832654012fSReza Sabdar 		}
19842654012fSReza Sabdar 
19852654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
19862654012fSReza Sabdar 
19872654012fSReza Sabdar 		session->ns_data.dd_sock = sock;
19882654012fSReza Sabdar 
19892654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
19902654012fSReza Sabdar 
19912654012fSReza Sabdar 		return (NDMP_NO_ERR);
19922654012fSReza Sabdar 	}
19932654012fSReza Sabdar 	/* Local mover connection. */
19942654012fSReza Sabdar 
19952654012fSReza Sabdar 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
19962654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
19972654012fSReza Sabdar 		return (NDMP_ILLEGAL_STATE_ERR);
19982654012fSReza Sabdar 	}
19992654012fSReza Sabdar 	if (session->ns_tape.td_fd == -1) {
20002654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Tape device not open");
20012654012fSReza Sabdar 		return (NDMP_DEV_NOT_OPEN_ERR);
20022654012fSReza Sabdar 	}
20032654012fSReza Sabdar 	if (mover_mode == NDMP_MOVER_MODE_READ &&
20042654012fSReza Sabdar 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
20052654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Write protected device.");
20062654012fSReza Sabdar 		return (NDMP_WRITE_PROTECT_ERR);
20072654012fSReza Sabdar 	}
20082654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
20092654012fSReza Sabdar 	session->ns_mover.md_mode = mover_mode;
20102654012fSReza Sabdar 
20112654012fSReza Sabdar 	return (NDMP_NO_ERR);
20122654012fSReza Sabdar }
20132654012fSReza Sabdar 
20142654012fSReza Sabdar 
20152654012fSReza Sabdar 
20162654012fSReza Sabdar /*
20172654012fSReza Sabdar  * ndmpd_mover_seek
20182654012fSReza Sabdar  *
20192654012fSReza Sabdar  * Seek to the requested data stream position.
20202654012fSReza Sabdar  * If the requested offset is outside of the current window,
20212654012fSReza Sabdar  * the mover is paused and a notify_mover_paused request is sent
20222654012fSReza Sabdar  * notifying the client that a seek is required.
20232654012fSReza Sabdar  * If the requested offest is within the window but not within the
20242654012fSReza Sabdar  * current record, then the tape is positioned to the record containing
20252654012fSReza Sabdar  * the requested offest.
20262654012fSReza Sabdar  * The requested amount of data is then read from the tape device and
20272654012fSReza Sabdar  * written to the data connection.
20282654012fSReza Sabdar  *
20292654012fSReza Sabdar  * Parameters:
20302654012fSReza Sabdar  *   session (input) - session pointer.
20312654012fSReza Sabdar  *   offset  (input) - data stream position to seek to.
20322654012fSReza Sabdar  *   length  (input) - amount of data that will be read.
20332654012fSReza Sabdar  *
20342654012fSReza Sabdar  * Returns:
20352654012fSReza Sabdar  *   1 - seek pending completion by the NDMP client.
20362654012fSReza Sabdar  *   0 - seek successfully completed.
20372654012fSReza Sabdar  *  -1 - error.
20382654012fSReza Sabdar  */
20392654012fSReza Sabdar int
20402654012fSReza Sabdar ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
20412654012fSReza Sabdar     u_longlong_t length)
20422654012fSReza Sabdar {
20432654012fSReza Sabdar 	int ctlcmd;
20442654012fSReza Sabdar 	int ctlcnt;
20452654012fSReza Sabdar 	u_longlong_t tape_position;
20462654012fSReza Sabdar 	u_longlong_t buf_position;
20472654012fSReza Sabdar 	ndmp_notify_mover_paused_request pause_request;
20482654012fSReza Sabdar 
20492654012fSReza Sabdar 	session->ns_mover.md_seek_position = offset;
20502654012fSReza Sabdar 	session->ns_mover.md_bytes_left_to_read = length;
20512654012fSReza Sabdar 
20522654012fSReza Sabdar 	/*
20532654012fSReza Sabdar 	 * If the requested position is outside of the window,
20542654012fSReza Sabdar 	 * notify the client that a seek is required.
20552654012fSReza Sabdar 	 */
20562654012fSReza Sabdar 	if (session->ns_mover.md_seek_position <
20572654012fSReza Sabdar 	    session->ns_mover.md_window_offset ||
20582654012fSReza Sabdar 	    session->ns_mover.md_seek_position >=
20592654012fSReza Sabdar 	    session->ns_mover.md_window_offset +
20602654012fSReza Sabdar 	    session->ns_mover.md_window_length) {
20612654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
20622654012fSReza Sabdar 		    session->ns_mover.md_seek_position);
20632654012fSReza Sabdar 
20642654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
20652654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
20662654012fSReza Sabdar 
20672654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
20682654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
20692654012fSReza Sabdar 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
20702654012fSReza Sabdar 		pause_request.seek_position = long_long_to_quad(offset);
20712654012fSReza Sabdar 
20722654012fSReza Sabdar 		if (ndmp_send_request(session->ns_connection,
20732654012fSReza Sabdar 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
20742654012fSReza Sabdar 		    (void *) &pause_request, 0) < 0) {
20752654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
20762654012fSReza Sabdar 			    "Sending notify_mover_paused request");
20772654012fSReza Sabdar 			return (-1);
20782654012fSReza Sabdar 		}
20792654012fSReza Sabdar 		return (1);
20802654012fSReza Sabdar 	}
20812654012fSReza Sabdar 	/*
20822654012fSReza Sabdar 	 * Determine the data stream position of the first byte in the
20832654012fSReza Sabdar 	 * data buffer.
20842654012fSReza Sabdar 	 */
20852654012fSReza Sabdar 	buf_position = session->ns_mover.md_position -
20862654012fSReza Sabdar 	    (session->ns_mover.md_position % session->ns_mover.md_record_size);
20872654012fSReza Sabdar 
20882654012fSReza Sabdar 	/*
20892654012fSReza Sabdar 	 * Determine the data stream position of the next byte that
20902654012fSReza Sabdar 	 * will be read from tape.
20912654012fSReza Sabdar 	 */
20922654012fSReza Sabdar 	tape_position = buf_position;
20932654012fSReza Sabdar 	if (session->ns_mover.md_w_index != 0)
20942654012fSReza Sabdar 		tape_position += session->ns_mover.md_record_size;
20952654012fSReza Sabdar 
20962654012fSReza Sabdar 	/*
20972654012fSReza Sabdar 	 * Check if requested position is for data that has been read and is
20982654012fSReza Sabdar 	 * in the buffer.
20992654012fSReza Sabdar 	 */
21002654012fSReza Sabdar 	if (offset >= buf_position && offset < tape_position) {
21012654012fSReza Sabdar 		session->ns_mover.md_position = offset;
21022654012fSReza Sabdar 		session->ns_mover.md_r_index = session->ns_mover.md_position -
21032654012fSReza Sabdar 		    buf_position;
21042654012fSReza Sabdar 
21052654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
21062654012fSReza Sabdar 		    session->ns_mover.md_position,
21072654012fSReza Sabdar 		    session->ns_mover.md_r_index);
21082654012fSReza Sabdar 
21092654012fSReza Sabdar 		return (0);
21102654012fSReza Sabdar 	}
21112654012fSReza Sabdar 
21122654012fSReza Sabdar 	ctlcmd = 0;
21132654012fSReza Sabdar 	if (tape_position > session->ns_mover.md_seek_position) {
21142654012fSReza Sabdar 		/* Need to seek backward. */
21152654012fSReza Sabdar 		ctlcmd = MTBSR;
21162654012fSReza Sabdar 		ctlcnt = (int)((tape_position - offset - 1)
21172654012fSReza Sabdar 		    / session->ns_mover.md_record_size) + 1;
21182654012fSReza Sabdar 		tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
21192654012fSReza Sabdar 		    session->ns_mover.md_record_size) + 1) *
21202654012fSReza Sabdar 		    (u_longlong_t)session->ns_mover.md_record_size);
21212654012fSReza Sabdar 
21222654012fSReza Sabdar 	} else if (offset >= tape_position + session->ns_mover.md_record_size) {
21232654012fSReza Sabdar 		/* Need to seek forward. */
21242654012fSReza Sabdar 		ctlcmd = MTFSR;
21252654012fSReza Sabdar 		ctlcnt = (int)((offset - tape_position)
21262654012fSReza Sabdar 		    / session->ns_mover.md_record_size);
21272654012fSReza Sabdar 		tape_position += ((u_longlong_t)(((offset - tape_position) /
21282654012fSReza Sabdar 		    session->ns_mover.md_record_size)) *
21292654012fSReza Sabdar 		    (u_longlong_t)session->ns_mover.md_record_size);
21302654012fSReza Sabdar 	}
21312654012fSReza Sabdar 	/* Reposition the tape if necessary. */
21322654012fSReza Sabdar 	if (ctlcmd) {
21332654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
21342654012fSReza Sabdar 		    ctlcmd, ctlcnt);
21352654012fSReza Sabdar 		(void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
21362654012fSReza Sabdar 	}
21372654012fSReza Sabdar 
21382654012fSReza Sabdar 	session->ns_mover.md_position = tape_position;
21392654012fSReza Sabdar 	session->ns_mover.md_r_index = 0;
21402654012fSReza Sabdar 	session->ns_mover.md_w_index = 0;
21412654012fSReza Sabdar 
21422654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
21432654012fSReza Sabdar 
21442654012fSReza Sabdar 	return (0);
21452654012fSReza Sabdar }
21462654012fSReza Sabdar 
21472654012fSReza Sabdar 
21482654012fSReza Sabdar /* ** static functions ************************************************** */
21492654012fSReza Sabdar 
21502654012fSReza Sabdar /*
21512654012fSReza Sabdar  * create_listen_socket_v2
21522654012fSReza Sabdar  *
21532654012fSReza Sabdar  * Creates a socket for listening for accepting data connections.
21542654012fSReza Sabdar  *
21552654012fSReza Sabdar  * Parameters:
21562654012fSReza Sabdar  *   session (input)  - session pointer.
21572654012fSReza Sabdar  *   addr    (output) - location to store address of socket.
21582654012fSReza Sabdar  *   port    (output) - location to store port of socket.
21592654012fSReza Sabdar  *
21602654012fSReza Sabdar  * Returns:
21612654012fSReza Sabdar  *   0 - success.
21622654012fSReza Sabdar  *  -1 - error.
21632654012fSReza Sabdar  */
21642654012fSReza Sabdar static int
21652654012fSReza Sabdar create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
21662654012fSReza Sabdar {
21672654012fSReza Sabdar 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
21682654012fSReza Sabdar 	if (session->ns_mover.md_listen_sock < 0)
21692654012fSReza Sabdar 		return (-1);
21702654012fSReza Sabdar 
21712654012fSReza Sabdar 	/*
21722654012fSReza Sabdar 	 * Add a file handler for the listen socket.
21732654012fSReza Sabdar 	 * ndmpd_select will call accept_connection when a
21742654012fSReza Sabdar 	 * connection is ready to be accepted.
21752654012fSReza Sabdar 	 */
21762654012fSReza Sabdar 	if (ndmpd_add_file_handler(session, (void *) session,
21772654012fSReza Sabdar 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
21782654012fSReza Sabdar 	    accept_connection) < 0) {
21792654012fSReza Sabdar 		(void) close(session->ns_mover.md_listen_sock);
21802654012fSReza Sabdar 		session->ns_mover.md_listen_sock = -1;
21812654012fSReza Sabdar 		return (-1);
21822654012fSReza Sabdar 	}
21832654012fSReza Sabdar 
21842654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
21852654012fSReza Sabdar 	return (0);
21862654012fSReza Sabdar }
21872654012fSReza Sabdar 
21882654012fSReza Sabdar /*
21892654012fSReza Sabdar  * accept_connection
21902654012fSReza Sabdar  *
21912654012fSReza Sabdar  * Accept a data connection from a data server.
21922654012fSReza Sabdar  * Called by ndmpd_select when a connection is pending on
21932654012fSReza Sabdar  * the mover listen socket.
21942654012fSReza Sabdar  *
21952654012fSReza Sabdar  * Parameters:
21962654012fSReza Sabdar  *   cookie  (input) - session pointer.
21972654012fSReza Sabdar  *   fd      (input) - file descriptor.
21982654012fSReza Sabdar  *   mode    (input) - select mode.
21992654012fSReza Sabdar  *
22002654012fSReza Sabdar  * Returns:
22012654012fSReza Sabdar  *   void.
22022654012fSReza Sabdar  */
22032654012fSReza Sabdar /*ARGSUSED*/
22042654012fSReza Sabdar static void
22052654012fSReza Sabdar accept_connection(void *cookie, int fd, ulong_t mode)
22062654012fSReza Sabdar {
22072654012fSReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
22082654012fSReza Sabdar 	struct sockaddr_in from;
22092654012fSReza Sabdar 	int from_len;
22102654012fSReza Sabdar 
22112654012fSReza Sabdar 	from_len = sizeof (from);
22122654012fSReza Sabdar 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
22132654012fSReza Sabdar 	    &from_len);
22142654012fSReza Sabdar 
22152654012fSReza Sabdar 	(void) ndmpd_remove_file_handler(session, fd);
22162654012fSReza Sabdar 	(void) close(session->ns_mover.md_listen_sock);
22172654012fSReza Sabdar 	session->ns_mover.md_listen_sock = -1;
22182654012fSReza Sabdar 
22192654012fSReza Sabdar 	if (session->ns_mover.md_sock < 0) {
22202654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
22212654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
22222654012fSReza Sabdar 		return;
22232654012fSReza Sabdar 	}
222497f7c475SJan Kryl 	set_socket_options(session->ns_mover.md_sock);
22252654012fSReza Sabdar 
22262654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
22272654012fSReza Sabdar 
22282654012fSReza Sabdar 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
22292654012fSReza Sabdar 		if (start_mover_for_backup(session) < 0) {
22302654012fSReza Sabdar 			ndmpd_mover_error(session,
22312654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
22322654012fSReza Sabdar 			return;
22332654012fSReza Sabdar 		}
22342654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
22352654012fSReza Sabdar 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
22362654012fSReza Sabdar 		    ntohs(from.sin_port));
22372654012fSReza Sabdar 	} else {
22382654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
22392654012fSReza Sabdar 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
22402654012fSReza Sabdar 		    ntohs(from.sin_port));
22412654012fSReza Sabdar 	}
22422654012fSReza Sabdar 
22432654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "Received connection");
22442654012fSReza Sabdar 
22452654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
22462654012fSReza Sabdar }
22472654012fSReza Sabdar 
22482654012fSReza Sabdar /*
22492654012fSReza Sabdar  * tape_read
22502654012fSReza Sabdar  *
22512654012fSReza Sabdar  * Reads a data record from tape. Detects and handles EOT conditions.
22522654012fSReza Sabdar  *
22532654012fSReza Sabdar  * Parameters:
22542654012fSReza Sabdar  *   session (input) - session pointer.
22552654012fSReza Sabdar  *   data    (input) - location to read data to.
22562654012fSReza Sabdar  *
22572654012fSReza Sabdar  * Returns:
22582654012fSReza Sabdar  *    0 - operation aborted.
22592654012fSReza Sabdar  *   -1 - tape read error.
22602654012fSReza Sabdar  *   otherwise - number of bytes read.
22612654012fSReza Sabdar  */
22622654012fSReza Sabdar static int
22632654012fSReza Sabdar tape_read(ndmpd_session_t *session, char *data)
22642654012fSReza Sabdar {
22652654012fSReza Sabdar 	ssize_t n;
22662654012fSReza Sabdar 	int err;
22672654012fSReza Sabdar 	int count = session->ns_mover.md_record_size;
22682654012fSReza Sabdar 
22692654012fSReza Sabdar 	for (; ; ) {
22702654012fSReza Sabdar 		n = read(session->ns_tape.td_fd, data, count);
22712654012fSReza Sabdar 		if (n < 0) {
22722654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
22732654012fSReza Sabdar 			return (TAPE_READ_ERR);
22742654012fSReza Sabdar 		}
22752654012fSReza Sabdar 		NS_ADD(rtape, n);
22762654012fSReza Sabdar 
22772654012fSReza Sabdar 		if (n == 0) {
22782654012fSReza Sabdar 			if (!is_writer_running(session))
22792654012fSReza Sabdar 				return (TAPE_NO_WRITER_ERR);
22802654012fSReza Sabdar 
22812654012fSReza Sabdar 			/*
22822654012fSReza Sabdar 			 * End of media reached.
22832654012fSReza Sabdar 			 * Notify client and wait for the client to
22842654012fSReza Sabdar 			 * either abort the data operation or continue the
22852654012fSReza Sabdar 			 * operation after changing the tape.
22862654012fSReza Sabdar 			 */
22872654012fSReza Sabdar 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
22882654012fSReza Sabdar 			    ++ndmp_log_msg_id,
22892654012fSReza Sabdar 			    "End of tape reached. Load next tape");
22902654012fSReza Sabdar 
22912654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
22922654012fSReza Sabdar 			    "End of tape reached. Load next tape");
22932654012fSReza Sabdar 
22942654012fSReza Sabdar 			err = change_tape(session);
22952654012fSReza Sabdar 
22962654012fSReza Sabdar 			/* Operation aborted or connection terminated? */
22972654012fSReza Sabdar 			if (err < 0) {
22982654012fSReza Sabdar 				/*
22992654012fSReza Sabdar 				 * K.L. Go back one record if it is read
23002654012fSReza Sabdar 				 * but not used.
23012654012fSReza Sabdar 				 */
23022654012fSReza Sabdar 
23032654012fSReza Sabdar 				if (count != session->ns_mover.md_record_size) {
23042654012fSReza Sabdar 					(void) ndmp_mtioctl(
23052654012fSReza Sabdar 					    session->ns_tape.td_fd, MTBSR, 1);
23062654012fSReza Sabdar 				}
23072654012fSReza Sabdar 				return (0);
23082654012fSReza Sabdar 			}
23092654012fSReza Sabdar 			/* Retry the read from the new tape. */
23102654012fSReza Sabdar 			continue;
23112654012fSReza Sabdar 		}
23122654012fSReza Sabdar 
23132654012fSReza Sabdar 		/* Change to pass Veritas Netbackup prequal test. */
23142654012fSReza Sabdar 		data += n;
23152654012fSReza Sabdar 		count -= n;
23162654012fSReza Sabdar 		if (count <= 0) {
23172654012fSReza Sabdar 			session->ns_mover.md_record_num++;
23182654012fSReza Sabdar 			session->ns_tape.td_record_count++;
23192654012fSReza Sabdar 			return (n);
23202654012fSReza Sabdar 		}
23212654012fSReza Sabdar 	}
23222654012fSReza Sabdar }
23232654012fSReza Sabdar 
23242654012fSReza Sabdar /*
23252654012fSReza Sabdar  * change_tape
23262654012fSReza Sabdar  *
23272654012fSReza Sabdar  * Send a notify_pause request (protocol version 1) or
23282654012fSReza Sabdar  * notify_mover_pause request (protocol version 2) to the
23292654012fSReza Sabdar  * NDMP client to inform
23302654012fSReza Sabdar  * the client that a tape volume change is required.
23312654012fSReza Sabdar  * Process messages until the data/mover operation is either aborted
23322654012fSReza Sabdar  * or continued.
23332654012fSReza Sabdar  *
23342654012fSReza Sabdar  * Parameters:
23352654012fSReza Sabdar  *   client_data (input) - session pointer.
23362654012fSReza Sabdar  *
23372654012fSReza Sabdar  * Returns:
23382654012fSReza Sabdar  *   0 - operation has been continued.
23392654012fSReza Sabdar  *  -1 - operation has been aborted.
23402654012fSReza Sabdar  */
23412654012fSReza Sabdar static int
23422654012fSReza Sabdar change_tape(ndmpd_session_t *session)
23432654012fSReza Sabdar {
23442654012fSReza Sabdar 	ndmp_notify_mover_paused_request request;
23452654012fSReza Sabdar 
23462654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
23472654012fSReza Sabdar 
23482654012fSReza Sabdar 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
23492654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
23502654012fSReza Sabdar 	else
23512654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
23522654012fSReza Sabdar 
23532654012fSReza Sabdar 	request.reason = session->ns_mover.md_pause_reason;
23542654012fSReza Sabdar 	request.seek_position = long_long_to_quad(0LL);
23552654012fSReza Sabdar 
23562654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
23572654012fSReza Sabdar 	    session->ns_mover.md_pause_reason);
23582654012fSReza Sabdar 
23592654012fSReza Sabdar 	if (ndmp_send_request(session->ns_connection,
23602654012fSReza Sabdar 	    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
23612654012fSReza Sabdar 	    (void *) &request, 0) < 0) {
23622654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
23632654012fSReza Sabdar 		    "Sending notify_mover_paused request");
23642654012fSReza Sabdar 		return (-1);
23652654012fSReza Sabdar 	}
23662654012fSReza Sabdar 	/*
23672654012fSReza Sabdar 	 * Wait for until the state is changed by
23682654012fSReza Sabdar 	 * an abort or continue request.
23692654012fSReza Sabdar 	 */
2370a23888a3SJan Kryl 	return (ndmp_wait_for_mover(session));
23712654012fSReza Sabdar }
23722654012fSReza Sabdar 
23732654012fSReza Sabdar 
23742654012fSReza Sabdar /*
23752654012fSReza Sabdar  * discard_data
23762654012fSReza Sabdar  *
23772654012fSReza Sabdar  * Read and discard data from the data connection.
23782654012fSReza Sabdar  * Called when a module has called ndmpd_seek() prior to
23792654012fSReza Sabdar  * reading all of the data from the previous seek.
23802654012fSReza Sabdar  *
23812654012fSReza Sabdar  * Parameters:
23822654012fSReza Sabdar  *   session (input) - session pointer.
23832654012fSReza Sabdar  *
23842654012fSReza Sabdar  * Returns:
23852654012fSReza Sabdar  *   number of bytes read and discarded.
23862654012fSReza Sabdar  *  -1 - error.
23872654012fSReza Sabdar  */
23882654012fSReza Sabdar static int
23892654012fSReza Sabdar discard_data(ndmpd_session_t *session, ulong_t length)
23902654012fSReza Sabdar {
23912654012fSReza Sabdar 	int n;
23922654012fSReza Sabdar 	char *addr;
23932654012fSReza Sabdar 
23942654012fSReza Sabdar 	if ((addr = ndmp_malloc(length)) == NULL)
23952654012fSReza Sabdar 		return (-1);
23962654012fSReza Sabdar 
23972654012fSReza Sabdar 	/* Read and discard the data. */
23982654012fSReza Sabdar 	n = read(session->ns_mover.md_sock, addr, length);
23992654012fSReza Sabdar 	if (n < 0) {
24002654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
24012654012fSReza Sabdar 		free(addr);
24022654012fSReza Sabdar 		return (-1);
24032654012fSReza Sabdar 	}
24042654012fSReza Sabdar 
24052654012fSReza Sabdar 	free(addr);
24062654012fSReza Sabdar 	return (n);
24072654012fSReza Sabdar }
24082654012fSReza Sabdar 
24092654012fSReza Sabdar 
24102654012fSReza Sabdar /*
24112654012fSReza Sabdar  * mover_tape_read_one_buf
24122654012fSReza Sabdar  *
24132654012fSReza Sabdar  * Read one buffer from the tape. This is used by mover_tape_reader
24142654012fSReza Sabdar  *
24152654012fSReza Sabdar  * Parameters:
24162654012fSReza Sabdar  *   session (input) - session pointer.
24172654012fSReza Sabdar  *   buf (input) - buffer read
24182654012fSReza Sabdar  *
24192654012fSReza Sabdar  * Returns:
24202654012fSReza Sabdar  *   0: on success
24212654012fSReza Sabdar  *  -1: otherwise
24222654012fSReza Sabdar  */
24232654012fSReza Sabdar static int
24242654012fSReza Sabdar mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
24252654012fSReza Sabdar {
24262654012fSReza Sabdar 	int n;
24272654012fSReza Sabdar 
24282654012fSReza Sabdar 	tlm_buffer_mark_empty(buf);
24292654012fSReza Sabdar 
24302654012fSReza Sabdar 	/*
24312654012fSReza Sabdar 	 * If the end of the mover window has been reached,
24322654012fSReza Sabdar 	 * then notify the client that a seek is needed.
24332654012fSReza Sabdar 	 * Remove the file handler to prevent this function from
24342654012fSReza Sabdar 	 * being called. The handler will be reinstalled in
24352654012fSReza Sabdar 	 * ndmpd_mover_continue.
24362654012fSReza Sabdar 	 */
24372654012fSReza Sabdar 
24382654012fSReza Sabdar 	if (session->ns_mover.md_position >=
24392654012fSReza Sabdar 	    session->ns_mover.md_window_offset +
24402654012fSReza Sabdar 	    session->ns_mover.md_window_length) {
24412654012fSReza Sabdar 		ndmp_notify_mover_paused_request pause_request;
24422654012fSReza Sabdar 
24432654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "end of mover window");
24442654012fSReza Sabdar 
24452654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
24462654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
24472654012fSReza Sabdar 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
24482654012fSReza Sabdar 		pause_request.seek_position =
24492654012fSReza Sabdar 		    long_long_to_quad(session->ns_mover.md_position);
24502654012fSReza Sabdar 
24512654012fSReza Sabdar 		if (ndmp_send_request(session->ns_connection,
24522654012fSReza Sabdar 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
24532654012fSReza Sabdar 		    (void *) &pause_request, 0) < 0) {
24542654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
24552654012fSReza Sabdar 			    "Sending notify_mover_paused request");
24562654012fSReza Sabdar 			ndmpd_mover_error(session,
24572654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
24582654012fSReza Sabdar 		}
24592654012fSReza Sabdar 		buf->tb_errno = EIO;
24602654012fSReza Sabdar 		return (TAPE_READ_ERR);
24612654012fSReza Sabdar 	}
24622654012fSReza Sabdar 
24632654012fSReza Sabdar 	n = tape_read(session, buf->tb_buffer_data);
24642654012fSReza Sabdar 
24652654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
24662654012fSReza Sabdar 
24672654012fSReza Sabdar 	if (n <= 0) {
24682654012fSReza Sabdar 		if (n < 0)
24692654012fSReza Sabdar 			ndmpd_mover_error(session,
24702654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
24712654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
24722654012fSReza Sabdar 		return (TAPE_READ_ERR);
24732654012fSReza Sabdar 	}
24742654012fSReza Sabdar 
24752654012fSReza Sabdar 	buf->tb_full = TRUE;
24762654012fSReza Sabdar 	buf->tb_buffer_size = session->ns_mover.md_record_size;
24772654012fSReza Sabdar 
24782654012fSReza Sabdar 	/*
24792654012fSReza Sabdar 	 * Discard data if the current data stream position is
24802654012fSReza Sabdar 	 * prior to the seek position. This is necessary if a seek
24812654012fSReza Sabdar 	 * request set the seek pointer to a position that is not a
24822654012fSReza Sabdar 	 * record boundary. The seek request handler can only position
24832654012fSReza Sabdar 	 * to the start of a record.
24842654012fSReza Sabdar 	 */
24852654012fSReza Sabdar 	if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
24862654012fSReza Sabdar 		session->ns_mover.md_position =
24872654012fSReza Sabdar 		    session->ns_mover.md_seek_position;
24882654012fSReza Sabdar 
24892654012fSReza Sabdar 	return (0);
24902654012fSReza Sabdar }
24912654012fSReza Sabdar 
24922654012fSReza Sabdar 
24932654012fSReza Sabdar /*
24942654012fSReza Sabdar  * mover_tape_reader
24952654012fSReza Sabdar  *
24962654012fSReza Sabdar  * Mover tape reader thread. It is launched when the mover is started
24972654012fSReza Sabdar  * for restore.
24982654012fSReza Sabdar  *
24992654012fSReza Sabdar  * Parameters:
25002654012fSReza Sabdar  *   session (input) - session pointer.
25012654012fSReza Sabdar  *
25022654012fSReza Sabdar  * Returns:
25032654012fSReza Sabdar  *   0: on success
25042654012fSReza Sabdar  *  -1: otherwise
25052654012fSReza Sabdar  */
25062654012fSReza Sabdar int
25072654012fSReza Sabdar mover_tape_reader(ndmpd_session_t *session)
25082654012fSReza Sabdar {
25092654012fSReza Sabdar 	int bidx;	/* buffer index */
25102654012fSReza Sabdar 	int rv;
25112654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
25122654012fSReza Sabdar 	tlm_buffer_t *buf;
25132654012fSReza Sabdar 	tlm_buffers_t *bufs;
25142654012fSReza Sabdar 	tlm_cmd_t *lcmd;	/* Local command */
25152654012fSReza Sabdar 	tlm_commands_t *cmds;	/* Commands structure */
25162654012fSReza Sabdar 
25172654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
25182654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
25192654012fSReza Sabdar 		return (-1);
25202654012fSReza Sabdar 	}
25212654012fSReza Sabdar 
25222654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
25232654012fSReza Sabdar 	lcmd = cmds->tcs_command;
25242654012fSReza Sabdar 	bufs = lcmd->tc_buffers;
25252654012fSReza Sabdar 
25262654012fSReza Sabdar 	lcmd->tc_ref++;
25272654012fSReza Sabdar 	cmds->tcs_reader_count++;
25282654012fSReza Sabdar 
25292654012fSReza Sabdar 	/*
25302654012fSReza Sabdar 	 * Let our parent thread know that we are running.
25312654012fSReza Sabdar 	 */
25322654012fSReza Sabdar 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
25332654012fSReza Sabdar 
25342654012fSReza Sabdar 	buf = tlm_buffer_in_buf(bufs, &bidx);
25352654012fSReza Sabdar 	while (cmds->tcs_reader == TLM_RESTORE_RUN &&
25362654012fSReza Sabdar 	    lcmd->tc_reader == TLM_RESTORE_RUN) {
25372654012fSReza Sabdar 		buf = tlm_buffer_in_buf(bufs, NULL);
25382654012fSReza Sabdar 
25392654012fSReza Sabdar 		if (buf->tb_full) {
25402654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
25412654012fSReza Sabdar 			/*
25422654012fSReza Sabdar 			 * The buffer is still full, wait for the consumer
25432654012fSReza Sabdar 			 * thread to use it.
25442654012fSReza Sabdar 			 */
25452654012fSReza Sabdar 			tlm_buffer_out_buf_timed_wait(bufs, 100);
25462654012fSReza Sabdar 
25472654012fSReza Sabdar 		} else {
25482654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "r%d", bidx);
25492654012fSReza Sabdar 
25502654012fSReza Sabdar 			rv = mover_tape_read_one_buf(session, buf);
25512654012fSReza Sabdar 			/*
25522654012fSReza Sabdar 			 * If there was an error while reading, such as
25532654012fSReza Sabdar 			 * end of stream.
25542654012fSReza Sabdar 			 */
25552654012fSReza Sabdar 			if (rv < 0) {
25562654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
25572654012fSReza Sabdar 				break;
25582654012fSReza Sabdar 			}
25592654012fSReza Sabdar 
25602654012fSReza Sabdar 			/*
25612654012fSReza Sabdar 			 * Can we do more buffering?
25622654012fSReza Sabdar 			 */
25632654012fSReza Sabdar 			if (is_buffer_erroneous(buf)) {
25642654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
25652654012fSReza Sabdar 				    "Exiting, errno: %d, eot: %d, eof: %d",
25662654012fSReza Sabdar 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
25672654012fSReza Sabdar 				break;
25682654012fSReza Sabdar 			}
25692654012fSReza Sabdar 
25702654012fSReza Sabdar 			(void) tlm_buffer_advance_in_idx(bufs);
25712654012fSReza Sabdar 			tlm_buffer_release_in_buf(bufs);
25722654012fSReza Sabdar 			bidx = bufs->tbs_buffer_in;
25732654012fSReza Sabdar 		}
25742654012fSReza Sabdar 	}
25752654012fSReza Sabdar 
25762654012fSReza Sabdar 	/* If the consumer is waiting for us, wake it up. */
25772654012fSReza Sabdar 	tlm_buffer_release_in_buf(bufs);
25782654012fSReza Sabdar 
25792654012fSReza Sabdar 	/*
25802654012fSReza Sabdar 	 * Clean up.
25812654012fSReza Sabdar 	 */
25822654012fSReza Sabdar 	cmds->tcs_reader_count--;
25832654012fSReza Sabdar 	lcmd->tc_ref--;
25842654012fSReza Sabdar 	lcmd->tc_writer = TLM_STOP;
25852654012fSReza Sabdar 	return (0);
25862654012fSReza Sabdar }
25872654012fSReza Sabdar 
25882654012fSReza Sabdar 
25892654012fSReza Sabdar /*
25902654012fSReza Sabdar  * mover_socket_write_one_buf
25912654012fSReza Sabdar  *
25922654012fSReza Sabdar  * Write one buffer to the network socket. This is used by mover_socket_writer
25932654012fSReza Sabdar  *
25942654012fSReza Sabdar  * Parameters:
25952654012fSReza Sabdar  *   session (input) - session pointer.
25962654012fSReza Sabdar  *   buf (input) - buffer read
25972654012fSReza Sabdar  *
25982654012fSReza Sabdar  * Returns:
25992654012fSReza Sabdar  *   0: on success
26002654012fSReza Sabdar  *  -1: otherwise
26012654012fSReza Sabdar  */
26022654012fSReza Sabdar static int
26032654012fSReza Sabdar mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
26042654012fSReza Sabdar {
26052654012fSReza Sabdar 	int n;
26062654012fSReza Sabdar 
26072654012fSReza Sabdar 	/* Write the data to the data connection. */
26082654012fSReza Sabdar 	errno = 0;
26092654012fSReza Sabdar 	n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
26102654012fSReza Sabdar 	    buf->tb_buffer_size);
26112654012fSReza Sabdar 
26122654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
26132654012fSReza Sabdar 
26142654012fSReza Sabdar 	if (n < 0) {
26152654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
26162654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
26172654012fSReza Sabdar 		return (-1);
26182654012fSReza Sabdar 	}
26192654012fSReza Sabdar 
26202654012fSReza Sabdar 	session->ns_mover.md_position += n;
26212654012fSReza Sabdar 	session->ns_mover.md_bytes_left_to_read -= n;
26222654012fSReza Sabdar 	tlm_buffer_mark_empty(buf);
26232654012fSReza Sabdar 
26242654012fSReza Sabdar 	/*
26252654012fSReza Sabdar 	 * If the read limit has been reached,
26262654012fSReza Sabdar 	 * then remove the file handler to prevent this
26272654012fSReza Sabdar 	 * function from getting called. The next mover_read request
26282654012fSReza Sabdar 	 * will reinstall the handler.
26292654012fSReza Sabdar 	 */
26302654012fSReza Sabdar 	if (session->ns_mover.md_bytes_left_to_read == 0) {
26312654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
26322654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
26332654012fSReza Sabdar 		    session->ns_mover.md_sock);
26342654012fSReza Sabdar 		return (-1);
26352654012fSReza Sabdar 	}
26362654012fSReza Sabdar 
26372654012fSReza Sabdar 	return (0);
26382654012fSReza Sabdar }
26392654012fSReza Sabdar 
26402654012fSReza Sabdar 
26412654012fSReza Sabdar 
26422654012fSReza Sabdar /*
26432654012fSReza Sabdar  * mover_socket_writer
26442654012fSReza Sabdar  *
26452654012fSReza Sabdar  * Mover's socket writer thread. This thread sends the read buffer
26462654012fSReza Sabdar  * from the tape to the data server through the network socket.
26472654012fSReza Sabdar  *
26482654012fSReza Sabdar  * Parameters:
26492654012fSReza Sabdar  *   session (input) - session pointer.
26502654012fSReza Sabdar  *
26512654012fSReza Sabdar  * Returns:
26522654012fSReza Sabdar  *   0: on success
26532654012fSReza Sabdar  *  -1: otherwise
26542654012fSReza Sabdar  */
26552654012fSReza Sabdar int
26562654012fSReza Sabdar mover_socket_writer(ndmpd_session_t *session)
26572654012fSReza Sabdar {
26582654012fSReza Sabdar 	int bidx;	/* buffer index */
26592654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
26602654012fSReza Sabdar 	tlm_buffer_t *buf;
26612654012fSReza Sabdar 	tlm_buffers_t *bufs;
26622654012fSReza Sabdar 	tlm_cmd_t *lcmd;	/* Local command */
26632654012fSReza Sabdar 	tlm_commands_t *cmds;	/* Commands structure */
26642654012fSReza Sabdar 
26652654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
26662654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
26672654012fSReza Sabdar 		return (-1);
26682654012fSReza Sabdar 	}
26692654012fSReza Sabdar 
26702654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
26712654012fSReza Sabdar 	lcmd = cmds->tcs_command;
26722654012fSReza Sabdar 	bufs = lcmd->tc_buffers;
26732654012fSReza Sabdar 
26742654012fSReza Sabdar 	lcmd->tc_ref++;
26752654012fSReza Sabdar 	cmds->tcs_writer_count++;
26762654012fSReza Sabdar 
26772654012fSReza Sabdar 	/*
26782654012fSReza Sabdar 	 * Let our parent thread know that we are running.
26792654012fSReza Sabdar 	 */
26802654012fSReza Sabdar 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
26812654012fSReza Sabdar 
26822654012fSReza Sabdar 	bidx = bufs->tbs_buffer_out;
26832654012fSReza Sabdar 	while (cmds->tcs_writer != (int)TLM_ABORT &&
26842654012fSReza Sabdar 	    lcmd->tc_writer != (int)TLM_ABORT) {
26852654012fSReza Sabdar 		buf = &bufs->tbs_buffer[bidx];
26862654012fSReza Sabdar 
26872654012fSReza Sabdar 		if (buf->tb_full) {
26882654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "w%d", bidx);
26892654012fSReza Sabdar 
26902654012fSReza Sabdar 			if (mover_socket_write_one_buf(session, buf) < 0) {
26912654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
26922654012fSReza Sabdar 				    "mover_socket_write_one_buf() < 0");
26932654012fSReza Sabdar 				break;
26942654012fSReza Sabdar 			}
26952654012fSReza Sabdar 
26962654012fSReza Sabdar 			(void) tlm_buffer_advance_out_idx(bufs);
26972654012fSReza Sabdar 			tlm_buffer_release_out_buf(bufs);
26982654012fSReza Sabdar 			bidx = bufs->tbs_buffer_out;
26992654012fSReza Sabdar 		} else {
27002654012fSReza Sabdar 			if (lcmd->tc_writer != TLM_RESTORE_RUN) {
27012654012fSReza Sabdar 				/* No more data is coming, time to exit */
27022654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Time to exit");
27032654012fSReza Sabdar 				break;
27042654012fSReza Sabdar 			}
27052654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
27062654012fSReza Sabdar 			/*
27072654012fSReza Sabdar 			 * The buffer is not full, wait for the producer
27082654012fSReza Sabdar 			 * thread to fill it.
27092654012fSReza Sabdar 			 */
271086c48bbfSReza Sabdar 			tlm_buffer_in_buf_timed_wait(bufs, 100);
27112654012fSReza Sabdar 		}
27122654012fSReza Sabdar 	}
27132654012fSReza Sabdar 
27142654012fSReza Sabdar 	if (cmds->tcs_writer == (int)TLM_ABORT)
27152654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
27162654012fSReza Sabdar 	if (lcmd->tc_writer == (int)TLM_ABORT)
27172654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
27182654012fSReza Sabdar 
27192654012fSReza Sabdar 	/* If the producer is waiting for us, wake it up. */
27202654012fSReza Sabdar 	tlm_buffer_release_out_buf(bufs);
27212654012fSReza Sabdar 
27222654012fSReza Sabdar 	/*
27232654012fSReza Sabdar 	 * Clean up.
27242654012fSReza Sabdar 	 */
27252654012fSReza Sabdar 	cmds->tcs_writer_count--;
27262654012fSReza Sabdar 	lcmd->tc_ref--;
27272654012fSReza Sabdar 	lcmd->tc_reader = TLM_STOP;
27282654012fSReza Sabdar 	return (0);
27292654012fSReza Sabdar }
27302654012fSReza Sabdar 
27312654012fSReza Sabdar 
27322654012fSReza Sabdar /*
27332654012fSReza Sabdar  * start_mover_for_restore
27342654012fSReza Sabdar  *
27352654012fSReza Sabdar  * Creates the mover tape reader and network writer threads for
27362654012fSReza Sabdar  * the mover to perform the 3-way restore.
27372654012fSReza Sabdar  *
27382654012fSReza Sabdar  * Parameters:
27392654012fSReza Sabdar  *   session (input) - session pointer.
27402654012fSReza Sabdar  *
27412654012fSReza Sabdar  * Returns:
27422654012fSReza Sabdar  *   0: on success
27432654012fSReza Sabdar  *  -1: otherwise
27442654012fSReza Sabdar  */
27452654012fSReza Sabdar static int
27462654012fSReza Sabdar start_mover_for_restore(ndmpd_session_t *session)
27472654012fSReza Sabdar {
27482654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
27492654012fSReza Sabdar 	tlm_commands_t *cmds;
27502654012fSReza Sabdar 	long xfer_size;
27512654012fSReza Sabdar 	int rc;
27522654012fSReza Sabdar 
27532654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
27542654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
27552654012fSReza Sabdar 		return (-1);
27562654012fSReza Sabdar 	}
27572654012fSReza Sabdar 
27582654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
27592654012fSReza Sabdar 	(void) memset(cmds, 0, sizeof (*cmds));
27602654012fSReza Sabdar 	cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
27612654012fSReza Sabdar 	xfer_size = ndmp_buffer_get_size(session);
27622654012fSReza Sabdar 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
27632654012fSReza Sabdar 	if (cmds->tcs_command == NULL)
27642654012fSReza Sabdar 		return (-1);
27652654012fSReza Sabdar 
27662654012fSReza Sabdar 	cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
27672654012fSReza Sabdar 	cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
27682654012fSReza Sabdar 
27692654012fSReza Sabdar 	/*
27702654012fSReza Sabdar 	 * We intentionnally don't wait for the threads to start since the
27712654012fSReza Sabdar 	 * reply of the request (which resulted in calling this function)
27722654012fSReza Sabdar 	 * must be sent to the client before probable errors are sent
27732654012fSReza Sabdar 	 * to the client.
27742654012fSReza Sabdar 	 */
27752654012fSReza Sabdar 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session);
27762654012fSReza Sabdar 	if (rc == 0) {
27772654012fSReza Sabdar 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
27782654012fSReza Sabdar 	} else {
27792654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
27802654012fSReza Sabdar 		    strerror(rc));
27812654012fSReza Sabdar 		return (-1);
27822654012fSReza Sabdar 	}
27832654012fSReza Sabdar 
27842654012fSReza Sabdar 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session);
27852654012fSReza Sabdar 	if (rc == 0) {
27862654012fSReza Sabdar 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
27872654012fSReza Sabdar 	} else {
27882654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
27892654012fSReza Sabdar 		    strerror(rc));
27902654012fSReza Sabdar 		return (-1);
27912654012fSReza Sabdar 	}
27922654012fSReza Sabdar 
27932654012fSReza Sabdar 	tlm_release_reader_writer_ipc(cmds->tcs_command);
27942654012fSReza Sabdar 	return (0);
27952654012fSReza Sabdar }
27962654012fSReza Sabdar 
27972654012fSReza Sabdar 
27982654012fSReza Sabdar /*
27992654012fSReza Sabdar  * mover_socket_read_one_buf
28002654012fSReza Sabdar  *
28012654012fSReza Sabdar  * Read one buffer from the network socket for the mover. This is used
28022654012fSReza Sabdar  * by mover_socket_reader
28032654012fSReza Sabdar  *
28042654012fSReza Sabdar  * Parameters:
28052654012fSReza Sabdar  *   session (input) - session pointer.
28062654012fSReza Sabdar  *   buf (input) - buffer read
28072654012fSReza Sabdar  *   read_size (input) - size to be read
28082654012fSReza Sabdar  *
28092654012fSReza Sabdar  * Returns:
28102654012fSReza Sabdar  *   0: on success
28112654012fSReza Sabdar  *  -1: otherwise
28122654012fSReza Sabdar  */
28132654012fSReza Sabdar static int
28142654012fSReza Sabdar mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
28152654012fSReza Sabdar     long read_size)
28162654012fSReza Sabdar {
28172654012fSReza Sabdar 	int n, index;
28182654012fSReza Sabdar 	long toread;
28192654012fSReza Sabdar 
28202654012fSReza Sabdar 	tlm_buffer_mark_empty(buf);
28212654012fSReza Sabdar 	for (index = 0, toread = read_size; toread > 0; ) {
28222654012fSReza Sabdar 		errno = 0;
28232654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
28242654012fSReza Sabdar 
28252654012fSReza Sabdar 		n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
28262654012fSReza Sabdar 		    toread);
28272654012fSReza Sabdar 		if (n == 0) {
28282654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
28292654012fSReza Sabdar 			break;
28302654012fSReza Sabdar 		} else if (n > 0) {
28312654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
28322654012fSReza Sabdar 			index += n;
28332654012fSReza Sabdar 			toread -= n;
28342654012fSReza Sabdar 		} else {
28352654012fSReza Sabdar 			buf->tb_eof = TRUE;
28362654012fSReza Sabdar 			buf->tb_errno = errno;
28372654012fSReza Sabdar 			buf->tb_buffer_size = 0;
28382654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
28392654012fSReza Sabdar 			return (-1);
28402654012fSReza Sabdar 		}
28412654012fSReza Sabdar 	}
28422654012fSReza Sabdar 
28432654012fSReza Sabdar 	if (index > 0) {
28442654012fSReza Sabdar 		buf->tb_full = TRUE;
28452654012fSReza Sabdar 		buf->tb_buffer_size = read_size;
28462654012fSReza Sabdar 		if (read_size > 0)
28472654012fSReza Sabdar 			(void) memset(&buf->tb_buffer_data[index], 0,
28482654012fSReza Sabdar 			    read_size - index);
28492654012fSReza Sabdar 	} else {
28502654012fSReza Sabdar 		buf->tb_eof = TRUE;
28512654012fSReza Sabdar 		buf->tb_buffer_size = 0;
28522654012fSReza Sabdar 	}
28532654012fSReza Sabdar 
28542654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
28552654012fSReza Sabdar 	    " errno: %d, size: %d, data: 0x%x",
28562654012fSReza Sabdar 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
28572654012fSReza Sabdar 	    buf->tb_buffer_size, buf->tb_buffer_data);
28582654012fSReza Sabdar 
28592654012fSReza Sabdar 	return (0);
28602654012fSReza Sabdar }
28612654012fSReza Sabdar 
28622654012fSReza Sabdar 
28632654012fSReza Sabdar 
28642654012fSReza Sabdar /*
28652654012fSReza Sabdar  * mover_socket_reader
28662654012fSReza Sabdar  *
28672654012fSReza Sabdar  * Mover socket reader thread. This is used when reading data from the
28682654012fSReza Sabdar  * network socket for performing remote backups.
28692654012fSReza Sabdar  *
28702654012fSReza Sabdar  * Parameters:
28712654012fSReza Sabdar  *   session (input) - session pointer.
28722654012fSReza Sabdar  *
28732654012fSReza Sabdar  * Returns:
28742654012fSReza Sabdar  *   0: on success
28752654012fSReza Sabdar  *  -1: otherwise
28762654012fSReza Sabdar  */
28772654012fSReza Sabdar int
28782654012fSReza Sabdar mover_socket_reader(ndmpd_session_t *session)
28792654012fSReza Sabdar {
28802654012fSReza Sabdar 	int bidx;	/* buffer index */
28812654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
28822654012fSReza Sabdar 	tlm_buffer_t *buf;
28832654012fSReza Sabdar 	tlm_buffers_t *bufs;
28842654012fSReza Sabdar 	tlm_cmd_t *lcmd;	/* Local command */
28852654012fSReza Sabdar 	tlm_commands_t *cmds;	/* Commands structure */
28862654012fSReza Sabdar 	static int nr = 0;
28872654012fSReza Sabdar 
28882654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
28892654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
28902654012fSReza Sabdar 		return (-1);
28912654012fSReza Sabdar 	}
28922654012fSReza Sabdar 
28932654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
28942654012fSReza Sabdar 	lcmd = cmds->tcs_command;
28952654012fSReza Sabdar 	bufs = lcmd->tc_buffers;
28962654012fSReza Sabdar 
28972654012fSReza Sabdar 	lcmd->tc_ref++;
28982654012fSReza Sabdar 	cmds->tcs_reader_count++;
28992654012fSReza Sabdar 
29002654012fSReza Sabdar 	/*
29012654012fSReza Sabdar 	 * Let our parent thread know that we are running.
29022654012fSReza Sabdar 	 */
29032654012fSReza Sabdar 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
29042654012fSReza Sabdar 
29052654012fSReza Sabdar 	bidx = bufs->tbs_buffer_in;
29062654012fSReza Sabdar 	while (cmds->tcs_reader == TLM_BACKUP_RUN &&
29072654012fSReza Sabdar 	    lcmd->tc_reader == TLM_BACKUP_RUN) {
29082654012fSReza Sabdar 		buf = &bufs->tbs_buffer[bidx];
29092654012fSReza Sabdar 
29102654012fSReza Sabdar 		if (buf->tb_full) {
29112654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
29122654012fSReza Sabdar 			/*
29132654012fSReza Sabdar 			 * The buffer is still full, wait for the consumer
29142654012fSReza Sabdar 			 * thread to use it.
29152654012fSReza Sabdar 			 */
29162654012fSReza Sabdar 			tlm_buffer_out_buf_timed_wait(bufs, 100);
29172654012fSReza Sabdar 		} else {
29182654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
29192654012fSReza Sabdar 
29202654012fSReza Sabdar 			(void) mover_socket_read_one_buf(session, buf,
29212654012fSReza Sabdar 			    bufs->tbs_data_transfer_size);
29222654012fSReza Sabdar 
29232654012fSReza Sabdar 			/*
29242654012fSReza Sabdar 			 * Can we do more buffering?
29252654012fSReza Sabdar 			 */
29262654012fSReza Sabdar 			if (is_buffer_erroneous(buf)) {
29272654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
29282654012fSReza Sabdar 				    "Exiting, errno: %d, eot: %d, eof: %d",
29292654012fSReza Sabdar 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
29302654012fSReza Sabdar 				break;
29312654012fSReza Sabdar 			}
29322654012fSReza Sabdar 
29332654012fSReza Sabdar 			(void) tlm_buffer_advance_in_idx(bufs);
29342654012fSReza Sabdar 			tlm_buffer_release_in_buf(bufs);
29352654012fSReza Sabdar 			bidx = bufs->tbs_buffer_in;
29362654012fSReza Sabdar 		}
29372654012fSReza Sabdar 	}
29382654012fSReza Sabdar 
29392654012fSReza Sabdar 	if (cmds->tcs_reader != TLM_BACKUP_RUN)
29402654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
29412654012fSReza Sabdar 	if (lcmd->tc_reader != TLM_BACKUP_RUN)
29422654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
29432654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
29442654012fSReza Sabdar 
29452654012fSReza Sabdar 	/* If the consumer is waiting for us, wake it up. */
29462654012fSReza Sabdar 	tlm_buffer_release_in_buf(bufs);
29472654012fSReza Sabdar 
29482654012fSReza Sabdar 	/*
29492654012fSReza Sabdar 	 * Clean up.
29502654012fSReza Sabdar 	 */
29512654012fSReza Sabdar 	cmds->tcs_reader_count--;
29522654012fSReza Sabdar 	lcmd->tc_ref--;
29532654012fSReza Sabdar 	lcmd->tc_writer = TLM_STOP;
29542654012fSReza Sabdar 	return (0);
29552654012fSReza Sabdar }
29562654012fSReza Sabdar 
29572654012fSReza Sabdar 
29582654012fSReza Sabdar /*
29592654012fSReza Sabdar  * mover_tape_writer_one_buf
29602654012fSReza Sabdar  *
29612654012fSReza Sabdar  * Write one buffer for the mover to the local tape device. This is
29622654012fSReza Sabdar  * used by mover_tape_writer thread.
29632654012fSReza Sabdar  *
29642654012fSReza Sabdar  * Parameters:
29652654012fSReza Sabdar  *   session (input) - session pointer.
29662654012fSReza Sabdar  *   buf (input) - buffer read
29672654012fSReza Sabdar  *
29682654012fSReza Sabdar  * Returns:
29692654012fSReza Sabdar  *   0: on success
29702654012fSReza Sabdar  *  -1: otherwise
29712654012fSReza Sabdar  */
29722654012fSReza Sabdar static int
29732654012fSReza Sabdar mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
29742654012fSReza Sabdar {
29752654012fSReza Sabdar 	int n;
29762654012fSReza Sabdar 
29772654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
29782654012fSReza Sabdar 	    " errno: %d, size: %d, data: 0x%x",
29792654012fSReza Sabdar 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
29802654012fSReza Sabdar 	    buf->tb_buffer_size, buf->tb_buffer_data);
29812654012fSReza Sabdar 
29829ee94b97SJan Kryl 	n = mover_tape_write_v3(session, buf->tb_buffer_data,
29839ee94b97SJan Kryl 	    buf->tb_buffer_size);
29842654012fSReza Sabdar 
29852654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "n: %d", n);
29862654012fSReza Sabdar 
29872654012fSReza Sabdar 	if (n <= 0) {
29882654012fSReza Sabdar 		ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
29892654012fSReza Sabdar 		    : NDMP_MOVER_HALT_INTERNAL_ERROR));
29902654012fSReza Sabdar 		return (-1);
29912654012fSReza Sabdar 	}
29922654012fSReza Sabdar 	session->ns_mover.md_position += n;
29932654012fSReza Sabdar 	session->ns_mover.md_data_written += n;
29942654012fSReza Sabdar 	session->ns_mover.md_record_num++;
29952654012fSReza Sabdar 
29962654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
29972654012fSReza Sabdar 	tlm_buffer_mark_empty(buf);
29982654012fSReza Sabdar 
29992654012fSReza Sabdar 	return (0);
30002654012fSReza Sabdar }
30012654012fSReza Sabdar 
30022654012fSReza Sabdar 
30032654012fSReza Sabdar /*
30042654012fSReza Sabdar  * mover_tape_writer
30052654012fSReza Sabdar  *
30062654012fSReza Sabdar  * Mover tape writer thread. This is used for performing remote backups
30072654012fSReza Sabdar  * in a 3-way configuration. It writes the data from network socket to
30082654012fSReza Sabdar  * the locally attached tape device.
30092654012fSReza Sabdar  *
30102654012fSReza Sabdar  * Parameters:
30112654012fSReza Sabdar  *   session (input) - session pointer.
30122654012fSReza Sabdar  *
30132654012fSReza Sabdar  * Returns:
30142654012fSReza Sabdar  *   0: on success
30152654012fSReza Sabdar  *  -1: otherwise
30162654012fSReza Sabdar  */
30172654012fSReza Sabdar int
30182654012fSReza Sabdar mover_tape_writer(ndmpd_session_t *session)
30192654012fSReza Sabdar {
30202654012fSReza Sabdar 	int bidx;
30212654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
30222654012fSReza Sabdar 	tlm_buffer_t *buf;
30232654012fSReza Sabdar 	tlm_buffers_t *bufs;
30242654012fSReza Sabdar 	tlm_cmd_t *lcmd;
30252654012fSReza Sabdar 	tlm_commands_t *cmds;
30262654012fSReza Sabdar 	static int nw = 0;
30272654012fSReza Sabdar 
30282654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
30292654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
30302654012fSReza Sabdar 		return (-1);
30312654012fSReza Sabdar 	}
30322654012fSReza Sabdar 
30332654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
30342654012fSReza Sabdar 	lcmd = cmds->tcs_command;
30352654012fSReza Sabdar 	bufs = lcmd->tc_buffers;
30362654012fSReza Sabdar 
30372654012fSReza Sabdar 	lcmd->tc_ref++;
30382654012fSReza Sabdar 	cmds->tcs_writer_count++;
30392654012fSReza Sabdar 
30402654012fSReza Sabdar 	/*
30412654012fSReza Sabdar 	 * Let our parent thread know that we are running.
30422654012fSReza Sabdar 	 */
30432654012fSReza Sabdar 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
30442654012fSReza Sabdar 
30452654012fSReza Sabdar 	bidx = bufs->tbs_buffer_out;
30462654012fSReza Sabdar 	buf = &bufs->tbs_buffer[bidx];
30472654012fSReza Sabdar 	while (cmds->tcs_writer != (int)TLM_ABORT &&
30482654012fSReza Sabdar 	    lcmd->tc_writer != (int)TLM_ABORT) {
30492654012fSReza Sabdar 		if (buf->tb_full) {
30502654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
30512654012fSReza Sabdar 
30522654012fSReza Sabdar 			if (mover_tape_write_one_buf(session, buf) < 0) {
30532654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
30542654012fSReza Sabdar 				    "mover_tape_write_one_buf() failed");
30552654012fSReza Sabdar 				break;
30562654012fSReza Sabdar 			}
30572654012fSReza Sabdar 
30582654012fSReza Sabdar 			(void) tlm_buffer_advance_out_idx(bufs);
30592654012fSReza Sabdar 			tlm_buffer_release_out_buf(bufs);
30602654012fSReza Sabdar 			bidx = bufs->tbs_buffer_out;
30612654012fSReza Sabdar 			buf = &bufs->tbs_buffer[bidx];
30622654012fSReza Sabdar 		} else {
30632654012fSReza Sabdar 			if (lcmd->tc_writer != TLM_BACKUP_RUN) {
30642654012fSReza Sabdar 				/* No more data is coming, time to exit */
30652654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "Time to exit");
30662654012fSReza Sabdar 				break;
30672654012fSReza Sabdar 			}
30682654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
30692654012fSReza Sabdar 			/*
30702654012fSReza Sabdar 			 * The buffer is not full, wait for the producer
30712654012fSReza Sabdar 			 * thread to fill it.
30722654012fSReza Sabdar 			 */
30732654012fSReza Sabdar 			tlm_buffer_in_buf_timed_wait(bufs, 100);
30742654012fSReza Sabdar 		}
30752654012fSReza Sabdar 	}
30762654012fSReza Sabdar 
30772654012fSReza Sabdar 	if (cmds->tcs_writer == (int)TLM_ABORT)
30782654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
30792654012fSReza Sabdar 	if (lcmd->tc_writer == (int)TLM_ABORT)
30802654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
30812654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
30822654012fSReza Sabdar 
30832654012fSReza Sabdar 	if (buf->tb_errno == 0) {
30842654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
30852654012fSReza Sabdar 	} else {
30862654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
30872654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
30882654012fSReza Sabdar 	}
30892654012fSReza Sabdar 
30902654012fSReza Sabdar 	/* If the producer is waiting for us, wake it up. */
30912654012fSReza Sabdar 	tlm_buffer_release_out_buf(bufs);
30922654012fSReza Sabdar 
30932654012fSReza Sabdar 	/*
30942654012fSReza Sabdar 	 * Clean up.
30952654012fSReza Sabdar 	 */
30962654012fSReza Sabdar 	cmds->tcs_writer_count--;
30972654012fSReza Sabdar 	lcmd->tc_ref--;
30982654012fSReza Sabdar 	lcmd->tc_reader = TLM_STOP;
30992654012fSReza Sabdar 	return (0);
31002654012fSReza Sabdar }
31012654012fSReza Sabdar 
31022654012fSReza Sabdar 
31032654012fSReza Sabdar /*
31042654012fSReza Sabdar  * start_mover_for_backup
31052654012fSReza Sabdar  *
31062654012fSReza Sabdar  * Starts a remote backup by running socket reader and tape
31072654012fSReza Sabdar  * writer threads. The mover runs a remote backup in a 3-way backup
31082654012fSReza Sabdar  * configuration.
31092654012fSReza Sabdar  *
31102654012fSReza Sabdar  * Parameters:
31112654012fSReza Sabdar  *   session (input) - session pointer.
31122654012fSReza Sabdar  *
31132654012fSReza Sabdar  * Returns:
31142654012fSReza Sabdar  *   0: on success
31152654012fSReza Sabdar  *  -1: otherwise
31162654012fSReza Sabdar  */
31172654012fSReza Sabdar static int
31182654012fSReza Sabdar start_mover_for_backup(ndmpd_session_t *session)
31192654012fSReza Sabdar {
31202654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
31212654012fSReza Sabdar 	tlm_commands_t *cmds;
31222654012fSReza Sabdar 	int rc;
31232654012fSReza Sabdar 
31242654012fSReza Sabdar 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
31252654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
31262654012fSReza Sabdar 		return (-1);
31272654012fSReza Sabdar 	}
31282654012fSReza Sabdar 
31292654012fSReza Sabdar 	cmds = &nlp->nlp_cmds;
31302654012fSReza Sabdar 	(void) memset(cmds, 0, sizeof (*cmds));
31312654012fSReza Sabdar 	cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
31322654012fSReza Sabdar 	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
31332654012fSReza Sabdar 	    session->ns_mover.md_record_size);
31342654012fSReza Sabdar 	if (cmds->tcs_command == NULL)
31352654012fSReza Sabdar 		return (-1);
31362654012fSReza Sabdar 
31372654012fSReza Sabdar 	cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
31382654012fSReza Sabdar 	cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
31392654012fSReza Sabdar 
31402654012fSReza Sabdar 	/*
31412654012fSReza Sabdar 	 * We intentionally don't wait for the threads to start since the
31422654012fSReza Sabdar 	 * reply of the request (which resulted in calling this function)
31432654012fSReza Sabdar 	 * must be sent to the client before probable errors are sent
31442654012fSReza Sabdar 	 * to the client.
31452654012fSReza Sabdar 	 */
31462654012fSReza Sabdar 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session);
31472654012fSReza Sabdar 	if (rc == 0) {
31482654012fSReza Sabdar 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
31492654012fSReza Sabdar 	} else {
31502654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
31512654012fSReza Sabdar 		    strerror(rc));
31522654012fSReza Sabdar 		return (-1);
31532654012fSReza Sabdar 	}
31542654012fSReza Sabdar 
31552654012fSReza Sabdar 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session);
31562654012fSReza Sabdar 	if (rc == 0) {
31572654012fSReza Sabdar 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
31582654012fSReza Sabdar 	} else {
31592654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
31602654012fSReza Sabdar 		    strerror(rc));
31612654012fSReza Sabdar 		return (-1);
31622654012fSReza Sabdar 	}
31632654012fSReza Sabdar 
31642654012fSReza Sabdar 	tlm_release_reader_writer_ipc(cmds->tcs_command);
31652654012fSReza Sabdar 	return (0);
31662654012fSReza Sabdar }
31672654012fSReza Sabdar 
31682654012fSReza Sabdar 
31692654012fSReza Sabdar /*
31702654012fSReza Sabdar  * is_writer_running
31712654012fSReza Sabdar  *
31722654012fSReza Sabdar  * Find out if the writer thread has started or not.
31732654012fSReza Sabdar  *
31742654012fSReza Sabdar  * Parameters:
31752654012fSReza Sabdar  *   session (input) - session pointer.
31762654012fSReza Sabdar  *
31772654012fSReza Sabdar  * Returns:
31782654012fSReza Sabdar  *   0: not started
31792654012fSReza Sabdar  *   non-zero: started
31808c4f9701SJanice Chang  *	Note: non-zero is also returned if the backup type is
31818c4f9701SJanice Chang  *		neither TAR nor DUMP.  I.e. the is_writer_running()
31828c4f9701SJanice Chang  *		check does not apply in this case and things should
31838c4f9701SJanice Chang  * 		appear successful.
31842654012fSReza Sabdar  */
31852654012fSReza Sabdar static boolean_t
31862654012fSReza Sabdar is_writer_running(ndmpd_session_t *session)
31872654012fSReza Sabdar {
31882654012fSReza Sabdar 	boolean_t rv;
31892654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
31902654012fSReza Sabdar 
31918c4f9701SJanice Chang 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
31928c4f9701SJanice Chang 		return (1);
31938c4f9701SJanice Chang 
31942654012fSReza Sabdar 	if (session == NULL)
31952654012fSReza Sabdar 		rv = 0;
31962654012fSReza Sabdar 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
31972654012fSReza Sabdar 		rv = 0;
31982654012fSReza Sabdar 	else
31992654012fSReza Sabdar 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
32002654012fSReza Sabdar 
32012654012fSReza Sabdar 	return (rv);
32022654012fSReza Sabdar }
32032654012fSReza Sabdar 
32042654012fSReza Sabdar 
32052654012fSReza Sabdar /*
32062654012fSReza Sabdar  * is_writer_running_v3
32072654012fSReza Sabdar  *
32082654012fSReza Sabdar  * Find out if the writer thread has started or not.
32092654012fSReza Sabdar  *
32102654012fSReza Sabdar  * Parameters:
32112654012fSReza Sabdar  *   session (input) - session pointer.
32122654012fSReza Sabdar  *
32132654012fSReza Sabdar  * Returns:
32142654012fSReza Sabdar  *   0: not started
32152654012fSReza Sabdar  *   non-zero: started
32168c4f9701SJanice Chang  *	Note: non-zero is also returned if the backup type is
32178c4f9701SJanice Chang  *		neither TAR nor DUMP.  I.e. the is_writer_running()
32188c4f9701SJanice Chang  *		check does not apply in this case and things should
32198c4f9701SJanice Chang  * 		appear successful.
32202654012fSReza Sabdar  */
32212654012fSReza Sabdar static boolean_t
32222654012fSReza Sabdar is_writer_running_v3(ndmpd_session_t *session)
32232654012fSReza Sabdar {
32242654012fSReza Sabdar 	boolean_t rv;
32252654012fSReza Sabdar 	ndmp_lbr_params_t *nlp;
32262654012fSReza Sabdar 
32278c4f9701SJanice Chang 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
32288c4f9701SJanice Chang 		return (1);
32298c4f9701SJanice Chang 
32302654012fSReza Sabdar 	if (session == NULL)
32312654012fSReza Sabdar 		rv = 0;
32322654012fSReza Sabdar 	else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
32332654012fSReza Sabdar 		rv = 1;
32342654012fSReza Sabdar 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
32352654012fSReza Sabdar 		rv = 0;
32362654012fSReza Sabdar 	else
32372654012fSReza Sabdar 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
32382654012fSReza Sabdar 
32392654012fSReza Sabdar 	return (rv);
32402654012fSReza Sabdar }
32412654012fSReza Sabdar 
32422654012fSReza Sabdar 
32432654012fSReza Sabdar /*
32442654012fSReza Sabdar  * ndmpd_mover_error_send
32452654012fSReza Sabdar  *
32462654012fSReza Sabdar  * This function sends the notify message to the client.
32472654012fSReza Sabdar  *
32482654012fSReza Sabdar  * Parameters:
32492654012fSReza Sabdar  *   session (input) - session pointer.
32502654012fSReza Sabdar  *   reason  (input) - halt reason.
32512654012fSReza Sabdar  *
32522654012fSReza Sabdar  * Returns:
32532654012fSReza Sabdar  *   Error code
32542654012fSReza Sabdar  */
32552654012fSReza Sabdar int
32562654012fSReza Sabdar ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
32572654012fSReza Sabdar {
32582654012fSReza Sabdar 	ndmp_notify_mover_halted_request req;
32592654012fSReza Sabdar 
32602654012fSReza Sabdar 	req.reason = reason;
32612654012fSReza Sabdar 	req.text_reason = "";
32622654012fSReza Sabdar 
32632654012fSReza Sabdar 	return (ndmp_send_request(session->ns_connection,
32642654012fSReza Sabdar 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
32652654012fSReza Sabdar }
32662654012fSReza Sabdar 
32672654012fSReza Sabdar 
32682654012fSReza Sabdar /*
32692654012fSReza Sabdar  * ndmpd_mover_error_send_v4
32702654012fSReza Sabdar  *
32712654012fSReza Sabdar  * This function sends the notify message to the client.
32722654012fSReza Sabdar  *
32732654012fSReza Sabdar  * Parameters:
32742654012fSReza Sabdar  *   session (input) - session pointer.
32752654012fSReza Sabdar  *   reason  (input) - halt reason.
32762654012fSReza Sabdar  *
32772654012fSReza Sabdar  * Returns:
32782654012fSReza Sabdar  *   Error code
32792654012fSReza Sabdar  */
32802654012fSReza Sabdar int
32812654012fSReza Sabdar ndmpd_mover_error_send_v4(ndmpd_session_t *session,
32822654012fSReza Sabdar     ndmp_mover_halt_reason reason)
32832654012fSReza Sabdar {
32842654012fSReza Sabdar 	ndmp_notify_mover_halted_request_v4 req;
32852654012fSReza Sabdar 
32862654012fSReza Sabdar 	req.reason = reason;
32872654012fSReza Sabdar 
32882654012fSReza Sabdar 	return (ndmp_send_request(session->ns_connection,
32892654012fSReza Sabdar 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
32902654012fSReza Sabdar }
32912654012fSReza Sabdar 
32922654012fSReza Sabdar 
32932654012fSReza Sabdar /*
32942654012fSReza Sabdar  * ndmpd_mover_error
32952654012fSReza Sabdar  *
32962654012fSReza Sabdar  * This function is called when an unrecoverable mover error
32972654012fSReza Sabdar  * has been detected. A notify message is sent to the client and the
32982654012fSReza Sabdar  * mover is placed into the halted state.
32992654012fSReza Sabdar  *
33002654012fSReza Sabdar  * Parameters:
33012654012fSReza Sabdar  *   session (input) - session pointer.
33022654012fSReza Sabdar  *   reason  (input) - halt reason.
33032654012fSReza Sabdar  *
33042654012fSReza Sabdar  * Returns:
33052654012fSReza Sabdar  *   void.
33062654012fSReza Sabdar  */
33072654012fSReza Sabdar void
33082654012fSReza Sabdar ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
33092654012fSReza Sabdar {
3310a23888a3SJan Kryl 	ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
3311a23888a3SJan Kryl 
33122654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
33132654012fSReza Sabdar 	    (session->ns_protocol_version > NDMPV2 &&
33142654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
33152654012fSReza Sabdar 		return;
33162654012fSReza Sabdar 
33172654012fSReza Sabdar 	if (session->ns_protocol_version == NDMPV4) {
33182654012fSReza Sabdar 		if (ndmpd_mover_error_send_v4(session, reason) < 0)
33192654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
33202654012fSReza Sabdar 			    "Error sending notify_mover_halted request");
33212654012fSReza Sabdar 	} else {
33222654012fSReza Sabdar 		/* No media error in V3 */
33232654012fSReza Sabdar 		if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
33242654012fSReza Sabdar 			reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
33252654012fSReza Sabdar 		if (ndmpd_mover_error_send(session, reason) < 0)
33262654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
33272654012fSReza Sabdar 			    "Error sending notify_mover_halted request");
33282654012fSReza Sabdar 	}
33292654012fSReza Sabdar 
3330a23888a3SJan Kryl 	(void) mutex_lock(&nlp->nlp_mtx);
33312654012fSReza Sabdar 	if (session->ns_mover.md_listen_sock != -1) {
33322654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
33332654012fSReza Sabdar 		    session->ns_mover.md_listen_sock);
33342654012fSReza Sabdar 		(void) close(session->ns_mover.md_listen_sock);
33352654012fSReza Sabdar 		session->ns_mover.md_listen_sock = -1;
33362654012fSReza Sabdar 	}
33372654012fSReza Sabdar 	if (session->ns_mover.md_sock != -1) {
33382654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session,
33392654012fSReza Sabdar 		    session->ns_mover.md_sock);
33402654012fSReza Sabdar 		(void) close(session->ns_mover.md_sock);
33412654012fSReza Sabdar 		session->ns_mover.md_sock = -1;
33422654012fSReza Sabdar 	}
33432654012fSReza Sabdar 
33442654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
33452654012fSReza Sabdar 	session->ns_mover.md_halt_reason = reason;
3346a23888a3SJan Kryl 	(void) cond_broadcast(&nlp->nlp_cv);
3347a23888a3SJan Kryl 	(void) mutex_unlock(&nlp->nlp_mtx);
33482654012fSReza Sabdar }
33492654012fSReza Sabdar 
33502654012fSReza Sabdar 
33512654012fSReza Sabdar /*
33522654012fSReza Sabdar  * mover_pause_v3
33532654012fSReza Sabdar  *
33542654012fSReza Sabdar  * Send an ndmp_notify_mover_paused request to the
33552654012fSReza Sabdar  * NDMP client to inform the client that its attention is required.
33562654012fSReza Sabdar  * Process messages until the data/mover operation is either aborted
33572654012fSReza Sabdar  * or continued.
33582654012fSReza Sabdar  *
33592654012fSReza Sabdar  * Parameters:
33602654012fSReza Sabdar  *   client_data (input) - session pointer.
33612654012fSReza Sabdar  *   reason (input) - pause reason.
33622654012fSReza Sabdar  *
33632654012fSReza Sabdar  * Returns:
33642654012fSReza Sabdar  *   0 - operation has been continued.
33652654012fSReza Sabdar  *  -1 - operation has been aborted.
33662654012fSReza Sabdar  */
33672654012fSReza Sabdar static int
33682654012fSReza Sabdar mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
33692654012fSReza Sabdar {
33702654012fSReza Sabdar 	int rv;
33712654012fSReza Sabdar 	ndmp_notify_mover_paused_request request;
33722654012fSReza Sabdar 
33732654012fSReza Sabdar 	rv = 0;
33742654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
33752654012fSReza Sabdar 	session->ns_mover.md_pause_reason = reason;
33762654012fSReza Sabdar 	session->ns_mover.md_pre_cond = FALSE;
33772654012fSReza Sabdar 
33782654012fSReza Sabdar 	request.reason = session->ns_mover.md_pause_reason;
33792654012fSReza Sabdar 	request.seek_position =
33802654012fSReza Sabdar 	    long_long_to_quad(session->ns_mover.md_position);
33812654012fSReza Sabdar 
33822654012fSReza Sabdar 	if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
33832654012fSReza Sabdar 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
33842654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
33852654012fSReza Sabdar 		    "Error sending notify_mover_paused_request");
33862654012fSReza Sabdar 		return (-1);
33872654012fSReza Sabdar 	}
33882654012fSReza Sabdar 
33892654012fSReza Sabdar 	/*
33902654012fSReza Sabdar 	 * 3-way operations are single-thread.  The same thread
33912654012fSReza Sabdar 	 * should process the messages.
33922654012fSReza Sabdar 	 *
33932654012fSReza Sabdar 	 * 2-way operations are multi-thread.  The main thread
33942654012fSReza Sabdar 	 * processes the messages.  We just need to wait and
33952654012fSReza Sabdar 	 * see if the mover state changes or the operation aborts.
33962654012fSReza Sabdar 	 */
33972654012fSReza Sabdar 	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
33982654012fSReza Sabdar 		/*
33992654012fSReza Sabdar 		 * Process messages until the state is changed by
34002654012fSReza Sabdar 		 * an abort, continue, or close request .
34012654012fSReza Sabdar 		 */
34022654012fSReza Sabdar 		for (; ; ) {
34032654012fSReza Sabdar 			if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
34042654012fSReza Sabdar 				return (-1);
34052654012fSReza Sabdar 
34062654012fSReza Sabdar 			if (session->ns_eof == TRUE)
34072654012fSReza Sabdar 				return (-1);
34082654012fSReza Sabdar 
34092654012fSReza Sabdar 			switch (session->ns_mover.md_state) {
34102654012fSReza Sabdar 			case NDMP_MOVER_STATE_ACTIVE:
34112654012fSReza Sabdar 				session->ns_tape.td_record_count = 0;
34122654012fSReza Sabdar 				return (0);
34132654012fSReza Sabdar 
34142654012fSReza Sabdar 			case NDMP_MOVER_STATE_PAUSED:
34152654012fSReza Sabdar 				continue;
34162654012fSReza Sabdar 
34172654012fSReza Sabdar 			default:
34182654012fSReza Sabdar 				return (-1);
34192654012fSReza Sabdar 			}
34202654012fSReza Sabdar 		}
34212654012fSReza Sabdar 
34222654012fSReza Sabdar 	} else {
34232654012fSReza Sabdar 		if (session->ns_mover.md_data_addr.addr_type ==
34242654012fSReza Sabdar 		    NDMP_ADDR_LOCAL) {
3425a23888a3SJan Kryl 			rv = ndmp_wait_for_mover(session);
34262654012fSReza Sabdar 		} else {
34272654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
34282654012fSReza Sabdar 			    session->ns_mover.md_data_addr.addr_type);
34292654012fSReza Sabdar 			rv = -1;
34302654012fSReza Sabdar 		}
34312654012fSReza Sabdar 	}
34322654012fSReza Sabdar 
34332654012fSReza Sabdar 	return (rv);
34342654012fSReza Sabdar }
34352654012fSReza Sabdar 
34362654012fSReza Sabdar 
34372654012fSReza Sabdar /*
34382654012fSReza Sabdar  * mover_tape_write_v3
34392654012fSReza Sabdar  *
34402654012fSReza Sabdar  * Writes a data record to tape. Detects and handles EOT conditions.
34412654012fSReza Sabdar  *
34422654012fSReza Sabdar  * Parameters:
34432654012fSReza Sabdar  *   session (input) - session pointer.
34442654012fSReza Sabdar  *   data    (input) - data to be written.
34452654012fSReza Sabdar  *   length  (input) - length of data to be written.
34462654012fSReza Sabdar  *
34472654012fSReza Sabdar  * Returns:
34482654012fSReza Sabdar  *    0 - operation aborted by client.
34492654012fSReza Sabdar  *   -1 - error.
34502654012fSReza Sabdar  *   otherwise - number of bytes written.
34512654012fSReza Sabdar  */
34522654012fSReza Sabdar static int
34532654012fSReza Sabdar mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
34542654012fSReza Sabdar {
34552654012fSReza Sabdar 	ssize_t n;
34569ee94b97SJan Kryl 	ssize_t count = length;
34572654012fSReza Sabdar 
34589ee94b97SJan Kryl 	while (count > 0) {
34592654012fSReza Sabdar 		/*
34602654012fSReza Sabdar 		 * Enforce mover window on write.
34612654012fSReza Sabdar 		 */
34622654012fSReza Sabdar 		if (session->ns_mover.md_position >=
34632654012fSReza Sabdar 		    session->ns_mover.md_window_offset +
34642654012fSReza Sabdar 		    session->ns_mover.md_window_length) {
34652654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
34662654012fSReza Sabdar 
34679ee94b97SJan Kryl 			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW) < 0)
34689ee94b97SJan Kryl 				/* Operation aborted or connection terminated */
34692654012fSReza Sabdar 				return (-1);
34702654012fSReza Sabdar 
34712654012fSReza Sabdar 		}
34722654012fSReza Sabdar 
34739ee94b97SJan Kryl 		n = write(session->ns_tape.td_fd, data, count);
34742654012fSReza Sabdar 		if (n < 0) {
34752654012fSReza Sabdar 			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
34762654012fSReza Sabdar 			return (-1);
34779ee94b97SJan Kryl 		} else if (n > 0) {
34782654012fSReza Sabdar 			NS_ADD(wtape, n);
34799ee94b97SJan Kryl 			count -= n;
34809ee94b97SJan Kryl 			data += n;
34819ee94b97SJan Kryl 			session->ns_tape.td_record_count++;
34822654012fSReza Sabdar 		}
34832654012fSReza Sabdar 
34849ee94b97SJan Kryl 		/* EOM handling */
34859ee94b97SJan Kryl 		if (count > 0) {
34869ee94b97SJan Kryl 			struct mtget mtstatus;
34879ee94b97SJan Kryl 
34889ee94b97SJan Kryl 			(void) ioctl(session->ns_tape.td_fd, MTIOCGET,
34899ee94b97SJan Kryl 			    &mtstatus);
34909ee94b97SJan Kryl 			NDMP_LOG(LOG_DEBUG, "EOM detected (%d written bytes, "
34919ee94b97SJan Kryl 			    "mover record %d, file #%d, block #%d)", n,
34929ee94b97SJan Kryl 			    session->ns_tape.td_record_count,
34939ee94b97SJan Kryl 			    mtstatus.mt_fileno, mtstatus.mt_blkno);
34949ee94b97SJan Kryl 
34952654012fSReza Sabdar 			/*
34969ee94b97SJan Kryl 			 * Notify the client to either abort the operation
34979ee94b97SJan Kryl 			 * or change the tape.
34982654012fSReza Sabdar 			 */
34992654012fSReza Sabdar 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
35002654012fSReza Sabdar 			    ++ndmp_log_msg_id,
35012654012fSReza Sabdar 			    "End of tape reached. Load next tape");
35022654012fSReza Sabdar 
35039ee94b97SJan Kryl 			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM) < 0)
35049ee94b97SJan Kryl 				/* Operation aborted or connection terminated */
35052654012fSReza Sabdar 				return (-1);
35069ee94b97SJan Kryl 		}
35072654012fSReza Sabdar 	}
35082654012fSReza Sabdar 
35099ee94b97SJan Kryl 	return (length);
35102654012fSReza Sabdar }
35112654012fSReza Sabdar 
35122654012fSReza Sabdar 
35132654012fSReza Sabdar /*
35142654012fSReza Sabdar  * mover_tape_flush_v3
35152654012fSReza Sabdar  *
35162654012fSReza Sabdar  * Writes all remaining buffered data to tape. A partial record is
35172654012fSReza Sabdar  * padded out to a full record with zeros.
35182654012fSReza Sabdar  *
35192654012fSReza Sabdar  * Parameters:
35202654012fSReza Sabdar  *   session (input) - session pointer.
35212654012fSReza Sabdar  *   data    (input) - data to be written.
35222654012fSReza Sabdar  *   length  (input) - length of data to be written.
35232654012fSReza Sabdar  *
35242654012fSReza Sabdar  * Returns:
35252654012fSReza Sabdar  *   -1 - error.
35262654012fSReza Sabdar  *   otherwise - number of bytes written.
35272654012fSReza Sabdar  */
35282654012fSReza Sabdar static int
35292654012fSReza Sabdar mover_tape_flush_v3(ndmpd_session_t *session)
35302654012fSReza Sabdar {
35312654012fSReza Sabdar 	int n;
35322654012fSReza Sabdar 
35332654012fSReza Sabdar 	if (session->ns_mover.md_w_index == 0)
35342654012fSReza Sabdar 		return (0);
35352654012fSReza Sabdar 
35362654012fSReza Sabdar 	(void) memset((void*)&session->ns_mover.md_buf[session->
35372654012fSReza Sabdar 	    ns_mover.md_w_index], 0,
35382654012fSReza Sabdar 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
35392654012fSReza Sabdar 
35402654012fSReza Sabdar 	n = mover_tape_write_v3(session, session->ns_mover.md_buf,
35412654012fSReza Sabdar 	    session->ns_mover.md_record_size);
35422654012fSReza Sabdar 	if (n < 0) {
35432654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
35442654012fSReza Sabdar 		return (-1);
35452654012fSReza Sabdar 	}
35462654012fSReza Sabdar 
35472654012fSReza Sabdar 	session->ns_mover.md_w_index = 0;
35482654012fSReza Sabdar 	session->ns_mover.md_position += n;
35492654012fSReza Sabdar 	return (n);
35502654012fSReza Sabdar }
35512654012fSReza Sabdar 
35522654012fSReza Sabdar 
35532654012fSReza Sabdar /*
35542654012fSReza Sabdar  * ndmpd_local_write_v3
35552654012fSReza Sabdar  *
35562654012fSReza Sabdar  * Buffers and writes data to the tape device.
35572654012fSReza Sabdar  * A full tape record is buffered before being written.
35582654012fSReza Sabdar  *
35592654012fSReza Sabdar  * Parameters:
35602654012fSReza Sabdar  *   session    (input) - session pointer.
35612654012fSReza Sabdar  *   data       (input) - data to be written.
35622654012fSReza Sabdar  *   length     (input) - data length.
35632654012fSReza Sabdar  *
35642654012fSReza Sabdar  * Returns:
35652654012fSReza Sabdar  *   0 - data successfully written.
35662654012fSReza Sabdar  *  -1 - error.
35672654012fSReza Sabdar  */
35682654012fSReza Sabdar int
35692654012fSReza Sabdar ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
35702654012fSReza Sabdar {
35712654012fSReza Sabdar 	ulong_t count = 0;
35722654012fSReza Sabdar 	ssize_t n;
35732654012fSReza Sabdar 	ulong_t len;
35742654012fSReza Sabdar 
35752654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
35762654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
35772654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
35782654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
35792654012fSReza Sabdar 		return (-1);
35802654012fSReza Sabdar 	}
35812654012fSReza Sabdar 
35822654012fSReza Sabdar 	/*
35832654012fSReza Sabdar 	 * A length of 0 indicates that any buffered data should be
35842654012fSReza Sabdar 	 * flushed to tape.
35852654012fSReza Sabdar 	 */
35862654012fSReza Sabdar 	if (length == 0) {
35872654012fSReza Sabdar 		if (session->ns_mover.md_w_index == 0)
35882654012fSReza Sabdar 			return (0);
35892654012fSReza Sabdar 
35902654012fSReza Sabdar 		(void) memset((void*)&session->ns_mover.md_buf[session->
35912654012fSReza Sabdar 		    ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
35922654012fSReza Sabdar 		    session->ns_mover.md_w_index);
35932654012fSReza Sabdar 
35942654012fSReza Sabdar 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
35952654012fSReza Sabdar 		    session->ns_mover.md_record_size);
35962654012fSReza Sabdar 		if (n <= 0) {
35972654012fSReza Sabdar 			ndmpd_mover_error(session,
35982654012fSReza Sabdar 			    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
35992654012fSReza Sabdar 			    NDMP_MOVER_HALT_MEDIA_ERROR));
36002654012fSReza Sabdar 			return (-1);
36012654012fSReza Sabdar 		}
36022654012fSReza Sabdar 
36032654012fSReza Sabdar 		session->ns_mover.md_position += n;
36048a5de3ffSReza Sabdar 		session->ns_mover.md_data_written +=
36058a5de3ffSReza Sabdar 		    session->ns_mover.md_w_index;
36062654012fSReza Sabdar 		session->ns_mover.md_record_num++;
36072654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
36082654012fSReza Sabdar 		return (0);
36092654012fSReza Sabdar 	}
36102654012fSReza Sabdar 
36112654012fSReza Sabdar 	/* Break the data into records. */
36122654012fSReza Sabdar 	while (count < length) {
36132654012fSReza Sabdar 		/*
36142654012fSReza Sabdar 		 * Determine if data needs to be buffered or
36152654012fSReza Sabdar 		 * can be written directly from user supplied location.
36162654012fSReza Sabdar 		 * We can fast path the write if there is no pending
36172654012fSReza Sabdar 		 * buffered data and there is at least a full records worth
36182654012fSReza Sabdar 		 * of data to be written.
36192654012fSReza Sabdar 		 */
36202654012fSReza Sabdar 		if (session->ns_mover.md_w_index == 0 &&
36212654012fSReza Sabdar 		    length - count >= session->ns_mover.md_record_size) {
36222654012fSReza Sabdar 			n = mover_tape_write_v3(session, &data[count],
36232654012fSReza Sabdar 			    session->ns_mover.md_record_size);
36242654012fSReza Sabdar 			if (n <= 0) {
36252654012fSReza Sabdar 				ndmpd_mover_error(session,
36262654012fSReza Sabdar 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
36272654012fSReza Sabdar 				    NDMP_MOVER_HALT_MEDIA_ERROR));
36282654012fSReza Sabdar 				return (-1);
36292654012fSReza Sabdar 			}
36302654012fSReza Sabdar 
36312654012fSReza Sabdar 			session->ns_mover.md_position += n;
36322654012fSReza Sabdar 			session->ns_mover.md_data_written += n;
36332654012fSReza Sabdar 			session->ns_mover.md_record_num++;
36342654012fSReza Sabdar 			count += n;
36352654012fSReza Sabdar 			continue;
36362654012fSReza Sabdar 		}
36372654012fSReza Sabdar 
36382654012fSReza Sabdar 		/* Buffer the data */
36392654012fSReza Sabdar 		len = length - count;
36402654012fSReza Sabdar 		if (len > session->ns_mover.md_record_size -
36412654012fSReza Sabdar 		    session->ns_mover.md_w_index)
36422654012fSReza Sabdar 			len = session->ns_mover.md_record_size -
36432654012fSReza Sabdar 			    session->ns_mover.md_w_index;
36442654012fSReza Sabdar 
36452654012fSReza Sabdar 		(void) memcpy(&session->ns_mover.md_buf[session->
36462654012fSReza Sabdar 		    ns_mover.md_w_index], &data[count], len);
36472654012fSReza Sabdar 		session->ns_mover.md_w_index += len;
36482654012fSReza Sabdar 		count += len;
36492654012fSReza Sabdar 
36502654012fSReza Sabdar 		/* Write the buffer if its full */
36512654012fSReza Sabdar 		if (session->ns_mover.md_w_index ==
36522654012fSReza Sabdar 		    session->ns_mover.md_record_size) {
36532654012fSReza Sabdar 			n = mover_tape_write_v3(session,
36542654012fSReza Sabdar 			    session->ns_mover.md_buf,
36552654012fSReza Sabdar 			    session->ns_mover.md_record_size);
36569ee94b97SJan Kryl 			if (n <= 0) {
36572654012fSReza Sabdar 				ndmpd_mover_error(session,
36582654012fSReza Sabdar 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
36592654012fSReza Sabdar 				    NDMP_MOVER_HALT_MEDIA_ERROR));
36602654012fSReza Sabdar 				return (-1);
36612654012fSReza Sabdar 			}
36622654012fSReza Sabdar 
36632654012fSReza Sabdar 			session->ns_mover.md_position += n;
36642654012fSReza Sabdar 			session->ns_mover.md_data_written += n;
36652654012fSReza Sabdar 			session->ns_mover.md_record_num++;
36662654012fSReza Sabdar 			session->ns_mover.md_w_index = 0;
36672654012fSReza Sabdar 		}
36682654012fSReza Sabdar 	}
36692654012fSReza Sabdar 
36702654012fSReza Sabdar 	return (0);
36712654012fSReza Sabdar }
36722654012fSReza Sabdar 
36732654012fSReza Sabdar 
36742654012fSReza Sabdar /*
36752654012fSReza Sabdar  * mover_data_read_v3
36762654012fSReza Sabdar  *
36772654012fSReza Sabdar  * Reads backup data from the data connection and writes the
36782654012fSReza Sabdar  * received data to the tape device.
36792654012fSReza Sabdar  *
36802654012fSReza Sabdar  * Parameters:
36812654012fSReza Sabdar  *   cookie  (input) - session pointer.
36822654012fSReza Sabdar  *   fd      (input) - file descriptor.
36832654012fSReza Sabdar  *   mode    (input) - select mode.
36842654012fSReza Sabdar  *
36852654012fSReza Sabdar  * Returns:
36862654012fSReza Sabdar  *   void.
36872654012fSReza Sabdar  */
36882654012fSReza Sabdar /*ARGSUSED*/
36892654012fSReza Sabdar static void
36902654012fSReza Sabdar mover_data_read_v3(void *cookie, int fd, ulong_t mode)
36912654012fSReza Sabdar {
36922654012fSReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
36932654012fSReza Sabdar 	int n;
36942654012fSReza Sabdar 	ulong_t index;
36952654012fSReza Sabdar 
36962654012fSReza Sabdar 	n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
36972654012fSReza Sabdar 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
36982654012fSReza Sabdar 
36992654012fSReza Sabdar 	/*
37002654012fSReza Sabdar 	 * Since this function is only called when select believes data
37012654012fSReza Sabdar 	 * is available to be read, a return of zero indicates the
37022654012fSReza Sabdar 	 * connection has been closed.
37032654012fSReza Sabdar 	 */
37042654012fSReza Sabdar 	if (n <= 0) {
370597f7c475SJan Kryl 		if (n == 0) {
370697f7c475SJan Kryl 			NDMP_LOG(LOG_DEBUG, "Data connection closed");
370797f7c475SJan Kryl 			ndmpd_mover_error(session,
370897f7c475SJan Kryl 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
370997f7c475SJan Kryl 		} else {
371097f7c475SJan Kryl 			/* Socket is non-blocking, perhaps there are no data */
371197f7c475SJan Kryl 			if (errno == EAGAIN) {
371297f7c475SJan Kryl 				NDMP_LOG(LOG_ERR, "No data to read");
37132654012fSReza Sabdar 				return;
37142654012fSReza Sabdar 			}
371597f7c475SJan Kryl 
371697f7c475SJan Kryl 			NDMP_LOG(LOG_ERR, "Failed to read from socket: %m");
371797f7c475SJan Kryl 			ndmpd_mover_error(session,
371897f7c475SJan Kryl 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
371997f7c475SJan Kryl 		}
37202654012fSReza Sabdar 
37212654012fSReza Sabdar 		/* Save the index since mover_tape_flush_v3 resets it. */
37222654012fSReza Sabdar 		index = session->ns_mover.md_w_index;
37232654012fSReza Sabdar 
37242654012fSReza Sabdar 		/* Flush any buffered data to tape. */
37252654012fSReza Sabdar 		if (mover_tape_flush_v3(session) > 0) {
37262654012fSReza Sabdar 			session->ns_mover.md_data_written += index;
37272654012fSReza Sabdar 			session->ns_mover.md_record_num++;
37282654012fSReza Sabdar 		}
37292654012fSReza Sabdar 
37302654012fSReza Sabdar 		return;
37312654012fSReza Sabdar 	}
37322654012fSReza Sabdar 
37332654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "n %d", n);
37342654012fSReza Sabdar 
37352654012fSReza Sabdar 	session->ns_mover.md_w_index += n;
37362654012fSReza Sabdar 
37372654012fSReza Sabdar 	if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
37382654012fSReza Sabdar 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
37392654012fSReza Sabdar 		    session->ns_mover.md_record_size);
37402654012fSReza Sabdar 		if (n <= 0) {
37412654012fSReza Sabdar 			ndmpd_mover_error(session,
37422654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
37432654012fSReza Sabdar 			    NDMP_MOVER_HALT_MEDIA_ERROR));
37442654012fSReza Sabdar 			return;
37452654012fSReza Sabdar 		}
37462654012fSReza Sabdar 
37472654012fSReza Sabdar 		session->ns_mover.md_position += n;
37482654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
37492654012fSReza Sabdar 		session->ns_mover.md_data_written += n;
37502654012fSReza Sabdar 		session->ns_mover.md_record_num++;
37512654012fSReza Sabdar 	}
37522654012fSReza Sabdar }
37532654012fSReza Sabdar 
37542654012fSReza Sabdar /*
37552654012fSReza Sabdar  * mover_tape_read_v3
37562654012fSReza Sabdar  *
37572654012fSReza Sabdar  * Reads a data record from tape. Detects and handles EOT conditions.
37582654012fSReza Sabdar  *
37592654012fSReza Sabdar  * Parameters:
37602654012fSReza Sabdar  *   session (input) - session pointer.
37612654012fSReza Sabdar  *   data    (input) - location to read data to.
37622654012fSReza Sabdar  *
37632654012fSReza Sabdar  * Returns:
37642654012fSReza Sabdar  *   0 - operation aborted.
37652654012fSReza Sabdar  *   TAPE_READ_ERR - tape read IO error.
37662654012fSReza Sabdar  *   TAPE_NO_WRITER_ERR - no writer is running during tape read
37672654012fSReza Sabdar  *   otherwise - number of bytes read.
37682654012fSReza Sabdar  */
37692654012fSReza Sabdar static int
37702654012fSReza Sabdar mover_tape_read_v3(ndmpd_session_t *session, char *data)
37712654012fSReza Sabdar {
37729ee94b97SJan Kryl 	int pause_reason;
37732654012fSReza Sabdar 	ssize_t	 n;
37742654012fSReza Sabdar 	int err;
37752654012fSReza Sabdar 	int count;
37762654012fSReza Sabdar 
37772654012fSReza Sabdar 	count = session->ns_mover.md_record_size;
37789ee94b97SJan Kryl 	while (count > 0) {
37799ee94b97SJan Kryl 		pause_reason = NDMP_MOVER_PAUSE_NA;
37809ee94b97SJan Kryl 
37812654012fSReza Sabdar 		n = read(session->ns_tape.td_fd, data, count);
37822654012fSReza Sabdar 		if (n < 0) {
37839ee94b97SJan Kryl 			/*
37849ee94b97SJan Kryl 			 * If at beginning of file and read fails with EIO,
37859ee94b97SJan Kryl 			 * then it's repeated attempt to read at EOT.
37869ee94b97SJan Kryl 			 */
37879ee94b97SJan Kryl 			if (errno == EIO && tape_is_at_bof(session)) {
37889ee94b97SJan Kryl 				NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
37899ee94b97SJan Kryl 				pause_reason = NDMP_MOVER_PAUSE_EOM;
37909ee94b97SJan Kryl 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
37919ee94b97SJan Kryl 				    ++ndmp_log_msg_id,
37929ee94b97SJan Kryl 				    "End of tape reached. Load next tape");
37939ee94b97SJan Kryl 			}
37949ee94b97SJan Kryl 			/*
37959ee94b97SJan Kryl 			 * According to NDMPv4 spec preferred error code when
37969ee94b97SJan Kryl 			 * trying to read from blank tape is NDMP_EOM_ERR.
37979ee94b97SJan Kryl 			 */
37989ee94b97SJan Kryl 			else if (errno == EIO && tape_is_at_bot(session)) {
37999ee94b97SJan Kryl 				NDMP_LOG(LOG_ERR,
38009ee94b97SJan Kryl 				    "Blank tape detected, returning EOM");
38019ee94b97SJan Kryl 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
38029ee94b97SJan Kryl 				    ++ndmp_log_msg_id,
38039ee94b97SJan Kryl 				    "Blank tape. Load another tape");
38049ee94b97SJan Kryl 				pause_reason = NDMP_MOVER_PAUSE_EOM;
38059ee94b97SJan Kryl 			} else {
38062654012fSReza Sabdar 				NDMP_LOG(LOG_ERR, "Tape read error: %m.");
38072654012fSReza Sabdar 				return (TAPE_READ_ERR);
38082654012fSReza Sabdar 			}
38099ee94b97SJan Kryl 		} else if (n > 0) {
38102654012fSReza Sabdar 			NS_ADD(rtape, n);
38119ee94b97SJan Kryl 			data += n;
38129ee94b97SJan Kryl 			count -= n;
38139ee94b97SJan Kryl 			session->ns_tape.td_record_count++;
38149ee94b97SJan Kryl 		} else {
38152654012fSReza Sabdar 			if (!is_writer_running_v3(session))
38162654012fSReza Sabdar 				return (TAPE_NO_WRITER_ERR);
38172654012fSReza Sabdar 
38182654012fSReza Sabdar 			/*
38199ee94b97SJan Kryl 			 * End of file or media reached. Notify client and
38209ee94b97SJan Kryl 			 * wait for the client to either abort the data
38219ee94b97SJan Kryl 			 * operation or continue the operation after changing
38229ee94b97SJan Kryl 			 * the tape.
38232654012fSReza Sabdar 			 */
38249ee94b97SJan Kryl 			if (tape_is_at_bof(session)) {
38259ee94b97SJan Kryl 				NDMP_LOG(LOG_DEBUG, "EOT detected");
38269ee94b97SJan Kryl 				pause_reason = NDMP_MOVER_PAUSE_EOM;
38272654012fSReza Sabdar 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
38289ee94b97SJan Kryl 				    ++ndmp_log_msg_id, "End of medium reached");
38299ee94b97SJan Kryl 			} else {
38309ee94b97SJan Kryl 				NDMP_LOG(LOG_DEBUG, "EOF detected");
38319ee94b97SJan Kryl 				/* reposition the tape to BOT side of FM */
38329ee94b97SJan Kryl 				fm_dance(session);
38339ee94b97SJan Kryl 				pause_reason = NDMP_MOVER_PAUSE_EOF;
38349ee94b97SJan Kryl 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
38359ee94b97SJan Kryl 				    ++ndmp_log_msg_id, "End of file reached.");
38369ee94b97SJan Kryl 			}
38379ee94b97SJan Kryl 		}
38382654012fSReza Sabdar 
38399ee94b97SJan Kryl 		if (pause_reason != NDMP_MOVER_PAUSE_NA) {
38409ee94b97SJan Kryl 			err = mover_pause_v3(session, pause_reason);
38412654012fSReza Sabdar 
38422654012fSReza Sabdar 			/* Operation aborted or connection terminated? */
38432654012fSReza Sabdar 			if (err < 0) {
38442654012fSReza Sabdar 				return (0);
38452654012fSReza Sabdar 			}
38469ee94b97SJan Kryl 			/* Retry the read from new location */
38472654012fSReza Sabdar 		}
38482654012fSReza Sabdar 	}
38499ee94b97SJan Kryl 	return (session->ns_mover.md_record_size);
38502654012fSReza Sabdar }
38512654012fSReza Sabdar 
38522654012fSReza Sabdar 
38532654012fSReza Sabdar /*
38542654012fSReza Sabdar  * mover_data_write_v3
38552654012fSReza Sabdar  *
38562654012fSReza Sabdar  * Reads backup data from the tape device and writes the
38572654012fSReza Sabdar  * data to the data connection.
38582654012fSReza Sabdar  * This function is called by ndmpd_select when the data connection
38592654012fSReza Sabdar  * is ready for more data to be written.
38602654012fSReza Sabdar  *
38612654012fSReza Sabdar  * Parameters:
38622654012fSReza Sabdar  *   cookie  (input) - session pointer.
38632654012fSReza Sabdar  *   fd      (input) - file descriptor.
38642654012fSReza Sabdar  *   mode    (input) - select mode.
38652654012fSReza Sabdar  *
38662654012fSReza Sabdar  * Returns:
38672654012fSReza Sabdar  *   void.
38682654012fSReza Sabdar  */
38692654012fSReza Sabdar /*ARGSUSED*/
38702654012fSReza Sabdar static void
38712654012fSReza Sabdar mover_data_write_v3(void *cookie, int fd, ulong_t mode)
38722654012fSReza Sabdar {
38732654012fSReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
38742654012fSReza Sabdar 	int n;
38752654012fSReza Sabdar 	ulong_t len;
38762654012fSReza Sabdar 	u_longlong_t wlen;
38772654012fSReza Sabdar 	ndmp_notify_mover_paused_request pause_request;
38782654012fSReza Sabdar 
38792654012fSReza Sabdar 	/*
38802654012fSReza Sabdar 	 * If the end of the mover window has been reached,
38812654012fSReza Sabdar 	 * then notify the client that a seek is needed.
38822654012fSReza Sabdar 	 * Remove the file handler to prevent this function from
38832654012fSReza Sabdar 	 * being called. The handler will be reinstalled in
38842654012fSReza Sabdar 	 * ndmpd_mover_continue.
38852654012fSReza Sabdar 	 */
38862654012fSReza Sabdar 	if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
38872654012fSReza Sabdar 	    + session->ns_mover.md_window_length) {
38882654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
38892654012fSReza Sabdar 		    "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
38902654012fSReza Sabdar 
38912654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
38922654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
38932654012fSReza Sabdar 
38942654012fSReza Sabdar 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
38952654012fSReza Sabdar 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
38962654012fSReza Sabdar 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
38972654012fSReza Sabdar 		pause_request.seek_position =
38982654012fSReza Sabdar 		    long_long_to_quad(session->ns_mover.md_position);
38992654012fSReza Sabdar 		session->ns_mover.md_seek_position =
39002654012fSReza Sabdar 		    session->ns_mover.md_position;
39012654012fSReza Sabdar 
39022654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session, fd);
39032654012fSReza Sabdar 
39042654012fSReza Sabdar 		if (ndmp_send_request(session->ns_connection,
39052654012fSReza Sabdar 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
39062654012fSReza Sabdar 		    (void *)&pause_request, 0) < 0) {
39072654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
39082654012fSReza Sabdar 			    "Sending notify_mover_paused request");
39092654012fSReza Sabdar 			ndmpd_mover_error(session,
39102654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
39112654012fSReza Sabdar 		}
39122654012fSReza Sabdar 		return;
39132654012fSReza Sabdar 	}
39142654012fSReza Sabdar 
39152654012fSReza Sabdar 	/*
39162654012fSReza Sabdar 	 * Read more data into the tape buffer if the buffer is empty.
39172654012fSReza Sabdar 	 */
39182654012fSReza Sabdar 	if (session->ns_mover.md_w_index == 0) {
39192654012fSReza Sabdar 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
39202654012fSReza Sabdar 
39212654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
39222654012fSReza Sabdar 		    "read %u bytes from tape", n);
39232654012fSReza Sabdar 
39242654012fSReza Sabdar 		if (n <= 0) {
39252654012fSReza Sabdar 			ndmpd_mover_error(session, (n == 0 ?
39262654012fSReza Sabdar 			    NDMP_MOVER_HALT_ABORTED
39272654012fSReza Sabdar 			    : NDMP_MOVER_HALT_MEDIA_ERROR));
39282654012fSReza Sabdar 			return;
39292654012fSReza Sabdar 		}
39302654012fSReza Sabdar 
39312654012fSReza Sabdar 		/*
39322654012fSReza Sabdar 		 * Discard data if the current data stream position is
39332654012fSReza Sabdar 		 * prior to the seek position. This is necessary if a seek
39342654012fSReza Sabdar 		 * request set the seek pointer to a position that is not a
39352654012fSReza Sabdar 		 * record boundary. The seek request handler can only position
39362654012fSReza Sabdar 		 * to the start of a record.
39372654012fSReza Sabdar 		 */
39382654012fSReza Sabdar 		if (session->ns_mover.md_position <
39392654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
39402654012fSReza Sabdar 			session->ns_mover.md_r_index =
39412654012fSReza Sabdar 			    session->ns_mover.md_seek_position -
39422654012fSReza Sabdar 			    session->ns_mover.md_position;
39432654012fSReza Sabdar 			session->ns_mover.md_position =
39442654012fSReza Sabdar 			    session->ns_mover.md_seek_position;
39452654012fSReza Sabdar 		}
39462654012fSReza Sabdar 
39472654012fSReza Sabdar 		session->ns_mover.md_w_index = n;
39489ee94b97SJan Kryl 		session->ns_mover.md_record_num++;
39492654012fSReza Sabdar 	}
39502654012fSReza Sabdar 
39512654012fSReza Sabdar 	/*
39522654012fSReza Sabdar 	 * The limit on the total amount of data to be sent can be
39532654012fSReza Sabdar 	 * dictated by either the end of the mover window or the end of the
39542654012fSReza Sabdar 	 * seek window.
39552654012fSReza Sabdar 	 * First determine which window applies and then determine if the
39562654012fSReza Sabdar 	 * send length needs to be less than a full record to avoid
39572654012fSReza Sabdar 	 * exceeding the window.
39582654012fSReza Sabdar 	 */
39592654012fSReza Sabdar 	if (session->ns_mover.md_position +
39602654012fSReza Sabdar 	    session->ns_mover.md_bytes_left_to_read >
39612654012fSReza Sabdar 	    session->ns_mover.md_window_offset +
39622654012fSReza Sabdar 	    session->ns_mover.md_window_length)
39632654012fSReza Sabdar 		wlen = session->ns_mover.md_window_offset +
39642654012fSReza Sabdar 		    session->ns_mover.md_window_length -
39652654012fSReza Sabdar 		    session->ns_mover.md_position;
39662654012fSReza Sabdar 	else
39672654012fSReza Sabdar 		wlen = session->ns_mover.md_bytes_left_to_read;
39682654012fSReza Sabdar 
39692654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
39702654012fSReza Sabdar 
39712654012fSReza Sabdar 	/*
39722654012fSReza Sabdar 	 * Now limit the length to the amount of data in the buffer.
39732654012fSReza Sabdar 	 */
39742654012fSReza Sabdar 	if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
39752654012fSReza Sabdar 		wlen = session->ns_mover.md_w_index -
39762654012fSReza Sabdar 		    session->ns_mover.md_r_index;
39772654012fSReza Sabdar 
39782654012fSReza Sabdar 	len = wlen & 0xffffffff;
39792654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG,
39802654012fSReza Sabdar 	    "buffer restrictions: wlen %llu len %u", wlen, len);
39812654012fSReza Sabdar 
39822654012fSReza Sabdar 	/*
39832654012fSReza Sabdar 	 * Write the data to the data connection.
39842654012fSReza Sabdar 	 */
39852654012fSReza Sabdar 	n = write(session->ns_mover.md_sock,
39862654012fSReza Sabdar 	    &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
39872654012fSReza Sabdar 
39882654012fSReza Sabdar 	if (n < 0) {
398997f7c475SJan Kryl 		/* Socket is non-blocking, perhaps the write queue is full */
399097f7c475SJan Kryl 		if (errno == EAGAIN) {
399197f7c475SJan Kryl 			NDMP_LOG(LOG_ERR, "Cannot write to socket");
39922654012fSReza Sabdar 			return;
39932654012fSReza Sabdar 		}
399497f7c475SJan Kryl 		NDMP_LOG(LOG_ERR, "Failed to write to socket: %m");
39952654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
39962654012fSReza Sabdar 		return;
39972654012fSReza Sabdar 	}
39982654012fSReza Sabdar 
39992654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG,
40002654012fSReza Sabdar 	    "wrote %u of %u bytes to data connection position %llu r_index %lu",
40012654012fSReza Sabdar 	    n, len, session->ns_mover.md_position,
40022654012fSReza Sabdar 	    session->ns_mover.md_r_index);
40032654012fSReza Sabdar 
40042654012fSReza Sabdar 	session->ns_mover.md_r_index += n;
40052654012fSReza Sabdar 	session->ns_mover.md_position += n;
40062654012fSReza Sabdar 	session->ns_mover.md_bytes_left_to_read -= n;
40072654012fSReza Sabdar 
40082654012fSReza Sabdar 	/*
40092654012fSReza Sabdar 	 * If all data in the buffer has been written,
40102654012fSReza Sabdar 	 * zero the buffer indices. The next call to this function
40112654012fSReza Sabdar 	 * will read more data from the tape device into the buffer.
40122654012fSReza Sabdar 	 */
40132654012fSReza Sabdar 	if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
40142654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
40152654012fSReza Sabdar 		session->ns_mover.md_w_index = 0;
40162654012fSReza Sabdar 	}
40172654012fSReza Sabdar 
40182654012fSReza Sabdar 	/*
40192654012fSReza Sabdar 	 * If the read limit has been reached,
40202654012fSReza Sabdar 	 * then remove the file handler to prevent this
40212654012fSReza Sabdar 	 * function from getting called. The next mover_read request
40222654012fSReza Sabdar 	 * will reinstall the handler.
40232654012fSReza Sabdar 	 */
40242654012fSReza Sabdar 	if (session->ns_mover.md_bytes_left_to_read == 0)
40252654012fSReza Sabdar 		(void) ndmpd_remove_file_handler(session, fd);
40262654012fSReza Sabdar }
40272654012fSReza Sabdar 
40282654012fSReza Sabdar 
40292654012fSReza Sabdar /*
40302654012fSReza Sabdar  * accept_connection_v3
40312654012fSReza Sabdar  *
40322654012fSReza Sabdar  * Accept a data connection from a data server.
40332654012fSReza Sabdar  * Called by ndmpd_select when a connection is pending on
40342654012fSReza Sabdar  * the mover listen socket.
40352654012fSReza Sabdar  *
40362654012fSReza Sabdar  * Parameters:
40372654012fSReza Sabdar  *   cookie  (input) - session pointer.
40382654012fSReza Sabdar  *   fd      (input) - file descriptor.
40392654012fSReza Sabdar  *   mode    (input) - select mode.
40402654012fSReza Sabdar  *
40412654012fSReza Sabdar  * Returns:
40422654012fSReza Sabdar  *   void.
40432654012fSReza Sabdar  */
40442654012fSReza Sabdar /*ARGSUSED*/
40452654012fSReza Sabdar static void
40462654012fSReza Sabdar accept_connection_v3(void *cookie, int fd, ulong_t mode)
40472654012fSReza Sabdar {
40482654012fSReza Sabdar 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
40492654012fSReza Sabdar 	int from_len;
40502654012fSReza Sabdar 	struct sockaddr_in from;
40512654012fSReza Sabdar 
40522654012fSReza Sabdar 	from_len = sizeof (from);
40532654012fSReza Sabdar 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
40542654012fSReza Sabdar 	    &from_len);
40552654012fSReza Sabdar 
40562654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
40572654012fSReza Sabdar 	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
40582654012fSReza Sabdar 
40592654012fSReza Sabdar 	(void) ndmpd_remove_file_handler(session, fd);
40602654012fSReza Sabdar 	(void) close(session->ns_mover.md_listen_sock);
40612654012fSReza Sabdar 	session->ns_mover.md_listen_sock = -1;
40622654012fSReza Sabdar 
40632654012fSReza Sabdar 	if (session->ns_mover.md_sock < 0) {
40642654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
40652654012fSReza Sabdar 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
40662654012fSReza Sabdar 		return;
40672654012fSReza Sabdar 	}
40682654012fSReza Sabdar 
40692654012fSReza Sabdar 	/*
40702654012fSReza Sabdar 	 * Save the peer address.
40712654012fSReza Sabdar 	 */
40722654012fSReza Sabdar 	session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
40732654012fSReza Sabdar 	session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
40742654012fSReza Sabdar 
407597f7c475SJan Kryl 	/* Set the parameter of the new socket */
407697f7c475SJan Kryl 	set_socket_options(session->ns_mover.md_sock);
40772654012fSReza Sabdar 
407897f7c475SJan Kryl 	/*
407997f7c475SJan Kryl 	 * Backup/restore is handled by a callback called from main event loop,
408097f7c475SJan Kryl 	 * which reads/writes data to md_sock socket. IO on socket must be
408197f7c475SJan Kryl 	 * non-blocking, otherwise ndmpd would be unable to process other
408297f7c475SJan Kryl 	 * incoming requests.
408397f7c475SJan Kryl 	 */
408497f7c475SJan Kryl 	if (!set_socket_nonblock(session->ns_mover.md_sock)) {
408597f7c475SJan Kryl 		NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
408697f7c475SJan Kryl 		    "on socket: %m");
408797f7c475SJan Kryl 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
408897f7c475SJan Kryl 		return;
408997f7c475SJan Kryl 	}
40902654012fSReza Sabdar 
40912654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
40922654012fSReza Sabdar 
40932654012fSReza Sabdar 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
40942654012fSReza Sabdar 		if (ndmpd_add_file_handler(session, (void*)session,
40952654012fSReza Sabdar 		    session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
40962654012fSReza Sabdar 		    HC_MOVER, mover_data_read_v3) < 0) {
40972654012fSReza Sabdar 			ndmpd_mover_error(session,
40982654012fSReza Sabdar 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
40992654012fSReza Sabdar 			return;
41002654012fSReza Sabdar 		}
41012654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
41022654012fSReza Sabdar 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
41032654012fSReza Sabdar 		    ntohs(from.sin_port));
41042654012fSReza Sabdar 	} else {
41052654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
41062654012fSReza Sabdar 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
41072654012fSReza Sabdar 		    ntohs(from.sin_port));
41082654012fSReza Sabdar 	}
41092654012fSReza Sabdar 
41102654012fSReza Sabdar 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
41112654012fSReza Sabdar }
41122654012fSReza Sabdar 
41132654012fSReza Sabdar 
41142654012fSReza Sabdar /*
41152654012fSReza Sabdar  * create_listen_socket_v3
41162654012fSReza Sabdar  *
41172654012fSReza Sabdar  * Creates a socket for listening for accepting data connections.
41182654012fSReza Sabdar  *
41192654012fSReza Sabdar  * Parameters:
41202654012fSReza Sabdar  *   session (input)  - session pointer.
41212654012fSReza Sabdar  *   addr    (output) - location to store address of socket.
41222654012fSReza Sabdar  *   port    (output) - location to store port of socket.
41232654012fSReza Sabdar  *
41242654012fSReza Sabdar  * Returns:
41252654012fSReza Sabdar  *   0 - success.
41262654012fSReza Sabdar  *  -1 - error.
41272654012fSReza Sabdar  */
41282654012fSReza Sabdar static int
41292654012fSReza Sabdar create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
41302654012fSReza Sabdar {
41312654012fSReza Sabdar 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
41322654012fSReza Sabdar 	if (session->ns_mover.md_listen_sock < 0)
41332654012fSReza Sabdar 		return (-1);
41342654012fSReza Sabdar 
41352654012fSReza Sabdar 	/*
41362654012fSReza Sabdar 	 * Add a file handler for the listen socket.
41372654012fSReza Sabdar 	 * ndmpd_select will call accept_connection when a
41382654012fSReza Sabdar 	 * connection is ready to be accepted.
41392654012fSReza Sabdar 	 */
41402654012fSReza Sabdar 	if (ndmpd_add_file_handler(session, (void *) session,
41412654012fSReza Sabdar 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
41422654012fSReza Sabdar 	    accept_connection_v3) < 0) {
41432654012fSReza Sabdar 		(void) close(session->ns_mover.md_listen_sock);
41442654012fSReza Sabdar 		session->ns_mover.md_listen_sock = -1;
41452654012fSReza Sabdar 		return (-1);
41462654012fSReza Sabdar 	}
41472654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "IP %s port %d",
41482654012fSReza Sabdar 	    inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
41492654012fSReza Sabdar 	return (0);
41502654012fSReza Sabdar }
41512654012fSReza Sabdar 
41522654012fSReza Sabdar 
41532654012fSReza Sabdar /*
415497f7c475SJan Kryl  * mover_connect_sock
41552654012fSReza Sabdar  *
41562654012fSReza Sabdar  * Connect the mover to the specified address
41572654012fSReza Sabdar  *
41582654012fSReza Sabdar  * Parameters:
41592654012fSReza Sabdar  *   session (input)  - session pointer.
41602654012fSReza Sabdar  *   mode    (input)  - mover mode.
41612654012fSReza Sabdar  *   addr    (output) - location to store address of socket.
41622654012fSReza Sabdar  *   port    (output) - location to store port of socket.
41632654012fSReza Sabdar  *
41642654012fSReza Sabdar  * Returns:
41652654012fSReza Sabdar  *   error code.
41662654012fSReza Sabdar  */
41672654012fSReza Sabdar static ndmp_error
416897f7c475SJan Kryl mover_connect_sock(ndmpd_session_t *session, ndmp_mover_mode mode,
41692654012fSReza Sabdar     ulong_t addr, ushort_t port)
41702654012fSReza Sabdar {
41712654012fSReza Sabdar 	int sock;
41722654012fSReza Sabdar 
41732654012fSReza Sabdar 	sock = ndmp_connect_sock_v3(addr, port);
41742654012fSReza Sabdar 	if (sock < 0)
41752654012fSReza Sabdar 		return (NDMP_CONNECT_ERR);
41762654012fSReza Sabdar 
417797f7c475SJan Kryl 	/*
417897f7c475SJan Kryl 	 * Backup/restore is handled by a callback called from main event loop,
417997f7c475SJan Kryl 	 * which reads/writes data to md_sock socket. IO on socket must be
418097f7c475SJan Kryl 	 * non-blocking, otherwise ndmpd would be unable to process other
418197f7c475SJan Kryl 	 * incoming requests.
418297f7c475SJan Kryl 	 */
418397f7c475SJan Kryl 	if (!set_socket_nonblock(sock)) {
418497f7c475SJan Kryl 		NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
418597f7c475SJan Kryl 		    "on socket: %m");
418697f7c475SJan Kryl 		(void) close(sock);
418797f7c475SJan Kryl 		return (NDMP_CONNECT_ERR);
418897f7c475SJan Kryl 	}
418997f7c475SJan Kryl 
41902654012fSReza Sabdar 	if (mode == NDMP_MOVER_MODE_READ) {
41912654012fSReza Sabdar 		if (ndmpd_add_file_handler(session, (void*)session, sock,
41922654012fSReza Sabdar 		    NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
41932654012fSReza Sabdar 			(void) close(sock);
41942654012fSReza Sabdar 			return (NDMP_CONNECT_ERR);
41952654012fSReza Sabdar 		}
41962654012fSReza Sabdar 	}
41972654012fSReza Sabdar 	session->ns_mover.md_sock = sock;
41982654012fSReza Sabdar 	session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
41992654012fSReza Sabdar 	session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
42002654012fSReza Sabdar 	session->ns_mover.md_data_addr.tcp_port_v3 = port;
42012654012fSReza Sabdar 	return (NDMP_NO_ERR);
42022654012fSReza Sabdar }
42032654012fSReza Sabdar 
42042654012fSReza Sabdar 
42052654012fSReza Sabdar /*
42062654012fSReza Sabdar  * ndmpd_local_read_v3
42072654012fSReza Sabdar  *
42082654012fSReza Sabdar  * Reads data from the local tape device.
42092654012fSReza Sabdar  * Full tape records are read and buffered.
42102654012fSReza Sabdar  *
42112654012fSReza Sabdar  * Parameters:
42122654012fSReza Sabdar  *   session (input) - session pointer.
42132654012fSReza Sabdar  *   data    (input) - location to store data.
42142654012fSReza Sabdar  *   length  (input) - data length.
42152654012fSReza Sabdar  *
42162654012fSReza Sabdar  * Returns:
42172654012fSReza Sabdar  *   1 - no read error but no writer running
42182654012fSReza Sabdar  *   0 - data successfully read.
42192654012fSReza Sabdar  *  -1 - error.
42202654012fSReza Sabdar  */
42212654012fSReza Sabdar int
42222654012fSReza Sabdar ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
42232654012fSReza Sabdar {
42242654012fSReza Sabdar 	ulong_t count;
42252654012fSReza Sabdar 	ulong_t len;
42262654012fSReza Sabdar 	ssize_t n;
42272654012fSReza Sabdar 
42282654012fSReza Sabdar 	count = 0;
42292654012fSReza Sabdar 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
42302654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
42312654012fSReza Sabdar 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
42322654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
42332654012fSReza Sabdar 		return (-1);
42342654012fSReza Sabdar 	}
42352654012fSReza Sabdar 
42362654012fSReza Sabdar 	/*
42372654012fSReza Sabdar 	 * Automatically increase the seek window if necessary.
42382654012fSReza Sabdar 	 * This is needed in the event the module attempts to read
42392654012fSReza Sabdar 	 * past a seek window set via a prior call to ndmpd_seek() or
42402654012fSReza Sabdar 	 * the module has not issued a seek. If no seek was issued then
42412654012fSReza Sabdar 	 * pretend that a seek was issued to read the entire tape.
42422654012fSReza Sabdar 	 */
42432654012fSReza Sabdar 	if (length > session->ns_mover.md_bytes_left_to_read) {
42442654012fSReza Sabdar 		/* ndmpd_seek() never called? */
42452654012fSReza Sabdar 		if (session->ns_data.dd_read_length == 0) {
42462654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read = ~0LL;
42472654012fSReza Sabdar 			session->ns_data.dd_read_offset = 0LL;
42482654012fSReza Sabdar 			session->ns_data.dd_read_length = ~0LL;
42492654012fSReza Sabdar 		} else {
42502654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read = length;
42512654012fSReza Sabdar 			session->ns_data.dd_read_offset =
42522654012fSReza Sabdar 			    session->ns_mover.md_position;
42532654012fSReza Sabdar 			session->ns_data.dd_read_length = length;
42542654012fSReza Sabdar 		}
42552654012fSReza Sabdar 	}
42562654012fSReza Sabdar 
42572654012fSReza Sabdar 	/*
42582654012fSReza Sabdar 	 * Read as many records as necessary to satisfy the request.
42592654012fSReza Sabdar 	 */
42602654012fSReza Sabdar 	while (count < length) {
42612654012fSReza Sabdar 		/*
42622654012fSReza Sabdar 		 * If the end of the mover window has been reached,
42632654012fSReza Sabdar 		 * then notify the client that a new data window is needed.
42642654012fSReza Sabdar 		 */
42652654012fSReza Sabdar 		if (session->ns_mover.md_position >=
42662654012fSReza Sabdar 		    session->ns_mover.md_window_offset +
42672654012fSReza Sabdar 		    session->ns_mover.md_window_length) {
42682654012fSReza Sabdar 			if (mover_pause_v3(session,
42692654012fSReza Sabdar 			    NDMP_MOVER_PAUSE_SEEK) < 0) {
42702654012fSReza Sabdar 				ndmpd_mover_error(session,
42712654012fSReza Sabdar 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
42722654012fSReza Sabdar 				return (-1);
42732654012fSReza Sabdar 			}
42742654012fSReza Sabdar 			continue;
42752654012fSReza Sabdar 		}
42762654012fSReza Sabdar 
42772654012fSReza Sabdar 		len = length - count;
42782654012fSReza Sabdar 
42792654012fSReza Sabdar 		/*
42802654012fSReza Sabdar 		 * Prevent reading past the end of the window.
42812654012fSReza Sabdar 		 */
42822654012fSReza Sabdar 		if (len > session->ns_mover.md_window_offset +
42832654012fSReza Sabdar 		    session->ns_mover.md_window_length -
42842654012fSReza Sabdar 		    session->ns_mover.md_position)
42852654012fSReza Sabdar 			len = session->ns_mover.md_window_offset +
42862654012fSReza Sabdar 			    session->ns_mover.md_window_length -
42872654012fSReza Sabdar 			    session->ns_mover.md_position;
42882654012fSReza Sabdar 
42892654012fSReza Sabdar 		/*
42902654012fSReza Sabdar 		 * Copy from the data buffer first.
42912654012fSReza Sabdar 		 */
42922654012fSReza Sabdar 		if (session->ns_mover.md_w_index -
42932654012fSReza Sabdar 		    session->ns_mover.md_r_index != 0) {
42942654012fSReza Sabdar 			/*
42952654012fSReza Sabdar 			 * Limit the copy to the amount of data in the buffer.
42962654012fSReza Sabdar 			 */
42972654012fSReza Sabdar 			if (len > session->ns_mover.md_w_index -
42982654012fSReza Sabdar 			    session->ns_mover.md_r_index)
42992654012fSReza Sabdar 				len = session->ns_mover.md_w_index -
43002654012fSReza Sabdar 				    session->ns_mover.md_r_index;
43012654012fSReza Sabdar 			(void) memcpy((void*)&data[count],
43022654012fSReza Sabdar 			    &session->ns_mover.md_buf[session->
43032654012fSReza Sabdar 			    ns_mover.md_r_index], len);
43042654012fSReza Sabdar 			count += len;
43052654012fSReza Sabdar 			session->ns_mover.md_r_index += len;
43062654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read -= len;
43072654012fSReza Sabdar 			session->ns_mover.md_position += len;
43082654012fSReza Sabdar 			continue;
43092654012fSReza Sabdar 		}
43102654012fSReza Sabdar 
43112654012fSReza Sabdar 		/*
43122654012fSReza Sabdar 		 * Determine if data needs to be buffered or
43132654012fSReza Sabdar 		 * can be read directly to user supplied location.
43142654012fSReza Sabdar 		 * We can fast path the read if at least a full record
43152654012fSReza Sabdar 		 * needs to be read and there is no seek pending.
43162654012fSReza Sabdar 		 * This is done to eliminate a buffer copy.
43172654012fSReza Sabdar 		 */
43182654012fSReza Sabdar 		if (len >= session->ns_mover.md_record_size &&
43192654012fSReza Sabdar 		    session->ns_mover.md_position >=
43202654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
43212654012fSReza Sabdar 			n = mover_tape_read_v3(session, &data[count]);
43222654012fSReza Sabdar 			if (n <= 0) {
43232654012fSReza Sabdar 				if (n == TAPE_NO_WRITER_ERR)
43242654012fSReza Sabdar 					return (1);
43252654012fSReza Sabdar 
43262654012fSReza Sabdar 				ndmpd_mover_error(session,
43272654012fSReza Sabdar 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
43282654012fSReza Sabdar 				    NDMP_MOVER_HALT_MEDIA_ERROR));
43292654012fSReza Sabdar 				return ((n == 0) ? 1 : -1);
43302654012fSReza Sabdar 			}
43312654012fSReza Sabdar 
43322654012fSReza Sabdar 			count += n;
43332654012fSReza Sabdar 			session->ns_mover.md_bytes_left_to_read -= n;
43342654012fSReza Sabdar 			session->ns_mover.md_position += n;
43359ee94b97SJan Kryl 			session->ns_mover.md_record_num++;
43362654012fSReza Sabdar 			continue;
43372654012fSReza Sabdar 		}
43382654012fSReza Sabdar 
43392654012fSReza Sabdar 		/* Read the next record into the buffer. */
43402654012fSReza Sabdar 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
43412654012fSReza Sabdar 		if (n <= 0) {
43422654012fSReza Sabdar 			if (n == TAPE_NO_WRITER_ERR)
43432654012fSReza Sabdar 				return (1);
43442654012fSReza Sabdar 
43452654012fSReza Sabdar 			ndmpd_mover_error(session,
43462654012fSReza Sabdar 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
43472654012fSReza Sabdar 			    NDMP_MOVER_HALT_MEDIA_ERROR));
43482654012fSReza Sabdar 			return ((n == 0) ? 1 : -1);
43492654012fSReza Sabdar 		}
43502654012fSReza Sabdar 
43512654012fSReza Sabdar 		session->ns_mover.md_w_index = n;
43522654012fSReza Sabdar 		session->ns_mover.md_r_index = 0;
43539ee94b97SJan Kryl 		session->ns_mover.md_record_num++;
43542654012fSReza Sabdar 
43552654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
43562654012fSReza Sabdar 
43572654012fSReza Sabdar 		/*
43582654012fSReza Sabdar 		 * Discard data if the current data stream position is
43592654012fSReza Sabdar 		 * prior to the seek position. This is necessary if a seek
43602654012fSReza Sabdar 		 * request set the seek pointer to a position that is not a
43612654012fSReza Sabdar 		 * record boundary. The seek request handler can only position
43622654012fSReza Sabdar 		 * to the start of a record.
43632654012fSReza Sabdar 		 */
43642654012fSReza Sabdar 		if (session->ns_mover.md_position <
43652654012fSReza Sabdar 		    session->ns_mover.md_seek_position) {
43662654012fSReza Sabdar 			session->ns_mover.md_r_index =
43672654012fSReza Sabdar 			    session->ns_mover.md_seek_position -
43682654012fSReza Sabdar 			    session->ns_mover.md_position;
43692654012fSReza Sabdar 			session->ns_mover.md_position =
43702654012fSReza Sabdar 			    session->ns_mover.md_seek_position;
43712654012fSReza Sabdar 		}
43722654012fSReza Sabdar 	}
43732654012fSReza Sabdar 
43742654012fSReza Sabdar 	return (0);
43752654012fSReza Sabdar }
4376