xref: /titanic_41/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c (revision f700969ab27181023551541cb5293e922f1587eb)
1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * BSD 3 Clause License
7  *
8  * Copyright (c) 2007, The Storage Networking Industry Association.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 	- Redistributions of source code must retain the above copyright
14  *	  notice, this list of conditions and the following disclaimer.
15  *
16  * 	- Redistributions in binary form must reproduce the above copyright
17  *	  notice, this list of conditions and the following disclaimer in
18  *	  the documentation and/or other materials provided with the
19  *	  distribution.
20  *
21  *	- Neither the name of The Storage Networking Industry Association (SNIA)
22  *	  nor the names of its contributors may be used to endorse or promote
23  *	  products derived from this software without specific prior written
24  *	  permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc.  All rights reserved. */
41 
42 #include <sys/ioctl.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <net/if.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <netdb.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <string.h>
55 #include "ndmpd_common.h"
56 #include "ndmpd.h"
57 #include <sys/mtio.h>
58 
59 /*
60  * Maximum mover record size
61  */
62 #define	MAX_MOVER_RECSIZE	(512*KILOBYTE)
63 
64 static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
65     ushort_t *port);
66 static int tape_read(ndmpd_session_t *session, char *data);
67 static int change_tape(ndmpd_session_t *session);
68 static int discard_data(ndmpd_session_t *session, ulong_t length);
69 static int mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf);
70 static int mover_socket_write_one_buf(ndmpd_session_t *session,
71     tlm_buffer_t *buf);
72 static int start_mover_for_restore(ndmpd_session_t *session);
73 static int mover_socket_read_one_buf(ndmpd_session_t *session,
74     tlm_buffer_t *buf, long read_size);
75 static int mover_tape_write_one_buf(ndmpd_session_t *session,
76     tlm_buffer_t *buf);
77 static int start_mover_for_backup(ndmpd_session_t *session);
78 static boolean_t is_writer_running_v3(ndmpd_session_t *session);
79 static int mover_pause_v3(ndmpd_session_t *session,
80     ndmp_mover_pause_reason reason);
81 static int mover_tape_write_v3(ndmpd_session_t *session, char *data,
82     ssize_t length);
83 static int mover_tape_flush_v3(ndmpd_session_t *session);
84 static int mover_tape_read_v3(ndmpd_session_t *session, char *data);
85 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
86     ushort_t *port);
87 static void mover_data_read_v3(void *cookie, int fd, ulong_t mode);
88 static void accept_connection(void *cookie, int fd, ulong_t mode);
89 static void mover_data_write_v3(void *cookie, int fd, ulong_t mode);
90 static void accept_connection_v3(void *cookie, int fd, ulong_t mode);
91 static ndmp_error mover_connect_sock_v3(ndmpd_session_t *session,
92     ndmp_mover_mode mode, ulong_t addr, ushort_t port);
93 static boolean_t is_writer_running(ndmpd_session_t *session);
94 
95 
96 int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
97 
98 #define	TAPE_READ_ERR		-1
99 #define	TAPE_NO_WRITER_ERR	-2
100 
101 /*
102  * ************************************************************************
103  * NDMP V2 HANDLERS
104  * ************************************************************************
105  */
106 
107 /*
108  * ndmpd_mover_get_state_v2
109  *
110  * This handler handles the mover_get_state request.
111  * Status information for the mover state machine is returned.
112  *
113  * Parameters:
114  *   connection (input) - connection handle.
115  *   body       (input) - request message body.
116  *
117  * Returns:
118  *   void
119  */
120 /*ARGSUSED*/
121 void
122 ndmpd_mover_get_state_v2(ndmp_connection_t *connection, void *body)
123 {
124 	ndmp_mover_get_state_reply_v2 reply;
125 	ndmpd_session_t *session = ndmp_get_client_data(connection);
126 
127 	reply.error = NDMP_NO_ERR;
128 	reply.state = session->ns_mover.md_state;
129 	reply.pause_reason = session->ns_mover.md_pause_reason;
130 	reply.halt_reason = session->ns_mover.md_halt_reason;
131 	reply.record_size = session->ns_mover.md_record_size;
132 	reply.record_num = session->ns_mover.md_record_num;
133 	reply.data_written =
134 	    long_long_to_quad(session->ns_mover.md_data_written);
135 	reply.seek_position =
136 	    long_long_to_quad(session->ns_mover.md_seek_position);
137 	reply.bytes_left_to_read =
138 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
139 	reply.window_offset =
140 	    long_long_to_quad(session->ns_mover.md_window_offset);
141 	reply.window_length =
142 	    long_long_to_quad(session->ns_mover.md_window_length);
143 
144 	ndmp_send_reply(connection, (void *) &reply,
145 	    "sending tape_get_state reply");
146 }
147 
148 
149 /*
150  * ndmpd_mover_listen_v2
151  *
152  * This handler handles mover_listen requests.
153  *
154  * Parameters:
155  *   connection (input) - connection handle.
156  *   body       (input) - request message body.
157  *
158  * Returns:
159  *   void
160  */
161 void
162 ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
163 {
164 	ndmp_mover_listen_request_v2 *request;
165 	ndmp_mover_listen_reply_v2 reply;
166 	ndmpd_session_t *session = ndmp_get_client_data(connection);
167 	ulong_t addr;
168 	ushort_t port;
169 
170 	request = (ndmp_mover_listen_request_v2 *)body;
171 
172 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
173 	    session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
174 		NDMP_LOG(LOG_DEBUG, "Invalid state");
175 		reply.error = NDMP_ILLEGAL_STATE_ERR;
176 		ndmp_send_reply(connection, (void *) &reply,
177 		    "sending mover_listen reply");
178 		return;
179 	}
180 	session->ns_mover.md_mode = request->mode;
181 
182 	if (request->addr_type == NDMP_ADDR_LOCAL) {
183 		reply.mover.addr_type = NDMP_ADDR_LOCAL;
184 	} else {
185 		if (create_listen_socket_v2(session, &addr, &port) < 0) {
186 			reply.error = NDMP_IO_ERR;
187 			ndmp_send_reply(connection, (void *) &reply,
188 			    "sending mover_listen reply");
189 			return;
190 		}
191 		reply.mover.addr_type = NDMP_ADDR_TCP;
192 		reply.mover.ndmp_mover_addr_u.addr.ip_addr = htonl(addr);
193 		reply.mover.ndmp_mover_addr_u.addr.port = htons(port);
194 	}
195 
196 	session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
197 
198 	/*
199 	 * ndmp window should always set by client during restore
200 	 */
201 
202 	/* Set the default window. */
203 	session->ns_mover.md_window_offset = 0;
204 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
205 	session->ns_mover.md_position = 0;
206 
207 	reply.error = NDMP_NO_ERR;
208 	ndmp_send_reply(connection, (void *) &reply,
209 	    "sending mover_listen reply");
210 }
211 
212 
213 /*
214  * ndmpd_mover_continue_v2
215  *
216  * This handler handles mover_continue requests.
217  *
218  * Parameters:
219  *   connection (input) - connection handle.
220  *   body       (input) - request message body.
221  *
222  * Returns:
223  *   void
224  */
225 /*ARGSUSED*/
226 void
227 ndmpd_mover_continue_v2(ndmp_connection_t *connection, void *body)
228 {
229 	ndmp_mover_continue_reply reply;
230 	ndmpd_session_t *session = ndmp_get_client_data(connection);
231 
232 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
233 		NDMP_LOG(LOG_DEBUG, "Invalid state");
234 
235 		reply.error = NDMP_ILLEGAL_STATE_ERR;
236 		ndmp_send_reply(connection, (void *) &reply,
237 		    "sending mover_continue reply");
238 		return;
239 	}
240 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
241 	reply.error = NDMP_NO_ERR;
242 	ndmp_send_reply(connection, (void *) &reply,
243 	    "sending mover_continue reply");
244 }
245 
246 
247 /*
248  * ndmpd_mover_abort_v2
249  *
250  * This handler handles mover_abort requests.
251  *
252  * Parameters:
253  *   connection (input) - connection handle.
254  *   body       (input) - request message body.
255  *
256  * Returns:
257  *   void
258  */
259 /*ARGSUSED*/
260 void
261 ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
262 {
263 	ndmp_mover_abort_reply reply;
264 	ndmpd_session_t *session = ndmp_get_client_data(connection);
265 
266 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
267 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
268 		NDMP_LOG(LOG_DEBUG, "Invalid state");
269 
270 		reply.error = NDMP_ILLEGAL_STATE_ERR;
271 		ndmp_send_reply(connection, (void *) &reply,
272 		    "sending mover_abort reply");
273 		return;
274 	}
275 
276 	reply.error = NDMP_NO_ERR;
277 	ndmp_send_reply(connection, (void *) &reply,
278 	    "sending mover_abort reply");
279 
280 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
281 	ndmp_stop_buffer_worker(session);
282 }
283 
284 
285 /*
286  * ndmpd_mover_stop_v2
287  *
288  * This handler handles mover_stop requests.
289  *
290  * Parameters:
291  *   connection (input) - connection handle.
292  *   body       (input) - request message body.
293  *
294  * Returns:
295  *   void
296  */
297 /*ARGSUSED*/
298 void
299 ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
300 {
301 	ndmp_mover_stop_reply reply;
302 	ndmpd_session_t *session = ndmp_get_client_data(connection);
303 
304 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {
305 		NDMP_LOG(LOG_DEBUG, "Invalid state");
306 
307 		reply.error = NDMP_ILLEGAL_STATE_ERR;
308 		ndmp_send_reply(connection, (void *) &reply,
309 		    "sending mover_stop reply");
310 		return;
311 	}
312 
313 	ndmp_waitfor_op(session);
314 	reply.error = NDMP_NO_ERR;
315 	ndmp_send_reply(connection, (void *) &reply,
316 	    "sending mover_stop reply");
317 
318 	ndmp_lbr_cleanup(session);
319 	ndmpd_mover_cleanup(session);
320 	(void) ndmpd_mover_init(session);
321 	(void) ndmp_lbr_init(session);
322 }
323 
324 
325 /*
326  * ndmpd_mover_set_window_v2
327  *
328  * This handler handles mover_set_window requests.
329  *
330  *
331  * Parameters:
332  *   connection (input) - connection handle.
333  *   body       (input) - request message body.
334  *
335  * Returns:
336  *   void
337  */
338 void
339 ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
340 {
341 	ndmp_mover_set_window_request *request;
342 	ndmp_mover_set_window_reply reply;
343 	ndmpd_session_t *session = ndmp_get_client_data(connection);
344 
345 	request = (ndmp_mover_set_window_request *) body;
346 
347 	/*
348 	 * The NDMPv2 specification states that "a window can be set only
349 	 * when in the listen or paused state."
350 	 *
351 	 * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
352 	 * allowing it in the idle state as well.
353 	 */
354 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
355 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
356 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
357 		reply.error = NDMP_ILLEGAL_STATE_ERR;
358 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
359 		    session->ns_mover.md_state);
360 	} else {
361 		if (quad_to_long_long(request->length) == 0) {
362 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
363 			NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
364 			    quad_to_long_long(request->length));
365 		} else {
366 			reply.error = NDMP_NO_ERR;
367 			session->ns_mover.md_window_offset =
368 			    quad_to_long_long(request->offset);
369 			session->ns_mover.md_window_length =
370 			    quad_to_long_long(request->length);
371 			session->ns_mover.md_position =
372 			    session->ns_mover.md_window_offset;
373 		}
374 	}
375 
376 	ndmp_send_reply(connection, (void *) &reply,
377 	    "sending mover_set_window reply");
378 }
379 
380 
381 /*
382  * ndmpd_mover_read_v2
383  *
384  * This handler handles mover_read requests. If the requested offset is
385  * outside of the current window, the mover is paused and a notify_mover_paused
386  * request is sent notifying the client that a seek is required. If the
387  * requested offest is within the window but not within the current record,
388  * then the tape is positioned to the record containing the requested offest.
389  * The requested amount of data is then read from the tape device and written
390  * to the data connection.
391  *
392  * Parameters:
393  *   connection (input) - connection handle.
394  *   body       (input) - request message body.
395  *
396  * Returns:
397  *   void
398  */
399 void
400 ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
401 {
402 	ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
403 	ndmp_mover_read_reply reply;
404 	ndmpd_session_t *session = ndmp_get_client_data(connection);
405 	int err;
406 
407 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
408 	    session->ns_mover.md_bytes_left_to_read != 0 ||
409 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
410 		NDMP_LOG(LOG_DEBUG, "Invalid state");
411 		reply.error = NDMP_ILLEGAL_STATE_ERR;
412 		ndmp_send_reply(connection, &reply,
413 		    "sending mover_read reply");
414 		return;
415 	}
416 	if (session->ns_tape.td_fd == -1) {
417 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
418 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
419 		ndmp_send_reply(connection, &reply,
420 		    "sending mover_read reply");
421 		return;
422 	}
423 
424 	reply.error = NDMP_NO_ERR;
425 	ndmp_send_reply(connection, &reply, "sending mover_read reply");
426 
427 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
428 	    quad_to_long_long(request->length));
429 	if (err < 0) {
430 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
431 		return;
432 	}
433 	/*
434 	 * Just return if we are waiting for the NDMP client to
435 	 * complete the seek.
436 	 */
437 	if (err == 1)
438 		return;
439 
440 	/*
441 	 * Start the mover for restore in the 3-way backups.
442 	 */
443 	if (start_mover_for_restore(session) < 0)
444 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
445 }
446 
447 
448 /*
449  * ndmpd_mover_close_v2
450  *
451  * This handler handles mover_close requests.
452  *
453  * Parameters:
454  *   connection (input) - connection handle.
455  *   body       (input) - request message body.
456  *
457  * Returns:
458  *   void
459  */
460 /*ARGSUSED*/
461 void
462 ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
463 {
464 	ndmp_mover_close_reply reply;
465 	ndmpd_session_t *session = ndmp_get_client_data(connection);
466 
467 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
468 		NDMP_LOG(LOG_DEBUG, "Invalid state");
469 
470 		reply.error = NDMP_ILLEGAL_STATE_ERR;
471 		ndmp_send_reply(connection, &reply,
472 		    "sending mover_close reply");
473 		return;
474 	}
475 	free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
476 
477 	reply.error = NDMP_NO_ERR;
478 	ndmp_send_reply(connection, &reply, "sending mover_close reply");
479 
480 	ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
481 }
482 
483 
484 /*
485  * ndmpd_mover_set_record_size_v2
486  *
487  * This handler handles mover_set_record_size requests.
488  *
489  * Parameters:
490  *   connection (input) - connection handle.
491  *   body       (input) - request message body.
492  *
493  * Returns:
494  *   void
495  */
496 void
497 ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
498 {
499 	ndmp_mover_set_record_size_request *request;
500 	ndmp_mover_set_record_size_reply reply;
501 	ndmpd_session_t *session = ndmp_get_client_data(connection);
502 
503 	request = (ndmp_mover_set_record_size_request *) body;
504 
505 	session->ns_mover.md_record_size = request->len;
506 	session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
507 	    request->len);
508 
509 	reply.error = NDMP_NO_ERR;
510 	ndmp_send_reply(connection, &reply,
511 	    "sending mover_set_record_size reply");
512 }
513 
514 
515 /*
516  * ************************************************************************
517  * NDMP V3 HANDLERS
518  * ************************************************************************
519  */
520 
521 /*
522  * ndmpd_mover_get_state_v3
523  *
524  * This handler handles the ndmp_mover_get_state_request.
525  * Status information for the mover state machine is returned.
526  *
527  * Parameters:
528  *   connection (input) - connection handle.
529  *   body       (input) - request message body.
530  *
531  * Returns:
532  *   void
533  */
534 /*ARGSUSED*/
535 void
536 ndmpd_mover_get_state_v3(ndmp_connection_t *connection, void *body)
537 {
538 	ndmp_mover_get_state_reply_v3 reply;
539 	ndmpd_session_t *session = ndmp_get_client_data(connection);
540 
541 	(void) memset((void*)&reply, 0, sizeof (reply));
542 
543 	reply.error = NDMP_NO_ERR;
544 	reply.state = session->ns_mover.md_state;
545 	reply.pause_reason = session->ns_mover.md_pause_reason;
546 	reply.halt_reason = session->ns_mover.md_halt_reason;
547 	reply.record_size = session->ns_mover.md_record_size;
548 	reply.record_num = session->ns_mover.md_record_num;
549 	reply.data_written =
550 	    long_long_to_quad(session->ns_mover.md_data_written);
551 	reply.seek_position =
552 	    long_long_to_quad(session->ns_mover.md_seek_position);
553 	reply.bytes_left_to_read =
554 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
555 	reply.window_offset =
556 	    long_long_to_quad(session->ns_mover.md_window_offset);
557 	reply.window_length =
558 	    long_long_to_quad(session->ns_mover.md_window_length);
559 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
560 		ndmp_copy_addr_v3(&reply.data_connection_addr,
561 		    &session->ns_mover.md_data_addr);
562 
563 	ndmp_send_reply(connection, &reply,
564 	    "sending ndmp_mover_get_state reply");
565 }
566 
567 
568 /*
569  * ndmpd_mover_listen_v3
570  *
571  * This handler handles ndmp_mover_listen_requests.
572  * A TCP/IP socket is created that is used to listen for
573  * and accept data connections initiated by a remote
574  * data server.
575  *
576  * Parameters:
577  *   connection (input) - connection handle.
578  *   body       (input) - request message body.
579  *
580  * Returns:
581  *   void
582  */
583 void
584 ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
585 {
586 	ndmp_mover_listen_request_v3 *request;
587 	ndmp_mover_listen_reply_v3 reply;
588 	ndmpd_session_t *session = ndmp_get_client_data(connection);
589 	ulong_t addr;
590 	ushort_t port;
591 
592 	request = (ndmp_mover_listen_request_v3 *)body;
593 
594 	(void) memset((void*)&reply, 0, sizeof (reply));
595 	reply.error = NDMP_NO_ERR;
596 
597 	if (request->mode != NDMP_MOVER_MODE_READ &&
598 	    request->mode != NDMP_MOVER_MODE_WRITE) {
599 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
600 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
601 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
602 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
603 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
604 		    request->addr_type);
605 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
606 		reply.error = NDMP_ILLEGAL_STATE_ERR;
607 		NDMP_LOG(LOG_DEBUG,
608 		    "Invalid mover state to process listen request");
609 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
610 		reply.error = NDMP_ILLEGAL_STATE_ERR;
611 		NDMP_LOG(LOG_DEBUG,
612 		    "Invalid data state to process listen request");
613 	} else if (session->ns_tape.td_fd == -1) {
614 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
615 		NDMP_LOG(LOG_DEBUG, "No tape device open");
616 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
617 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
618 		reply.error = NDMP_PERMISSION_ERR;
619 		NDMP_LOG(LOG_ERR, "Write protected device.");
620 	}
621 
622 	if (reply.error != NDMP_NO_ERR) {
623 		ndmp_send_reply(connection, &reply,
624 		    "error sending ndmp_mover_listen reply");
625 		return;
626 	}
627 
628 	switch (request->addr_type) {
629 	case NDMP_ADDR_LOCAL:
630 		reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
631 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
632 		reply.error = NDMP_NO_ERR;
633 		break;
634 	case NDMP_ADDR_TCP:
635 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
636 			reply.error = NDMP_IO_ERR;
637 			break;
638 		}
639 		reply.error = NDMP_NO_ERR;
640 		reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
641 		reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
642 		reply.data_connection_addr.tcp_port_v3 = htons(port);
643 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
644 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
645 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
646 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
647 		    session->ns_mover.md_listen_sock);
648 		break;
649 	default:
650 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
651 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
652 		    request->addr_type);
653 	}
654 
655 	if (reply.error == NDMP_NO_ERR) {
656 		session->ns_mover.md_mode = request->mode;
657 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
658 	}
659 
660 	ndmp_send_reply(connection, &reply,
661 	    "error sending ndmp_mover_listen reply");
662 }
663 
664 
665 /*
666  * ndmpd_mover_continue_v3
667  *
668  * This handler handles ndmp_mover_continue_requests.
669  *
670  * Parameters:
671  *   connection (input) - connection handle.
672  *   body       (input) - request message body.
673  *
674  * Returns:
675  *   void
676  */
677 /*ARGSUSED*/
678 void
679 ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
680 {
681 	ndmp_mover_continue_reply reply;
682 	ndmpd_session_t *session = ndmp_get_client_data(connection);
683 	ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
684 	int ret;
685 
686 	(void) memset((void*)&reply, 0, sizeof (reply));
687 
688 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
689 		NDMP_LOG(LOG_DEBUG, "Invalid state");
690 		reply.error = NDMP_ILLEGAL_STATE_ERR;
691 		ndmp_send_reply(connection, (void *) &reply,
692 		    "sending mover_continue reply");
693 		return;
694 	}
695 
696 	if (session->ns_protocol_version == NDMPV4 &&
697 	    !session->ns_mover.md_pre_cond) {
698 		NDMP_LOG(LOG_DEBUG, "Precondition check");
699 		reply.error = NDMP_PRECONDITION_ERR;
700 		ndmp_send_reply(connection, (void *) &reply,
701 		    "sending mover_continue reply");
702 		return;
703 	}
704 	/*
705 	 * Restore the file handler if the mover is remote to the data
706 	 * server and the handler was removed pending the continuation of a
707 	 * seek request. The handler is removed in mover_data_write().
708 	 */
709 	if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
710 	    session->ns_mover.md_sock != -1) {
711 		/*
712 		 * If we are here, it means that we needed DMA interference
713 		 * for seek. We should be on the right window, so we do not
714 		 * need the DMA interference anymore.
715 		 * We do another seek inside the Window to move to the
716 		 * exact position on the tape.
717 		 * If the resore is running without DAR the pause reason should
718 		 * not be seek.
719 		 */
720 		ret = ndmpd_mover_seek(session,
721 		    session->ns_mover.md_seek_position,
722 		    session->ns_mover.md_bytes_left_to_read);
723 		if (ret < 0) {
724 			ndmpd_mover_error(session,
725 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
726 			return;
727 		}
728 
729 		if (!ret) {
730 			if (ndmpd_add_file_handler(session, (void*) session,
731 			    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
732 			    HC_MOVER, mover_data_write_v3) < 0)
733 				ndmpd_mover_error(session,
734 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
735 		} else {
736 			/*
737 			 * This should not happen because we should be in the
738 			 * right window. This means that DMA does not follow
739 			 * the V3 spec.
740 			 */
741 			NDMP_LOG(LOG_DEBUG, "DMA Error.");
742 			ndmpd_mover_error(session,
743 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
744 			return;
745 		}
746 	}
747 
748 	(void) mutex_lock(&nlp->nlp_mtx);
749 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
750 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
751 	(void) cond_broadcast(&nlp->nlp_cv);
752 	(void) mutex_unlock(&nlp->nlp_mtx);
753 
754 	reply.error = NDMP_NO_ERR;
755 	ndmp_send_reply(connection, (void *) &reply,
756 	    "sending mover_continue reply");
757 }
758 
759 
760 /*
761  * ndmpd_mover_abort_v3
762  *
763  * This handler handles mover_abort requests.
764  *
765  * Parameters:
766  *   connection (input) - connection handle.
767  *   body       (input) - request message body.
768  *
769  * Returns:
770  *   void
771  */
772 /*ARGSUSED*/
773 void
774 ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
775 {
776 	ndmp_mover_abort_reply reply;
777 	ndmpd_session_t *session = ndmp_get_client_data(connection);
778 
779 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
780 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
781 		NDMP_LOG(LOG_DEBUG, "Invalid state");
782 
783 		reply.error = NDMP_ILLEGAL_STATE_ERR;
784 		ndmp_send_reply(connection, (void *) &reply,
785 		    "sending mover_abort reply");
786 		return;
787 	}
788 
789 	reply.error = NDMP_NO_ERR;
790 	ndmp_send_reply(connection, (void *) &reply,
791 	    "sending mover_abort reply");
792 
793 	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
794 }
795 
796 
797 /*
798  * ndmpd_mover_set_window_v3
799  *
800  * This handler handles mover_set_window requests.
801  *
802  *
803  * Parameters:
804  *   connection (input) - connection handle.
805  *   body       (input) - request message body.
806  *
807  * Returns:
808  *   void
809  */
810 void
811 ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
812 {
813 	ndmp_mover_set_window_request *request;
814 	ndmp_mover_set_window_reply reply;
815 	ndmpd_session_t *session = ndmp_get_client_data(connection);
816 
817 	request = (ndmp_mover_set_window_request *) body;
818 
819 	/*
820 	 * Note: The spec says that the window can be set only in the listen
821 	 * and paused states.  We let this happen when mover is in the idle
822 	 * state as well.  I can't rememebr which NDMP client (net_backup 4.5
823 	 * or net_worker 6.1.1) forced us to do this!
824 	 */
825 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
826 	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
827 	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
828 		reply.error = NDMP_ILLEGAL_STATE_ERR;
829 		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
830 		    session->ns_mover.md_state);
831 	} else if (session->ns_mover.md_record_size == 0) {
832 		if (session->ns_protocol_version == NDMPV4)
833 			reply.error = NDMP_PRECONDITION_ERR;
834 		else
835 			reply.error = NDMP_ILLEGAL_ARGS_ERR;
836 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
837 	} else
838 		reply.error = NDMP_NO_ERR;
839 
840 	if (quad_to_long_long(request->length) == 0) {
841 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
842 		NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
843 		    quad_to_long_long(request->length));
844 	}
845 
846 	if (reply.error != NDMP_NO_ERR) {
847 		ndmp_send_reply(connection, (void *) &reply,
848 		    "sending mover_set_window_v3 reply");
849 		return;
850 	}
851 
852 	session->ns_mover.md_pre_cond = TRUE;
853 	session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
854 	session->ns_mover.md_window_length = quad_to_long_long(request->length);
855 
856 	/*
857 	 * We have to update the position for DAR. DAR needs this
858 	 * information to position to the right index on tape,
859 	 * especially when we span the tapes.
860 	 */
861 #ifdef	NO_POSITION_CHANGE
862 	/*
863 	 * Do not change the mover position if we are reading from
864 	 * the tape.  In this way, we can use the position+window_length
865 	 * to know how much we can write to a tape before pausing with
866 	 * EOW reason.
867 	 */
868 	if (session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE)
869 #endif	/* NO_POSITION_CHANGE */
870 		session->ns_mover.md_position =
871 		    session->ns_mover.md_window_offset;
872 
873 	ndmp_send_reply(connection, (void *) &reply,
874 	    "sending mover_set_window_v3 reply");
875 }
876 
877 
878 /*
879  * ndmpd_mover_read_v3
880  *
881  * This handler handles ndmp_mover_read_requests.
882  * If the requested offset is outside of the current window, the mover
883  * is paused and a notify_mover_paused request is sent notifying the
884  * client that a seek is required. If the requested offest is within
885  * the window but not within the current record, then the tape is
886  * positioned to the record containing the requested offest. The requested
887  * amount of data is then read from the tape device and written to the
888  * data connection.
889  *
890  * Parameters:
891  *   connection (input) - connection handle.
892  *   body       (input) - request message body.
893  *
894  * Returns:
895  *   void
896  */
897 void
898 ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
899 {
900 	ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
901 	ndmp_mover_read_reply reply;
902 	ndmpd_session_t *session = ndmp_get_client_data(connection);
903 	int err;
904 
905 	(void) memset((void*)&reply, 0, sizeof (reply));
906 
907 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
908 	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
909 		reply.error = NDMP_ILLEGAL_STATE_ERR;
910 		NDMP_LOG(LOG_DEBUG, "Invalid state");
911 	} else if (session->ns_mover.md_bytes_left_to_read != 0) {
912 		reply.error = NDMP_READ_IN_PROGRESS_ERR;
913 		NDMP_LOG(LOG_DEBUG, "In progress");
914 	} else if (session->ns_tape.td_fd == -1) {
915 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
916 		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
917 	} else if (quad_to_long_long(request->length) == 0 ||
918 	    (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
919 	    quad_to_long_long(request->offset) != 0)) {
920 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
921 		NDMP_LOG(LOG_DEBUG, "Illegal args");
922 	} else {
923 		reply.error = NDMP_NO_ERR;
924 	}
925 
926 	ndmp_send_reply(connection, (void *) &reply,
927 	    "sending ndmp_mover_read_reply");
928 	if (reply.error != NDMP_NO_ERR)
929 		return;
930 
931 	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
932 	    quad_to_long_long(request->length));
933 	if (err < 0) {
934 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
935 		return;
936 	}
937 
938 	/*
939 	 * Just return if we are waiting for the DMA to complete the seek.
940 	 */
941 	if (err == 1)
942 		return;
943 
944 	/*
945 	 * Setup a handler function that will be called when
946 	 * data can be written to the data connection without blocking.
947 	 */
948 	if (ndmpd_add_file_handler(session, (void*)session,
949 	    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE, HC_MOVER,
950 	    mover_data_write_v3) < 0) {
951 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
952 		return;
953 	}
954 }
955 
956 
957 /*
958  * ndmpd_mover_set_record_size_v3
959  *
960  * This handler handles mover_set_record_size requests.
961  *
962  * Parameters:
963  *   connection (input) - connection handle.
964  *   body       (input) - request message body.
965  *
966  * Returns:
967  *   void
968  */
969 void
970 ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
971 {
972 	ndmp_mover_set_record_size_request *request;
973 	ndmp_mover_set_record_size_reply reply;
974 	ndmpd_session_t *session = ndmp_get_client_data(connection);
975 	char *cp;
976 
977 	request = (ndmp_mover_set_record_size_request *) body;
978 
979 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
980 		reply.error = NDMP_ILLEGAL_STATE_ERR;
981 		NDMP_LOG(LOG_DEBUG, "Invalid mover state %d",
982 		    session->ns_mover.md_state);
983 	} else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
984 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
985 		NDMP_LOG(LOG_DEBUG,
986 		    "Invalid argument %d, should be > 0 and <= %d",
987 		    request->len, ndmp_max_mover_recsize);
988 	} else if (request->len == session->ns_mover.md_record_size)
989 		reply.error = NDMP_NO_ERR;
990 	else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
991 		reply.error = NDMP_NO_MEM_ERR;
992 	} else {
993 		reply.error = NDMP_NO_ERR;
994 		session->ns_mover.md_buf = cp;
995 		session->ns_mover.md_record_size = request->len;
996 		session->ns_mover.md_window_offset = 0;
997 		session->ns_mover.md_window_length = 0;
998 	}
999 
1000 	ndmp_send_reply(connection, (void *) &reply,
1001 	    "sending mover_set_record_size reply");
1002 }
1003 
1004 
1005 /*
1006  * ndmpd_mover_connect_v3
1007  *   Request handler. Connects the mover to either a local
1008  *   or remote data server.
1009  *
1010  * Parameters:
1011  *   connection (input) - connection handle.
1012  *   body       (input) - request message body.
1013  *
1014  * Returns:
1015  *   void
1016  */
1017 void
1018 ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
1019 {
1020 	ndmp_mover_connect_request_v3 *request;
1021 	ndmp_mover_connect_reply_v3 reply;
1022 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1023 
1024 	request = (ndmp_mover_connect_request_v3*)body;
1025 
1026 	(void) memset((void*)&reply, 0, sizeof (reply));
1027 
1028 	if (request->mode != NDMP_MOVER_MODE_READ &&
1029 	    request->mode != NDMP_MOVER_MODE_WRITE) {
1030 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1031 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1032 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1033 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1034 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1035 		    request->addr.addr_type);
1036 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1037 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1038 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1039 		    session->ns_mover.md_state);
1040 	} else if (session->ns_tape.td_fd == -1) {
1041 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1042 		NDMP_LOG(LOG_DEBUG, "No tape device open");
1043 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1044 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1045 		reply.error = NDMP_WRITE_PROTECT_ERR;
1046 		NDMP_LOG(LOG_ERR, "Write protected device.");
1047 	} else
1048 		reply.error = NDMP_NO_ERR;
1049 
1050 	if (reply.error != NDMP_NO_ERR) {
1051 		ndmp_send_reply(connection, (void *) &reply,
1052 		    "sending ndmp_mover_connect reply");
1053 		return;
1054 	}
1055 
1056 	switch (request->addr.addr_type) {
1057 	case NDMP_ADDR_LOCAL:
1058 		/*
1059 		 * Verify that the data server is listening for a
1060 		 * local connection.
1061 		 */
1062 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1063 		    session->ns_data.dd_listen_sock != -1) {
1064 			NDMP_LOG(LOG_DEBUG,
1065 			    "Data server is not in local listen state");
1066 			reply.error = NDMP_ILLEGAL_STATE_ERR;
1067 		} else
1068 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1069 		break;
1070 
1071 	case NDMP_ADDR_TCP:
1072 		reply.error = mover_connect_sock_v3(session, request->mode,
1073 		    request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
1074 		break;
1075 
1076 	default:
1077 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1078 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1079 		    request->addr.addr_type);
1080 	}
1081 
1082 	if (reply.error == NDMP_NO_ERR) {
1083 		session->ns_mover.md_data_addr.addr_type =
1084 		    request->addr.addr_type;
1085 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1086 		session->ns_mover.md_mode = request->mode;
1087 	}
1088 
1089 	ndmp_send_reply(connection, (void *) &reply,
1090 	    "sending ndmp_mover_connect reply");
1091 }
1092 
1093 
1094 /*
1095  * ************************************************************************
1096  * NDMP V4 HANDLERS
1097  * ************************************************************************
1098  */
1099 
1100 /*
1101  * ndmpd_mover_get_state_v4
1102  *
1103  * This handler handles the ndmp_mover_get_state_request.
1104  * Status information for the mover state machine is returned.
1105  *
1106  * Parameters:
1107  *   connection (input) - connection handle.
1108  *   body       (input) - request message body.
1109  *
1110  * Returns:
1111  *   void
1112  */
1113 /*ARGSUSED*/
1114 void
1115 ndmpd_mover_get_state_v4(ndmp_connection_t *connection, void *body)
1116 {
1117 	ndmp_mover_get_state_reply_v4 reply;
1118 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1119 
1120 	(void) memset((void*)&reply, 0, sizeof (reply));
1121 
1122 	reply.error = NDMP_NO_ERR;
1123 	reply.state = session->ns_mover.md_state;
1124 	reply.mode = session->ns_mover.md_mode;
1125 	reply.pause_reason = session->ns_mover.md_pause_reason;
1126 	reply.halt_reason = session->ns_mover.md_halt_reason;
1127 	reply.record_size = session->ns_mover.md_record_size;
1128 	reply.record_num = session->ns_mover.md_record_num;
1129 	reply.bytes_moved =
1130 	    long_long_to_quad(session->ns_mover.md_data_written);
1131 	reply.seek_position =
1132 	    long_long_to_quad(session->ns_mover.md_seek_position);
1133 	reply.bytes_left_to_read =
1134 	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
1135 	reply.window_offset =
1136 	    long_long_to_quad(session->ns_mover.md_window_offset);
1137 	reply.window_length =
1138 	    long_long_to_quad(session->ns_mover.md_window_length);
1139 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
1140 		ndmp_copy_addr_v4(&reply.data_connection_addr,
1141 		    &session->ns_mover.md_data_addr_v4);
1142 
1143 	ndmp_send_reply(connection, (void *) &reply,
1144 	    "sending ndmp_mover_get_state reply");
1145 	free(reply.data_connection_addr.tcp_addr_v4);
1146 }
1147 
1148 
1149 /*
1150  * ndmpd_mover_listen_v4
1151  *
1152  * This handler handles ndmp_mover_listen_requests.
1153  * A TCP/IP socket is created that is used to listen for
1154  * and accept data connections initiated by a remote
1155  * data server.
1156  *
1157  * Parameters:
1158  *   connection (input) - connection handle.
1159  *   body       (input) - request message body.
1160  *
1161  * Returns:
1162  *   void
1163  */
1164 void
1165 ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
1166 {
1167 	ndmp_mover_listen_request_v4 *request;
1168 
1169 	ndmp_mover_listen_reply_v4 reply;
1170 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1171 	ulong_t addr;
1172 	ushort_t port;
1173 
1174 	request = (ndmp_mover_listen_request_v4 *)body;
1175 
1176 	(void) memset((void*)&reply, 0, sizeof (reply));
1177 	reply.error = NDMP_NO_ERR;
1178 
1179 	if (request->mode != NDMP_MOVER_MODE_READ &&
1180 	    request->mode != NDMP_MOVER_MODE_WRITE) {
1181 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1182 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1183 	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
1184 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1185 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1186 		    request->addr_type);
1187 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1188 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1189 		NDMP_LOG(LOG_DEBUG,
1190 		    "Invalid mover state to process listen request");
1191 	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1192 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1193 		NDMP_LOG(LOG_DEBUG,
1194 		    "Invalid data state to process listen request");
1195 	} else if (session->ns_tape.td_fd == -1) {
1196 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1197 		NDMP_LOG(LOG_DEBUG, "No tape device open");
1198 	} else if (session->ns_mover.md_record_size == 0) {
1199 		reply.error = NDMP_PRECONDITION_ERR;
1200 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1201 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1202 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1203 		reply.error = NDMP_PERMISSION_ERR;
1204 		NDMP_LOG(LOG_ERR, "Write protected device.");
1205 	}
1206 
1207 	if (reply.error != NDMP_NO_ERR) {
1208 		ndmp_send_reply(connection, (void *) &reply,
1209 		    "error sending ndmp_mover_listen reply");
1210 		return;
1211 	}
1212 
1213 	switch (request->addr_type) {
1214 	case NDMP_ADDR_LOCAL:
1215 		reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
1216 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
1217 		reply.error = NDMP_NO_ERR;
1218 		break;
1219 	case NDMP_ADDR_TCP:
1220 		if (create_listen_socket_v3(session, &addr, &port) < 0) {
1221 			reply.error = NDMP_IO_ERR;
1222 			break;
1223 		}
1224 		reply.error = NDMP_NO_ERR;
1225 
1226 		session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1227 		session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
1228 		session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
1229 		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1230 
1231 		session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
1232 		session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1233 
1234 		ndmp_copy_addr_v4(&reply.connect_addr,
1235 		    &session->ns_mover.md_data_addr_v4);
1236 
1237 		/* For compatibility with V3 */
1238 		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
1239 		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
1240 		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
1241 		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
1242 		    session->ns_mover.md_listen_sock);
1243 		break;
1244 	default:
1245 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1246 		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
1247 		    request->addr_type);
1248 	}
1249 
1250 	if (reply.error == NDMP_NO_ERR) {
1251 		session->ns_mover.md_mode = request->mode;
1252 		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
1253 	}
1254 
1255 	ndmp_send_reply(connection, (void *) &reply,
1256 	    "error sending ndmp_mover_listen reply");
1257 	free(reply.connect_addr.tcp_addr_v4);
1258 }
1259 
1260 /*
1261  * ndmpd_mover_connect_v4
1262  *   Request handler. Connects the mover to either a local
1263  *   or remote data server.
1264  *
1265  * Parameters:
1266  *   connection (input) - connection handle.
1267  *   body       (input) - request message body.
1268  *
1269  * Returns:
1270  *   void
1271  */
1272 void
1273 ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
1274 {
1275 	ndmp_mover_connect_request_v4 *request;
1276 	ndmp_mover_connect_reply_v4 reply;
1277 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1278 
1279 	request = (ndmp_mover_connect_request_v4 *)body;
1280 	(void) memset((void*)&reply, 0, sizeof (reply));
1281 
1282 	if (request->mode != NDMP_MOVER_MODE_READ &&
1283 	    request->mode != NDMP_MOVER_MODE_WRITE) {
1284 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1285 		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1286 	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1287 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1288 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1289 		    request->addr.addr_type);
1290 	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1291 		reply.error = NDMP_ILLEGAL_STATE_ERR;
1292 		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1293 		    session->ns_mover.md_state);
1294 	} else if (session->ns_tape.td_fd == -1) {
1295 		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1296 		NDMP_LOG(LOG_DEBUG, "No tape device open");
1297 	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1298 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1299 		reply.error = NDMP_PERMISSION_ERR;
1300 		NDMP_LOG(LOG_ERR, "Write protected device.");
1301 	} else if (session->ns_mover.md_record_size == 0) {
1302 		reply.error = NDMP_PRECONDITION_ERR;
1303 		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1304 	} else
1305 		reply.error = NDMP_NO_ERR;
1306 
1307 	if (reply.error != NDMP_NO_ERR) {
1308 		ndmp_send_reply(connection, (void *) &reply,
1309 		    "sending ndmp_mover_connect reply");
1310 		return;
1311 	}
1312 
1313 	switch (request->addr.addr_type) {
1314 	case NDMP_ADDR_LOCAL:
1315 		/*
1316 		 * Verify that the data server is listening for a
1317 		 * local connection.
1318 		 */
1319 		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1320 		    session->ns_data.dd_listen_sock != -1) {
1321 			NDMP_LOG(LOG_DEBUG,
1322 			    "Data server is not in local listen state");
1323 			reply.error = NDMP_ILLEGAL_STATE_ERR;
1324 		} else
1325 			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1326 		break;
1327 
1328 	case NDMP_ADDR_TCP:
1329 		reply.error = mover_connect_sock_v3(session, request->mode,
1330 		    request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
1331 		break;
1332 
1333 	default:
1334 		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1335 		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1336 		    request->addr.addr_type);
1337 	}
1338 
1339 	if (reply.error == NDMP_NO_ERR) {
1340 		session->ns_mover.md_data_addr.addr_type =
1341 		    request->addr.addr_type;
1342 		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1343 		session->ns_mover.md_mode = request->mode;
1344 	}
1345 
1346 	ndmp_send_reply(connection, (void *) &reply,
1347 	    "sending ndmp_mover_connect reply");
1348 }
1349 
1350 
1351 
1352 /*
1353  * ************************************************************************
1354  * LOCALS
1355  * ************************************************************************
1356  */
1357 
1358 /*
1359  * ndmpd_local_write
1360  *
1361  * Writes data to the mover.
1362  * Buffers and write data to the tape device.
1363  * A full tape record is buffered before being written.
1364  *
1365  * Parameters:
1366  *   session    (input) - session pointer.
1367  *   data       (input) - data to be written.
1368  *   length     (input) - data length.
1369  *
1370  * Returns:
1371  *   0 - data successfully written.
1372  *  -1 - error.
1373  */
1374 int
1375 ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
1376 {
1377 	ulong_t count = 0;
1378 	ssize_t n;
1379 	ulong_t len;
1380 
1381 	/*
1382 	 * A length of 0 indicates that any buffered data should be
1383 	 * flushed to tape.
1384 	 */
1385 	if (length == 0) {
1386 		if (session->ns_mover.md_w_index == 0)
1387 			return (0);
1388 
1389 		(void) memset(
1390 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1391 		    0, session->ns_mover.md_record_size -
1392 		    session->ns_mover.md_w_index);
1393 
1394 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
1395 		    session->ns_mover.md_record_size);
1396 		if (n <= 0) {
1397 			ndmpd_mover_error(session,
1398 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1399 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
1400 			return (-1);
1401 		}
1402 		session->ns_mover.md_position += n;
1403 		session->ns_mover.md_data_written +=
1404 		    session->ns_mover.md_w_index;
1405 		session->ns_mover.md_record_num++;
1406 		session->ns_mover.md_w_index = 0;
1407 		return (0);
1408 	}
1409 	/* Break the data into records. */
1410 	while (count < length) {
1411 		/*
1412 		 * Determine if data needs to be buffered or
1413 		 * can be written directly from user supplied location.
1414 		 * We can fast path the write if there is no pending
1415 		 * buffered data and there is at least a full record's worth
1416 		 * of data to be written.
1417 		 */
1418 		if (session->ns_mover.md_w_index == 0 &&
1419 		    length - count >= session->ns_mover.md_record_size) {
1420 			n = mover_tape_write_v3(session, &data[count],
1421 			    session->ns_mover.md_record_size);
1422 			if (n <= 0) {
1423 				ndmpd_mover_error(session,
1424 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1425 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1426 				return (-1);
1427 			}
1428 			session->ns_mover.md_position += n;
1429 			session->ns_mover.md_data_written += n;
1430 			session->ns_mover.md_record_num++;
1431 			count += n;
1432 			continue;
1433 		}
1434 		/* Buffer the data */
1435 		len = length - count;
1436 		if (len > session->ns_mover.md_record_size -
1437 		    session->ns_mover.md_w_index)
1438 			len = session->ns_mover.md_record_size -
1439 			    session->ns_mover.md_w_index;
1440 
1441 		(void) memcpy(
1442 		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1443 		    &data[count], len);
1444 		session->ns_mover.md_w_index += len;
1445 		count += len;
1446 
1447 		/* Write the buffer if its full */
1448 		if (session->ns_mover.md_w_index ==
1449 		    session->ns_mover.md_record_size) {
1450 			n = mover_tape_write_v3(session,
1451 			    session->ns_mover.md_buf,
1452 			    session->ns_mover.md_record_size);
1453 			if (n <= 0) {
1454 				ndmpd_mover_error(session,
1455 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1456 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1457 				return (-1);
1458 			}
1459 			session->ns_mover.md_position += n;
1460 			session->ns_mover.md_data_written += n;
1461 			session->ns_mover.md_record_num++;
1462 			session->ns_mover.md_w_index = 0;
1463 		}
1464 	}
1465 
1466 	return (0);
1467 }
1468 
1469 
1470 /*
1471  * ndmpd_remote_write
1472  *
1473  * Writes data to the remote mover.
1474  *
1475  * Parameters:
1476  *   session    (input) - session pointer.
1477  *   data       (input) - data to be written.
1478  *   length     (input) - data length.
1479  *
1480  * Returns:
1481  *   0 - data successfully written.
1482  *  -1 - error.
1483  */
1484 int
1485 ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
1486 {
1487 	ssize_t n;
1488 	ulong_t count = 0;
1489 
1490 	while (count < length) {
1491 		if (session->ns_eof == TRUE ||
1492 		    session->ns_data.dd_abort == TRUE)
1493 			return (-1);
1494 
1495 		if ((n = write(session->ns_data.dd_sock, &data[count],
1496 		    length - count)) < 0) {
1497 			NDMP_LOG(LOG_ERR, "Socket write error: %m.");
1498 			return (-1);
1499 		}
1500 		count += n;
1501 	}
1502 
1503 	return (0);
1504 }
1505 
1506 /*
1507  * ndmpd_local_read
1508  *
1509  * Reads data from the local tape device.
1510  * Full tape records are read and buffered.
1511  *
1512  * Parameters:
1513  *   session (input) - session pointer.
1514  *   data    (input) - location to store data.
1515  *   length  (input) - data length.
1516  *
1517  * Returns:
1518  *   0 - data successfully read.
1519  *  -1 - error.
1520  *   1 - session terminated or operation aborted.
1521  */
1522 int
1523 ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
1524 {
1525 	ulong_t count = 0;
1526 	ssize_t n;
1527 	ulong_t len;
1528 	ndmp_notify_mover_paused_request pause_request;
1529 
1530 	/*
1531 	 * Automatically increase the seek window if necessary.
1532 	 * This is needed in the event the module attempts to read
1533 	 * past a seek window set via a prior call to ndmpd_seek() or
1534 	 * the module has not issued a seek. If no seek was issued then
1535 	 * pretend that a seek was issued to read the entire tape.
1536 	 */
1537 	if (length > session->ns_mover.md_bytes_left_to_read) {
1538 		/* ndmpd_seek() never called? */
1539 		if (session->ns_data.dd_read_length == 0) {
1540 			session->ns_mover.md_bytes_left_to_read = ~0LL;
1541 			session->ns_data.dd_read_offset = 0LL;
1542 			session->ns_data.dd_read_length = ~0LL;
1543 		} else {
1544 			session->ns_mover.md_bytes_left_to_read = length;
1545 			session->ns_data.dd_read_offset =
1546 			    session->ns_mover.md_position;
1547 			session->ns_data.dd_read_length = length;
1548 		}
1549 	}
1550 	/*
1551 	 * Read as many records as necessary to satisfy the request.
1552 	 */
1553 	while (count < length) {
1554 		/*
1555 		 * If the end of the mover window has been reached,
1556 		 * then notify the client that a new data window is needed.
1557 		 */
1558 		if (session->ns_mover.md_position >=
1559 		    session->ns_mover.md_window_offset +
1560 		    session->ns_mover.md_window_length) {
1561 
1562 			session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
1563 			session->ns_mover.md_pause_reason =
1564 			    NDMP_MOVER_PAUSE_SEEK;
1565 			pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
1566 			pause_request.seek_position =
1567 			    long_long_to_quad(session->ns_mover.md_position);
1568 
1569 			if (ndmp_send_request(session->ns_connection,
1570 			    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
1571 			    (void *) &pause_request, 0) < 0) {
1572 				NDMP_LOG(LOG_DEBUG,
1573 				    "Sending notify_mover_paused request");
1574 				ndmpd_mover_error(session,
1575 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
1576 				return (-1);
1577 			}
1578 			/*
1579 			 * Wait until the state is changed by
1580 			 * an abort or continue request.
1581 			 */
1582 			if (ndmp_wait_for_mover(session) != 0)
1583 				return (1);
1584 		}
1585 		len = length - count;
1586 
1587 		/*
1588 		 * Prevent reading past the end of the window.
1589 		 */
1590 		if (len >
1591 		    session->ns_mover.md_window_offset +
1592 		    session->ns_mover.md_window_length -
1593 		    session->ns_mover.md_position)
1594 			len = session->ns_mover.md_window_offset +
1595 			    session->ns_mover.md_window_length -
1596 			    session->ns_mover.md_position;
1597 
1598 		/*
1599 		 * Copy from the data buffer first.
1600 		 */
1601 		if (session->ns_mover.md_w_index -
1602 		    session->ns_mover.md_r_index != 0) {
1603 			/*
1604 			 * Limit the copy to the amount of data in the buffer.
1605 			 */
1606 			if (len > session->ns_mover.md_w_index -
1607 			    session->ns_mover.md_r_index)
1608 				len = session->ns_mover.md_w_index
1609 				    - session->ns_mover.md_r_index;
1610 
1611 			(void) memcpy((void *) &data[count],
1612 			    &session->ns_mover.md_buf[session->
1613 			    ns_mover.md_r_index], len);
1614 			count += len;
1615 			session->ns_mover.md_r_index += len;
1616 			session->ns_mover.md_bytes_left_to_read -= len;
1617 			session->ns_mover.md_position += len;
1618 			continue;
1619 		}
1620 		/*
1621 		 * Determine if data needs to be buffered or
1622 		 * can be read directly to user supplied location.
1623 		 * We can fast path the read if at least a full record
1624 		 * needs to be read and there is no seek pending.
1625 		 * This is done to eliminate a buffer copy.
1626 		 */
1627 		if (len >= session->ns_mover.md_record_size &&
1628 		    session->ns_mover.md_position >=
1629 		    session->ns_mover.md_seek_position) {
1630 			n = tape_read(session, &data[count]);
1631 			if (n <= 0) {
1632 				if (n == TAPE_NO_WRITER_ERR)
1633 					return (1);
1634 
1635 				ndmpd_mover_error(session,
1636 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1637 				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1638 				return (n == 0) ? (1) : (-1);
1639 			}
1640 			count += n;
1641 			session->ns_mover.md_bytes_left_to_read -= n;
1642 			session->ns_mover.md_position += n;
1643 			continue;
1644 		}
1645 		/* Read the next record into the buffer. */
1646 		n = tape_read(session, session->ns_mover.md_buf);
1647 		if (n <= 0) {
1648 			if (n == TAPE_NO_WRITER_ERR)
1649 				return (1);
1650 
1651 			ndmpd_mover_error(session,
1652 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1653 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
1654 			return (n == 0) ? (1) : (-1);
1655 		}
1656 		session->ns_mover.md_w_index = n;
1657 		session->ns_mover.md_r_index = 0;
1658 
1659 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
1660 
1661 		/*
1662 		 * Discard data if the current data stream position is
1663 		 * prior to the seek position. This is necessary if a seek
1664 		 * request set the seek pointer to a position that is not a
1665 		 * record boundary. The seek request handler can only position
1666 		 * to the start of a record.
1667 		 */
1668 		if (session->ns_mover.md_position <
1669 		    session->ns_mover.md_seek_position) {
1670 			session->ns_mover.md_r_index =
1671 			    session->ns_mover.md_seek_position -
1672 			    session->ns_mover.md_position;
1673 			session->ns_mover.md_position =
1674 			    session->ns_mover.md_seek_position;
1675 		}
1676 	}
1677 
1678 	return (0);
1679 }
1680 
1681 
1682 /*
1683  * ndmpd_remote_read
1684  *
1685  * Reads data from the remote mover.
1686  *
1687  * Parameters:
1688  *   session (input) - session pointer.
1689  *   data    (input) - data to be written.
1690  *   length  (input) - data length.
1691  *
1692  * Returns:
1693  *   0 - data successfully read.
1694  *  -1 - error.
1695  *   1 - session terminated or operation aborted.
1696  */
1697 int
1698 ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
1699 {
1700 	ulong_t count = 0;
1701 	ssize_t n;
1702 	ulong_t len;
1703 	ndmp_notify_data_read_request request;
1704 
1705 	while (count < length) {
1706 		len = length - count;
1707 
1708 		/*
1709 		 * If the end of the seek window has been reached then
1710 		 * send an ndmp_read request to the client.
1711 		 * The NDMP client will then send a mover_data_read request to
1712 		 * the remote mover and the mover will send more data.
1713 		 * This condition can occur if the module attempts to read past
1714 		 * a seek window set via a prior call to ndmpd_seek() or
1715 		 * the module has not issued a seek. If no seek was issued then
1716 		 * pretend that a seek was issued to read the entire tape.
1717 		 */
1718 		if (session->ns_mover.md_bytes_left_to_read == 0) {
1719 			/* ndmpd_seek() never called? */
1720 			if (session->ns_data.dd_read_length == 0) {
1721 				session->ns_mover.md_bytes_left_to_read = ~0LL;
1722 				session->ns_data.dd_read_offset = 0LL;
1723 				session->ns_data.dd_read_length = ~0LL;
1724 			} else {
1725 				session->ns_mover.md_bytes_left_to_read = len;
1726 				session->ns_data.dd_read_offset =
1727 				    session->ns_mover.md_position;
1728 				session->ns_data.dd_read_length = len;
1729 			}
1730 
1731 			request.offset =
1732 			    long_long_to_quad(session->ns_data.dd_read_offset);
1733 			request.length =
1734 			    long_long_to_quad(session->ns_data.dd_read_length);
1735 
1736 			if (ndmp_send_request_lock(session->ns_connection,
1737 			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1738 			    (void *) &request, 0) < 0) {
1739 				NDMP_LOG(LOG_DEBUG,
1740 				    "Sending notify_data_read request");
1741 				return (-1);
1742 			}
1743 		}
1744 		if (session->ns_eof == TRUE ||
1745 		    session->ns_data.dd_abort == TRUE)
1746 			return (1);
1747 
1748 		/*
1749 		 * If the module called ndmpd_seek() prior to reading all of the
1750 		 * data that the remote mover was requested to send, then the
1751 		 * excess data from the seek has to be discardd.
1752 		 */
1753 		if (session->ns_mover.md_discard_length != 0) {
1754 			n = discard_data(session,
1755 			    (ulong_t)session->ns_mover.md_discard_length);
1756 			if (n < 0)
1757 				return (-1);
1758 			session->ns_mover.md_discard_length -= n;
1759 			continue;
1760 		}
1761 		/*
1762 		 * Don't attempt to read more data than the remote is sending.
1763 		 */
1764 		if (len > session->ns_mover.md_bytes_left_to_read)
1765 			len = session->ns_mover.md_bytes_left_to_read;
1766 
1767 		NDMP_LOG(LOG_DEBUG, "len: %u", len);
1768 
1769 		if ((n = read(session->ns_data.dd_sock, &data[count],
1770 		    len)) < 0) {
1771 			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1772 			return (-1);
1773 		}
1774 		/* read returns 0 if the connection was closed */
1775 		if (n == 0)
1776 			return (-1);
1777 
1778 		count += n;
1779 		session->ns_mover.md_bytes_left_to_read -= n;
1780 		session->ns_mover.md_position += n;
1781 	}
1782 
1783 	return (0);
1784 }
1785 
1786 /* *** ndmpd internal functions ***************************************** */
1787 
1788 /*
1789  * ndmpd_mover_init
1790  *
1791  * Initialize mover specific session variables.
1792  * Don't initialize variables such as record_size that need to
1793  * persist across data operations. A client may open a connection and
1794  * do multiple backups after setting the record_size.
1795  *
1796  * Parameters:
1797  *   session (input) - session pointer.
1798  *
1799  * Returns:
1800  *   0 - success.
1801  *  -1 - error.
1802  */
1803 int
1804 ndmpd_mover_init(ndmpd_session_t *session)
1805 {
1806 	session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
1807 	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
1808 	session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
1809 	session->ns_mover.md_data_written = 0LL;
1810 	session->ns_mover.md_seek_position = 0LL;
1811 	session->ns_mover.md_bytes_left_to_read = 0LL;
1812 	session->ns_mover.md_window_offset = 0LL;
1813 	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
1814 	session->ns_mover.md_position = 0LL;
1815 	session->ns_mover.md_discard_length = 0;
1816 	session->ns_mover.md_record_num = 0;
1817 	session->ns_mover.md_record_size = 0;
1818 	session->ns_mover.md_listen_sock = -1;
1819 	session->ns_mover.md_pre_cond = FALSE;
1820 	session->ns_mover.md_sock = -1;
1821 	session->ns_mover.md_r_index = 0;
1822 	session->ns_mover.md_w_index = 0;
1823 	session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
1824 	if (!session->ns_mover.md_buf)
1825 		return (-1);
1826 
1827 	if (ndmp_get_version(session->ns_connection) == NDMPV3) {
1828 		session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
1829 		(void) memset(&session->ns_mover.md_data_addr, 0,
1830 		    sizeof (ndmp_addr_v3));
1831 	}
1832 	return (0);
1833 }
1834 
1835 
1836 /*
1837  * ndmpd_mover_shut_down
1838  *
1839  * Shutdown the mover. It closes all the sockets.
1840  *
1841  * Parameters:
1842  *   session (input) - session pointer.
1843  *
1844  * Returns:
1845  *   void
1846  */
1847 void
1848 ndmpd_mover_shut_down(ndmpd_session_t *session)
1849 {
1850 	ndmp_lbr_params_t *nlp;
1851 
1852 	if ((nlp = ndmp_get_nlp(session)) == NULL)
1853 		return;
1854 
1855 	(void) mutex_lock(&nlp->nlp_mtx);
1856 	if (session->ns_mover.md_listen_sock != -1) {
1857 		NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
1858 		    session->ns_mover.md_listen_sock);
1859 		(void) ndmpd_remove_file_handler(session,
1860 		    session->ns_mover.md_listen_sock);
1861 		(void) close(session->ns_mover.md_listen_sock);
1862 		session->ns_mover.md_listen_sock = -1;
1863 	}
1864 	if (session->ns_mover.md_sock != -1) {
1865 		NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
1866 		    session->ns_mover.md_sock);
1867 		(void) ndmpd_remove_file_handler(session,
1868 		    session->ns_mover.md_sock);
1869 		(void) close(session->ns_mover.md_sock);
1870 		session->ns_mover.md_sock = -1;
1871 	}
1872 	(void) cond_broadcast(&nlp->nlp_cv);
1873 	(void) mutex_unlock(&nlp->nlp_mtx);
1874 }
1875 
1876 
1877 /*
1878  * ndmpd_mover_cleanup
1879  *
1880  * Parameters:
1881  *   session (input) - session pointer.
1882  *
1883  * Returns:
1884  *   void
1885  */
1886 void
1887 ndmpd_mover_cleanup(ndmpd_session_t *session)
1888 {
1889 	NDMP_FREE(session->ns_mover.md_buf);
1890 }
1891 
1892 
1893 /*
1894  * ndmpd_mover_connect
1895  *   Create a connection to the specified mover.
1896  *
1897  * Parameters:
1898  *   session (input) - session pointer
1899  *
1900  * Returns:
1901  *   error code.
1902  */
1903 ndmp_error
1904 ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
1905 {
1906 	ndmp_mover_addr *mover = &session->ns_data.dd_mover;
1907 	struct sockaddr_in sin;
1908 	int sock = -1;
1909 	int flag = 1;
1910 
1911 	if (mover->addr_type == NDMP_ADDR_TCP) {
1912 		if (mover->ndmp_mover_addr_u.addr.ip_addr) {
1913 			(void) memset((void *) &sin, 0, sizeof (sin));
1914 			sin.sin_family = AF_INET;
1915 			sin.sin_addr.s_addr =
1916 			    htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
1917 			sin.sin_port =
1918 			    htons(mover->ndmp_mover_addr_u.addr.port);
1919 
1920 			/*
1921 			 * If the address type is TCP but both the address and
1922 			 * the port number are zero, we have to use a different
1923 			 * socket than the mover socket. This can happen when
1924 			 * using NDMP disk to disk copy (AKA D2D copy).
1925 			 * The NDMPCopy client will send a zero address to
1926 			 * direct the server to use the mover socket as the
1927 			 * data socket to receive the recovery data.
1928 			 */
1929 			if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
1930 				session->ns_data.dd_sock =
1931 				    session->ns_mover.md_sock;
1932 				return (NDMP_NO_ERR);
1933 			}
1934 
1935 			NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
1936 			    mover->ndmp_mover_addr_u.addr.ip_addr,
1937 			    (ulong_t)sin.sin_port);
1938 
1939 			if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1940 				NDMP_LOG(LOG_DEBUG, "Socket error: %m");
1941 				return (NDMP_IO_ERR);
1942 			}
1943 			if (connect(sock, (struct sockaddr *)&sin,
1944 			    sizeof (sin)) < 0) {
1945 				NDMP_LOG(LOG_DEBUG, "Connect error: %m");
1946 				(void) close(sock);
1947 				return (NDMP_IO_ERR);
1948 			}
1949 
1950 			if (ndmp_sbs > 0)
1951 				ndmp_set_socket_snd_buf(sock,
1952 				    ndmp_sbs * KILOBYTE);
1953 			if (ndmp_rbs > 0)
1954 				ndmp_set_socket_rcv_buf(sock,
1955 				    ndmp_rbs * KILOBYTE);
1956 
1957 			ndmp_set_socket_nodelay(sock);
1958 			(void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag,
1959 			    sizeof (flag));
1960 		} else {
1961 			if ((session->ns_mover.md_state !=
1962 			    NDMP_MOVER_STATE_ACTIVE) ||
1963 			    (session->ns_mover.md_sock == -1)) {
1964 
1965 				NDMP_LOG(LOG_DEBUG,
1966 				    "Not in active  state mover"
1967 				    "  state = %d or Invalid mover sock=%d",
1968 				    session->ns_mover.md_state,
1969 				    session->ns_mover.md_sock);
1970 				return (NDMP_ILLEGAL_STATE_ERR);
1971 			}
1972 
1973 			sock = session->ns_mover.md_sock;
1974 			NDMP_LOG(LOG_DEBUG,
1975 			    "session: 0x%x setting data sock fd: %d to be"
1976 			    " same as listen_sock", session, sock);
1977 		}
1978 
1979 		NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
1980 
1981 		session->ns_data.dd_sock = sock;
1982 
1983 		NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
1984 
1985 		return (NDMP_NO_ERR);
1986 	}
1987 	/* Local mover connection. */
1988 
1989 	if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
1990 		NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
1991 		return (NDMP_ILLEGAL_STATE_ERR);
1992 	}
1993 	if (session->ns_tape.td_fd == -1) {
1994 		NDMP_LOG(LOG_DEBUG, "Tape device not open");
1995 		return (NDMP_DEV_NOT_OPEN_ERR);
1996 	}
1997 	if (mover_mode == NDMP_MOVER_MODE_READ &&
1998 	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1999 		NDMP_LOG(LOG_ERR, "Write protected device.");
2000 		return (NDMP_WRITE_PROTECT_ERR);
2001 	}
2002 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2003 	session->ns_mover.md_mode = mover_mode;
2004 
2005 	return (NDMP_NO_ERR);
2006 }
2007 
2008 
2009 
2010 /*
2011  * ndmpd_mover_seek
2012  *
2013  * Seek to the requested data stream position.
2014  * If the requested offset is outside of the current window,
2015  * the mover is paused and a notify_mover_paused request is sent
2016  * notifying the client that a seek is required.
2017  * If the requested offest is within the window but not within the
2018  * current record, then the tape is positioned to the record containing
2019  * the requested offest.
2020  * The requested amount of data is then read from the tape device and
2021  * written to the data connection.
2022  *
2023  * Parameters:
2024  *   session (input) - session pointer.
2025  *   offset  (input) - data stream position to seek to.
2026  *   length  (input) - amount of data that will be read.
2027  *
2028  * Returns:
2029  *   1 - seek pending completion by the NDMP client.
2030  *   0 - seek successfully completed.
2031  *  -1 - error.
2032  */
2033 int
2034 ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
2035     u_longlong_t length)
2036 {
2037 	int ctlcmd;
2038 	int ctlcnt;
2039 	u_longlong_t tape_position;
2040 	u_longlong_t buf_position;
2041 	ndmp_notify_mover_paused_request pause_request;
2042 
2043 	session->ns_mover.md_seek_position = offset;
2044 	session->ns_mover.md_bytes_left_to_read = length;
2045 
2046 	/*
2047 	 * If the requested position is outside of the window,
2048 	 * notify the client that a seek is required.
2049 	 */
2050 	if (session->ns_mover.md_seek_position <
2051 	    session->ns_mover.md_window_offset ||
2052 	    session->ns_mover.md_seek_position >=
2053 	    session->ns_mover.md_window_offset +
2054 	    session->ns_mover.md_window_length) {
2055 		NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
2056 		    session->ns_mover.md_seek_position);
2057 
2058 		session->ns_mover.md_w_index = 0;
2059 		session->ns_mover.md_r_index = 0;
2060 
2061 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2062 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2063 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2064 		pause_request.seek_position = long_long_to_quad(offset);
2065 
2066 		if (ndmp_send_request(session->ns_connection,
2067 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2068 		    (void *) &pause_request, 0) < 0) {
2069 			NDMP_LOG(LOG_DEBUG,
2070 			    "Sending notify_mover_paused request");
2071 			return (-1);
2072 		}
2073 		return (1);
2074 	}
2075 	/*
2076 	 * Determine the data stream position of the first byte in the
2077 	 * data buffer.
2078 	 */
2079 	buf_position = session->ns_mover.md_position -
2080 	    (session->ns_mover.md_position % session->ns_mover.md_record_size);
2081 
2082 	/*
2083 	 * Determine the data stream position of the next byte that
2084 	 * will be read from tape.
2085 	 */
2086 	tape_position = buf_position;
2087 	if (session->ns_mover.md_w_index != 0)
2088 		tape_position += session->ns_mover.md_record_size;
2089 
2090 	/*
2091 	 * Check if requested position is for data that has been read and is
2092 	 * in the buffer.
2093 	 */
2094 	if (offset >= buf_position && offset < tape_position) {
2095 		session->ns_mover.md_position = offset;
2096 		session->ns_mover.md_r_index = session->ns_mover.md_position -
2097 		    buf_position;
2098 
2099 		NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
2100 		    session->ns_mover.md_position,
2101 		    session->ns_mover.md_r_index);
2102 
2103 		return (0);
2104 	}
2105 
2106 	ctlcmd = 0;
2107 	if (tape_position > session->ns_mover.md_seek_position) {
2108 		/* Need to seek backward. */
2109 		ctlcmd = MTBSR;
2110 		ctlcnt = (int)((tape_position - offset - 1)
2111 		    / session->ns_mover.md_record_size) + 1;
2112 		tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
2113 		    session->ns_mover.md_record_size) + 1) *
2114 		    (u_longlong_t)session->ns_mover.md_record_size);
2115 
2116 	} else if (offset >= tape_position + session->ns_mover.md_record_size) {
2117 		/* Need to seek forward. */
2118 		ctlcmd = MTFSR;
2119 		ctlcnt = (int)((offset - tape_position)
2120 		    / session->ns_mover.md_record_size);
2121 		tape_position += ((u_longlong_t)(((offset - tape_position) /
2122 		    session->ns_mover.md_record_size)) *
2123 		    (u_longlong_t)session->ns_mover.md_record_size);
2124 	}
2125 	/* Reposition the tape if necessary. */
2126 	if (ctlcmd) {
2127 		NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
2128 		    ctlcmd, ctlcnt);
2129 		(void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
2130 	}
2131 
2132 	session->ns_mover.md_position = tape_position;
2133 	session->ns_mover.md_r_index = 0;
2134 	session->ns_mover.md_w_index = 0;
2135 
2136 	NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
2137 
2138 	return (0);
2139 }
2140 
2141 
2142 /* ** static functions ************************************************** */
2143 
2144 /*
2145  * create_listen_socket_v2
2146  *
2147  * Creates a socket for listening for accepting data connections.
2148  *
2149  * Parameters:
2150  *   session (input)  - session pointer.
2151  *   addr    (output) - location to store address of socket.
2152  *   port    (output) - location to store port of socket.
2153  *
2154  * Returns:
2155  *   0 - success.
2156  *  -1 - error.
2157  */
2158 static int
2159 create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
2160 {
2161 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
2162 	if (session->ns_mover.md_listen_sock < 0)
2163 		return (-1);
2164 
2165 	/*
2166 	 * Add a file handler for the listen socket.
2167 	 * ndmpd_select will call accept_connection when a
2168 	 * connection is ready to be accepted.
2169 	 */
2170 	if (ndmpd_add_file_handler(session, (void *) session,
2171 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
2172 	    accept_connection) < 0) {
2173 		(void) close(session->ns_mover.md_listen_sock);
2174 		session->ns_mover.md_listen_sock = -1;
2175 		return (-1);
2176 	}
2177 
2178 	NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
2179 	return (0);
2180 }
2181 
2182 
2183 /*
2184  * accept_connection
2185  *
2186  * Accept a data connection from a data server.
2187  * Called by ndmpd_select when a connection is pending on
2188  * the mover listen socket.
2189  *
2190  * Parameters:
2191  *   cookie  (input) - session pointer.
2192  *   fd      (input) - file descriptor.
2193  *   mode    (input) - select mode.
2194  *
2195  * Returns:
2196  *   void.
2197  */
2198 /*ARGSUSED*/
2199 static void
2200 accept_connection(void *cookie, int fd, ulong_t mode)
2201 {
2202 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
2203 	struct sockaddr_in from;
2204 	int from_len;
2205 	int flag = 1;
2206 
2207 	from_len = sizeof (from);
2208 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
2209 	    &from_len);
2210 
2211 	(void) ndmpd_remove_file_handler(session, fd);
2212 	(void) close(session->ns_mover.md_listen_sock);
2213 	session->ns_mover.md_listen_sock = -1;
2214 
2215 	if (session->ns_mover.md_sock < 0) {
2216 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
2217 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
2218 		return;
2219 	}
2220 
2221 	(void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE,
2222 	    &flag, sizeof (flag));
2223 	ndmp_set_socket_nodelay(session->ns_mover.md_sock);
2224 	ndmp_set_socket_rcv_buf(session->ns_mover.md_sock, 60 * KILOBYTE);
2225 	ndmp_set_socket_snd_buf(session->ns_mover.md_sock, 60 * KILOBYTE);
2226 
2227 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
2228 
2229 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
2230 		if (start_mover_for_backup(session) < 0) {
2231 			ndmpd_mover_error(session,
2232 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
2233 			return;
2234 		}
2235 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
2236 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2237 		    ntohs(from.sin_port));
2238 	} else {
2239 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
2240 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2241 		    ntohs(from.sin_port));
2242 	}
2243 
2244 	NDMP_LOG(LOG_DEBUG, "Received connection");
2245 
2246 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2247 }
2248 
2249 /*
2250  * tape_read
2251  *
2252  * Reads a data record from tape. Detects and handles EOT conditions.
2253  *
2254  * Parameters:
2255  *   session (input) - session pointer.
2256  *   data    (input) - location to read data to.
2257  *
2258  * Returns:
2259  *    0 - operation aborted.
2260  *   -1 - tape read error.
2261  *   otherwise - number of bytes read.
2262  */
2263 static int
2264 tape_read(ndmpd_session_t *session, char *data)
2265 {
2266 	ssize_t n;
2267 	int err;
2268 	int count = session->ns_mover.md_record_size;
2269 
2270 	for (; ; ) {
2271 		n = read(session->ns_tape.td_fd, data, count);
2272 		if (n < 0) {
2273 			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
2274 			return (TAPE_READ_ERR);
2275 		}
2276 		NS_ADD(rtape, n);
2277 
2278 		if (n == 0) {
2279 			if (!is_writer_running(session))
2280 				return (TAPE_NO_WRITER_ERR);
2281 
2282 			/*
2283 			 * End of media reached.
2284 			 * Notify client and wait for the client to
2285 			 * either abort the data operation or continue the
2286 			 * operation after changing the tape.
2287 			 */
2288 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2289 			    ++ndmp_log_msg_id,
2290 			    "End of tape reached. Load next tape");
2291 
2292 			NDMP_LOG(LOG_DEBUG,
2293 			    "End of tape reached. Load next tape");
2294 
2295 			err = change_tape(session);
2296 
2297 			/* Operation aborted or connection terminated? */
2298 			if (err < 0) {
2299 				/*
2300 				 * K.L. Go back one record if it is read
2301 				 * but not used.
2302 				 */
2303 
2304 				if (count != session->ns_mover.md_record_size) {
2305 					(void) ndmp_mtioctl(
2306 					    session->ns_tape.td_fd, MTBSR, 1);
2307 				}
2308 				return (0);
2309 			}
2310 			/* Retry the read from the new tape. */
2311 			continue;
2312 		}
2313 
2314 		/* Change to pass Veritas Netbackup prequal test. */
2315 		data += n;
2316 		count -= n;
2317 		if (count <= 0) {
2318 			session->ns_mover.md_record_num++;
2319 			session->ns_tape.td_record_count++;
2320 			return (n);
2321 		}
2322 	}
2323 }
2324 
2325 /*
2326  * change_tape
2327  *
2328  * Send a notify_pause request (protocol version 1) or
2329  * notify_mover_pause request (protocol version 2) to the
2330  * NDMP client to inform
2331  * the client that a tape volume change is required.
2332  * Process messages until the data/mover operation is either aborted
2333  * or continued.
2334  *
2335  * Parameters:
2336  *   client_data (input) - session pointer.
2337  *
2338  * Returns:
2339  *   0 - operation has been continued.
2340  *  -1 - operation has been aborted.
2341  */
2342 static int
2343 change_tape(ndmpd_session_t *session)
2344 {
2345 	ndmp_notify_mover_paused_request request;
2346 
2347 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2348 
2349 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
2350 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
2351 	else
2352 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
2353 
2354 	request.reason = session->ns_mover.md_pause_reason;
2355 	request.seek_position = long_long_to_quad(0LL);
2356 
2357 	NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
2358 	    session->ns_mover.md_pause_reason);
2359 
2360 	if (ndmp_send_request(session->ns_connection,
2361 	    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2362 	    (void *) &request, 0) < 0) {
2363 		NDMP_LOG(LOG_DEBUG,
2364 		    "Sending notify_mover_paused request");
2365 		return (-1);
2366 	}
2367 	/*
2368 	 * Wait for until the state is changed by
2369 	 * an abort or continue request.
2370 	 */
2371 	return (ndmp_wait_for_mover(session));
2372 }
2373 
2374 
2375 /*
2376  * discard_data
2377  *
2378  * Read and discard data from the data connection.
2379  * Called when a module has called ndmpd_seek() prior to
2380  * reading all of the data from the previous seek.
2381  *
2382  * Parameters:
2383  *   session (input) - session pointer.
2384  *
2385  * Returns:
2386  *   number of bytes read and discarded.
2387  *  -1 - error.
2388  */
2389 static int
2390 discard_data(ndmpd_session_t *session, ulong_t length)
2391 {
2392 	int n;
2393 	char *addr;
2394 
2395 	if ((addr = ndmp_malloc(length)) == NULL)
2396 		return (-1);
2397 
2398 	/* Read and discard the data. */
2399 	n = read(session->ns_mover.md_sock, addr, length);
2400 	if (n < 0) {
2401 		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
2402 		free(addr);
2403 		return (-1);
2404 	}
2405 
2406 	free(addr);
2407 	return (n);
2408 }
2409 
2410 
2411 /*
2412  * mover_tape_read_one_buf
2413  *
2414  * Read one buffer from the tape. This is used by mover_tape_reader
2415  *
2416  * Parameters:
2417  *   session (input) - session pointer.
2418  *   buf (input) - buffer read
2419  *
2420  * Returns:
2421  *   0: on success
2422  *  -1: otherwise
2423  */
2424 static int
2425 mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2426 {
2427 	int n;
2428 
2429 	tlm_buffer_mark_empty(buf);
2430 
2431 	/*
2432 	 * If the end of the mover window has been reached,
2433 	 * then notify the client that a seek is needed.
2434 	 * Remove the file handler to prevent this function from
2435 	 * being called. The handler will be reinstalled in
2436 	 * ndmpd_mover_continue.
2437 	 */
2438 
2439 	if (session->ns_mover.md_position >=
2440 	    session->ns_mover.md_window_offset +
2441 	    session->ns_mover.md_window_length) {
2442 		ndmp_notify_mover_paused_request pause_request;
2443 
2444 		NDMP_LOG(LOG_DEBUG, "end of mover window");
2445 
2446 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2447 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2448 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2449 		pause_request.seek_position =
2450 		    long_long_to_quad(session->ns_mover.md_position);
2451 
2452 		if (ndmp_send_request(session->ns_connection,
2453 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2454 		    (void *) &pause_request, 0) < 0) {
2455 			NDMP_LOG(LOG_DEBUG,
2456 			    "Sending notify_mover_paused request");
2457 			ndmpd_mover_error(session,
2458 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
2459 		}
2460 		buf->tb_errno = EIO;
2461 		return (TAPE_READ_ERR);
2462 	}
2463 
2464 	n = tape_read(session, buf->tb_buffer_data);
2465 
2466 	NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
2467 
2468 	if (n <= 0) {
2469 		if (n < 0)
2470 			ndmpd_mover_error(session,
2471 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
2472 			    NDMP_MOVER_HALT_INTERNAL_ERROR));
2473 		return (TAPE_READ_ERR);
2474 	}
2475 
2476 	buf->tb_full = TRUE;
2477 	buf->tb_buffer_size = session->ns_mover.md_record_size;
2478 
2479 	/*
2480 	 * Discard data if the current data stream position is
2481 	 * prior to the seek position. This is necessary if a seek
2482 	 * request set the seek pointer to a position that is not a
2483 	 * record boundary. The seek request handler can only position
2484 	 * to the start of a record.
2485 	 */
2486 	if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
2487 		session->ns_mover.md_position =
2488 		    session->ns_mover.md_seek_position;
2489 
2490 	return (0);
2491 }
2492 
2493 
2494 /*
2495  * mover_tape_reader
2496  *
2497  * Mover tape reader thread. It is launched when the mover is started
2498  * for restore.
2499  *
2500  * Parameters:
2501  *   session (input) - session pointer.
2502  *
2503  * Returns:
2504  *   0: on success
2505  *  -1: otherwise
2506  */
2507 int
2508 mover_tape_reader(ndmpd_session_t *session)
2509 {
2510 	int bidx;	/* buffer index */
2511 	int rv;
2512 	ndmp_lbr_params_t *nlp;
2513 	tlm_buffer_t *buf;
2514 	tlm_buffers_t *bufs;
2515 	tlm_cmd_t *lcmd;	/* Local command */
2516 	tlm_commands_t *cmds;	/* Commands structure */
2517 
2518 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2519 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2520 		return (-1);
2521 	}
2522 
2523 	cmds = &nlp->nlp_cmds;
2524 	lcmd = cmds->tcs_command;
2525 	bufs = lcmd->tc_buffers;
2526 
2527 	lcmd->tc_ref++;
2528 	cmds->tcs_reader_count++;
2529 
2530 	/*
2531 	 * Let our parent thread know that we are running.
2532 	 */
2533 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
2534 
2535 	buf = tlm_buffer_in_buf(bufs, &bidx);
2536 	while (cmds->tcs_reader == TLM_RESTORE_RUN &&
2537 	    lcmd->tc_reader == TLM_RESTORE_RUN) {
2538 		buf = tlm_buffer_in_buf(bufs, NULL);
2539 
2540 		if (buf->tb_full) {
2541 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2542 			/*
2543 			 * The buffer is still full, wait for the consumer
2544 			 * thread to use it.
2545 			 */
2546 			tlm_buffer_out_buf_timed_wait(bufs, 100);
2547 
2548 		} else {
2549 			NDMP_LOG(LOG_DEBUG, "r%d", bidx);
2550 
2551 			rv = mover_tape_read_one_buf(session, buf);
2552 			/*
2553 			 * If there was an error while reading, such as
2554 			 * end of stream.
2555 			 */
2556 			if (rv < 0) {
2557 				NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
2558 				break;
2559 			}
2560 
2561 			/*
2562 			 * Can we do more buffering?
2563 			 */
2564 			if (is_buffer_erroneous(buf)) {
2565 				NDMP_LOG(LOG_DEBUG,
2566 				    "Exiting, errno: %d, eot: %d, eof: %d",
2567 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
2568 				break;
2569 			}
2570 
2571 			(void) tlm_buffer_advance_in_idx(bufs);
2572 			tlm_buffer_release_in_buf(bufs);
2573 			bidx = bufs->tbs_buffer_in;
2574 		}
2575 	}
2576 
2577 	/* If the consumer is waiting for us, wake it up. */
2578 	tlm_buffer_release_in_buf(bufs);
2579 
2580 	/*
2581 	 * Clean up.
2582 	 */
2583 	cmds->tcs_reader_count--;
2584 	lcmd->tc_ref--;
2585 	lcmd->tc_writer = TLM_STOP;
2586 	return (0);
2587 }
2588 
2589 
2590 /*
2591  * mover_socket_write_one_buf
2592  *
2593  * Write one buffer to the network socket. This is used by mover_socket_writer
2594  *
2595  * Parameters:
2596  *   session (input) - session pointer.
2597  *   buf (input) - buffer read
2598  *
2599  * Returns:
2600  *   0: on success
2601  *  -1: otherwise
2602  */
2603 static int
2604 mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2605 {
2606 	int n;
2607 
2608 	/* Write the data to the data connection. */
2609 	errno = 0;
2610 	n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
2611 	    buf->tb_buffer_size);
2612 
2613 	NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
2614 
2615 	if (n < 0) {
2616 		NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2617 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
2618 		return (-1);
2619 	}
2620 
2621 	session->ns_mover.md_position += n;
2622 	session->ns_mover.md_bytes_left_to_read -= n;
2623 	tlm_buffer_mark_empty(buf);
2624 
2625 	/*
2626 	 * If the read limit has been reached,
2627 	 * then remove the file handler to prevent this
2628 	 * function from getting called. The next mover_read request
2629 	 * will reinstall the handler.
2630 	 */
2631 	if (session->ns_mover.md_bytes_left_to_read == 0) {
2632 		NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
2633 		(void) ndmpd_remove_file_handler(session,
2634 		    session->ns_mover.md_sock);
2635 		return (-1);
2636 	}
2637 
2638 	return (0);
2639 }
2640 
2641 
2642 
2643 /*
2644  * mover_socket_writer
2645  *
2646  * Mover's socket writer thread. This thread sends the read buffer
2647  * from the tape to the data server through the network socket.
2648  *
2649  * Parameters:
2650  *   session (input) - session pointer.
2651  *
2652  * Returns:
2653  *   0: on success
2654  *  -1: otherwise
2655  */
2656 int
2657 mover_socket_writer(ndmpd_session_t *session)
2658 {
2659 	int bidx;	/* buffer index */
2660 	ndmp_lbr_params_t *nlp;
2661 	tlm_buffer_t *buf;
2662 	tlm_buffers_t *bufs;
2663 	tlm_cmd_t *lcmd;	/* Local command */
2664 	tlm_commands_t *cmds;	/* Commands structure */
2665 
2666 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2667 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2668 		return (-1);
2669 	}
2670 
2671 	cmds = &nlp->nlp_cmds;
2672 	lcmd = cmds->tcs_command;
2673 	bufs = lcmd->tc_buffers;
2674 
2675 	lcmd->tc_ref++;
2676 	cmds->tcs_writer_count++;
2677 
2678 	/*
2679 	 * Let our parent thread know that we are running.
2680 	 */
2681 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
2682 
2683 	bidx = bufs->tbs_buffer_out;
2684 	while (cmds->tcs_writer != (int)TLM_ABORT &&
2685 	    lcmd->tc_writer != (int)TLM_ABORT) {
2686 		buf = &bufs->tbs_buffer[bidx];
2687 
2688 		if (buf->tb_full) {
2689 			NDMP_LOG(LOG_DEBUG, "w%d", bidx);
2690 
2691 			if (mover_socket_write_one_buf(session, buf) < 0) {
2692 				NDMP_LOG(LOG_DEBUG,
2693 				    "mover_socket_write_one_buf() < 0");
2694 				break;
2695 			}
2696 
2697 			(void) tlm_buffer_advance_out_idx(bufs);
2698 			tlm_buffer_release_out_buf(bufs);
2699 			bidx = bufs->tbs_buffer_out;
2700 		} else {
2701 			if (lcmd->tc_writer != TLM_RESTORE_RUN) {
2702 				/* No more data is coming, time to exit */
2703 				NDMP_LOG(LOG_DEBUG, "Time to exit");
2704 				break;
2705 			}
2706 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
2707 			/*
2708 			 * The buffer is not full, wait for the producer
2709 			 * thread to fill it.
2710 			 */
2711 			tlm_buffer_in_buf_timed_wait(bufs, 100);
2712 		}
2713 	}
2714 
2715 	if (cmds->tcs_writer == (int)TLM_ABORT)
2716 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
2717 	if (lcmd->tc_writer == (int)TLM_ABORT)
2718 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
2719 
2720 	/* If the producer is waiting for us, wake it up. */
2721 	tlm_buffer_release_out_buf(bufs);
2722 
2723 	/*
2724 	 * Clean up.
2725 	 */
2726 	cmds->tcs_writer_count--;
2727 	lcmd->tc_ref--;
2728 	lcmd->tc_reader = TLM_STOP;
2729 	return (0);
2730 }
2731 
2732 
2733 /*
2734  * start_mover_for_restore
2735  *
2736  * Creates the mover tape reader and network writer threads for
2737  * the mover to perform the 3-way restore.
2738  *
2739  * Parameters:
2740  *   session (input) - session pointer.
2741  *
2742  * Returns:
2743  *   0: on success
2744  *  -1: otherwise
2745  */
2746 static int
2747 start_mover_for_restore(ndmpd_session_t *session)
2748 {
2749 	ndmp_lbr_params_t *nlp;
2750 	tlm_commands_t *cmds;
2751 	long xfer_size;
2752 	int rc;
2753 
2754 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2755 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2756 		return (-1);
2757 	}
2758 
2759 	cmds = &nlp->nlp_cmds;
2760 	(void) memset(cmds, 0, sizeof (*cmds));
2761 	cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
2762 	xfer_size = ndmp_buffer_get_size(session);
2763 	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2764 	if (cmds->tcs_command == NULL)
2765 		return (-1);
2766 
2767 	cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
2768 	cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
2769 
2770 	/*
2771 	 * We intentionnally don't wait for the threads to start since the
2772 	 * reply of the request (which resulted in calling this function)
2773 	 * must be sent to the client before probable errors are sent
2774 	 * to the client.
2775 	 */
2776 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session);
2777 	if (rc == 0) {
2778 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
2779 	} else {
2780 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
2781 		    strerror(rc));
2782 		return (-1);
2783 	}
2784 
2785 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session);
2786 	if (rc == 0) {
2787 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
2788 	} else {
2789 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
2790 		    strerror(rc));
2791 		return (-1);
2792 	}
2793 
2794 	tlm_release_reader_writer_ipc(cmds->tcs_command);
2795 	return (0);
2796 }
2797 
2798 
2799 /*
2800  * mover_socket_read_one_buf
2801  *
2802  * Read one buffer from the network socket for the mover. This is used
2803  * by mover_socket_reader
2804  *
2805  * Parameters:
2806  *   session (input) - session pointer.
2807  *   buf (input) - buffer read
2808  *   read_size (input) - size to be read
2809  *
2810  * Returns:
2811  *   0: on success
2812  *  -1: otherwise
2813  */
2814 static int
2815 mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
2816     long read_size)
2817 {
2818 	int n, index;
2819 	long toread;
2820 
2821 	tlm_buffer_mark_empty(buf);
2822 	for (index = 0, toread = read_size; toread > 0; ) {
2823 		errno = 0;
2824 		NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
2825 
2826 		n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
2827 		    toread);
2828 		if (n == 0) {
2829 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
2830 			break;
2831 		} else if (n > 0) {
2832 			NDMP_LOG(LOG_DEBUG, "n: %d", n);
2833 			index += n;
2834 			toread -= n;
2835 		} else {
2836 			buf->tb_eof = TRUE;
2837 			buf->tb_errno = errno;
2838 			buf->tb_buffer_size = 0;
2839 			NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2840 			return (-1);
2841 		}
2842 	}
2843 
2844 	if (index > 0) {
2845 		buf->tb_full = TRUE;
2846 		buf->tb_buffer_size = read_size;
2847 		if (read_size > 0)
2848 			(void) memset(&buf->tb_buffer_data[index], 0,
2849 			    read_size - index);
2850 	} else {
2851 		buf->tb_eof = TRUE;
2852 		buf->tb_buffer_size = 0;
2853 	}
2854 
2855 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2856 	    " errno: %d, size: %d, data: 0x%x",
2857 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2858 	    buf->tb_buffer_size, buf->tb_buffer_data);
2859 
2860 	return (0);
2861 }
2862 
2863 
2864 
2865 /*
2866  * mover_socket_reader
2867  *
2868  * Mover socket reader thread. This is used when reading data from the
2869  * network socket for performing remote backups.
2870  *
2871  * Parameters:
2872  *   session (input) - session pointer.
2873  *
2874  * Returns:
2875  *   0: on success
2876  *  -1: otherwise
2877  */
2878 int
2879 mover_socket_reader(ndmpd_session_t *session)
2880 {
2881 	int bidx;	/* buffer index */
2882 	ndmp_lbr_params_t *nlp;
2883 	tlm_buffer_t *buf;
2884 	tlm_buffers_t *bufs;
2885 	tlm_cmd_t *lcmd;	/* Local command */
2886 	tlm_commands_t *cmds;	/* Commands structure */
2887 	static int nr = 0;
2888 
2889 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2890 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2891 		return (-1);
2892 	}
2893 
2894 	cmds = &nlp->nlp_cmds;
2895 	lcmd = cmds->tcs_command;
2896 	bufs = lcmd->tc_buffers;
2897 
2898 	lcmd->tc_ref++;
2899 	cmds->tcs_reader_count++;
2900 
2901 	/*
2902 	 * Let our parent thread know that we are running.
2903 	 */
2904 	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
2905 
2906 	bidx = bufs->tbs_buffer_in;
2907 	while (cmds->tcs_reader == TLM_BACKUP_RUN &&
2908 	    lcmd->tc_reader == TLM_BACKUP_RUN) {
2909 		buf = &bufs->tbs_buffer[bidx];
2910 
2911 		if (buf->tb_full) {
2912 			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2913 			/*
2914 			 * The buffer is still full, wait for the consumer
2915 			 * thread to use it.
2916 			 */
2917 			tlm_buffer_out_buf_timed_wait(bufs, 100);
2918 		} else {
2919 			NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
2920 
2921 			(void) mover_socket_read_one_buf(session, buf,
2922 			    bufs->tbs_data_transfer_size);
2923 
2924 			/*
2925 			 * Can we do more buffering?
2926 			 */
2927 			if (is_buffer_erroneous(buf)) {
2928 				NDMP_LOG(LOG_DEBUG,
2929 				    "Exiting, errno: %d, eot: %d, eof: %d",
2930 				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
2931 				break;
2932 			}
2933 
2934 			(void) tlm_buffer_advance_in_idx(bufs);
2935 			tlm_buffer_release_in_buf(bufs);
2936 			bidx = bufs->tbs_buffer_in;
2937 		}
2938 	}
2939 
2940 	if (cmds->tcs_reader != TLM_BACKUP_RUN)
2941 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
2942 	if (lcmd->tc_reader != TLM_BACKUP_RUN)
2943 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
2944 	NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
2945 
2946 	/* If the consumer is waiting for us, wake it up. */
2947 	tlm_buffer_release_in_buf(bufs);
2948 
2949 	/*
2950 	 * Clean up.
2951 	 */
2952 	cmds->tcs_reader_count--;
2953 	lcmd->tc_ref--;
2954 	lcmd->tc_writer = TLM_STOP;
2955 	return (0);
2956 }
2957 
2958 
2959 /*
2960  * mover_tape_writer_one_buf
2961  *
2962  * Write one buffer for the mover to the local tape device. This is
2963  * used by mover_tape_writer thread.
2964  *
2965  * Parameters:
2966  *   session (input) - session pointer.
2967  *   buf (input) - buffer read
2968  *
2969  * Returns:
2970  *   0: on success
2971  *  -1: otherwise
2972  */
2973 static int
2974 mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2975 {
2976 	int n;
2977 
2978 	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2979 	    " errno: %d, size: %d, data: 0x%x",
2980 	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2981 	    buf->tb_buffer_size, buf->tb_buffer_data);
2982 
2983 	n = mover_tape_write_v3(session, buf->tb_buffer_data,
2984 	    buf->tb_buffer_size);
2985 
2986 	NDMP_LOG(LOG_DEBUG, "n: %d", n);
2987 
2988 	if (n <= 0) {
2989 		ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
2990 		    : NDMP_MOVER_HALT_INTERNAL_ERROR));
2991 		return (-1);
2992 	}
2993 	session->ns_mover.md_position += n;
2994 	session->ns_mover.md_data_written += n;
2995 	session->ns_mover.md_record_num++;
2996 
2997 	NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
2998 	tlm_buffer_mark_empty(buf);
2999 
3000 	return (0);
3001 }
3002 
3003 
3004 /*
3005  * mover_tape_writer
3006  *
3007  * Mover tape writer thread. This is used for performing remote backups
3008  * in a 3-way configuration. It writes the data from network socket to
3009  * the locally attached tape device.
3010  *
3011  * Parameters:
3012  *   session (input) - session pointer.
3013  *
3014  * Returns:
3015  *   0: on success
3016  *  -1: otherwise
3017  */
3018 int
3019 mover_tape_writer(ndmpd_session_t *session)
3020 {
3021 	int bidx;
3022 	ndmp_lbr_params_t *nlp;
3023 	tlm_buffer_t *buf;
3024 	tlm_buffers_t *bufs;
3025 	tlm_cmd_t *lcmd;
3026 	tlm_commands_t *cmds;
3027 	static int nw = 0;
3028 
3029 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3030 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3031 		return (-1);
3032 	}
3033 
3034 	cmds = &nlp->nlp_cmds;
3035 	lcmd = cmds->tcs_command;
3036 	bufs = lcmd->tc_buffers;
3037 
3038 	lcmd->tc_ref++;
3039 	cmds->tcs_writer_count++;
3040 
3041 	/*
3042 	 * Let our parent thread know that we are running.
3043 	 */
3044 	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
3045 
3046 	bidx = bufs->tbs_buffer_out;
3047 	buf = &bufs->tbs_buffer[bidx];
3048 	while (cmds->tcs_writer != (int)TLM_ABORT &&
3049 	    lcmd->tc_writer != (int)TLM_ABORT) {
3050 		if (buf->tb_full) {
3051 			NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
3052 
3053 			if (mover_tape_write_one_buf(session, buf) < 0) {
3054 				NDMP_LOG(LOG_DEBUG,
3055 				    "mover_tape_write_one_buf() failed");
3056 				break;
3057 			}
3058 
3059 			(void) tlm_buffer_advance_out_idx(bufs);
3060 			tlm_buffer_release_out_buf(bufs);
3061 			bidx = bufs->tbs_buffer_out;
3062 			buf = &bufs->tbs_buffer[bidx];
3063 		} else {
3064 			if (lcmd->tc_writer != TLM_BACKUP_RUN) {
3065 				/* No more data is coming, time to exit */
3066 				NDMP_LOG(LOG_DEBUG, "Time to exit");
3067 				break;
3068 			}
3069 			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
3070 			/*
3071 			 * The buffer is not full, wait for the producer
3072 			 * thread to fill it.
3073 			 */
3074 			tlm_buffer_in_buf_timed_wait(bufs, 100);
3075 		}
3076 	}
3077 
3078 	if (cmds->tcs_writer == (int)TLM_ABORT)
3079 		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
3080 	if (lcmd->tc_writer == (int)TLM_ABORT)
3081 		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
3082 	NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
3083 
3084 	if (buf->tb_errno == 0) {
3085 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3086 	} else {
3087 		NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
3088 		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
3089 	}
3090 
3091 	/* If the producer is waiting for us, wake it up. */
3092 	tlm_buffer_release_out_buf(bufs);
3093 
3094 	/*
3095 	 * Clean up.
3096 	 */
3097 	cmds->tcs_writer_count--;
3098 	lcmd->tc_ref--;
3099 	lcmd->tc_reader = TLM_STOP;
3100 	return (0);
3101 }
3102 
3103 
3104 /*
3105  * start_mover_for_backup
3106  *
3107  * Starts a remote backup by running socket reader and tape
3108  * writer threads. The mover runs a remote backup in a 3-way backup
3109  * configuration.
3110  *
3111  * Parameters:
3112  *   session (input) - session pointer.
3113  *
3114  * Returns:
3115  *   0: on success
3116  *  -1: otherwise
3117  */
3118 static int
3119 start_mover_for_backup(ndmpd_session_t *session)
3120 {
3121 	ndmp_lbr_params_t *nlp;
3122 	tlm_commands_t *cmds;
3123 	int rc;
3124 
3125 	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3126 		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3127 		return (-1);
3128 	}
3129 
3130 	cmds = &nlp->nlp_cmds;
3131 	(void) memset(cmds, 0, sizeof (*cmds));
3132 	cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
3133 	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
3134 	    session->ns_mover.md_record_size);
3135 	if (cmds->tcs_command == NULL)
3136 		return (-1);
3137 
3138 	cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
3139 	cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
3140 
3141 	/*
3142 	 * We intentionally don't wait for the threads to start since the
3143 	 * reply of the request (which resulted in calling this function)
3144 	 * must be sent to the client before probable errors are sent
3145 	 * to the client.
3146 	 */
3147 	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session);
3148 	if (rc == 0) {
3149 		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
3150 	} else {
3151 		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
3152 		    strerror(rc));
3153 		return (-1);
3154 	}
3155 
3156 	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session);
3157 	if (rc == 0) {
3158 		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
3159 	} else {
3160 		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
3161 		    strerror(rc));
3162 		return (-1);
3163 	}
3164 
3165 	tlm_release_reader_writer_ipc(cmds->tcs_command);
3166 	return (0);
3167 }
3168 
3169 
3170 /*
3171  * is_writer_running
3172  *
3173  * Find out if the writer thread has started or not.
3174  *
3175  * Parameters:
3176  *   session (input) - session pointer.
3177  *
3178  * Returns:
3179  *   0: not started
3180  *   non-zero: started
3181  *	Note: non-zero is also returned if the backup type is
3182  *		neither TAR nor DUMP.  I.e. the is_writer_running()
3183  *		check does not apply in this case and things should
3184  * 		appear successful.
3185  */
3186 static boolean_t
3187 is_writer_running(ndmpd_session_t *session)
3188 {
3189 	boolean_t rv;
3190 	ndmp_lbr_params_t *nlp;
3191 
3192 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3193 		return (1);
3194 
3195 	if (session == NULL)
3196 		rv = 0;
3197 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
3198 		rv = 0;
3199 	else
3200 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3201 
3202 	return (rv);
3203 }
3204 
3205 
3206 /*
3207  * is_writer_running_v3
3208  *
3209  * Find out if the writer thread has started or not.
3210  *
3211  * Parameters:
3212  *   session (input) - session pointer.
3213  *
3214  * Returns:
3215  *   0: not started
3216  *   non-zero: started
3217  *	Note: non-zero is also returned if the backup type is
3218  *		neither TAR nor DUMP.  I.e. the is_writer_running()
3219  *		check does not apply in this case and things should
3220  * 		appear successful.
3221  */
3222 static boolean_t
3223 is_writer_running_v3(ndmpd_session_t *session)
3224 {
3225 	boolean_t rv;
3226 	ndmp_lbr_params_t *nlp;
3227 
3228 	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3229 		return (1);
3230 
3231 	if (session == NULL)
3232 		rv = 0;
3233 	else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
3234 		rv = 1;
3235 	else if ((nlp = ndmp_get_nlp(session)) == NULL)
3236 		rv = 0;
3237 	else
3238 		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3239 
3240 	return (rv);
3241 }
3242 
3243 
3244 /*
3245  * ndmpd_mover_error_send
3246  *
3247  * This function sends the notify message to the client.
3248  *
3249  * Parameters:
3250  *   session (input) - session pointer.
3251  *   reason  (input) - halt reason.
3252  *
3253  * Returns:
3254  *   Error code
3255  */
3256 int
3257 ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3258 {
3259 	ndmp_notify_mover_halted_request req;
3260 
3261 	req.reason = reason;
3262 	req.text_reason = "";
3263 
3264 	return (ndmp_send_request(session->ns_connection,
3265 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3266 }
3267 
3268 
3269 /*
3270  * ndmpd_mover_error_send_v4
3271  *
3272  * This function sends the notify message to the client.
3273  *
3274  * Parameters:
3275  *   session (input) - session pointer.
3276  *   reason  (input) - halt reason.
3277  *
3278  * Returns:
3279  *   Error code
3280  */
3281 int
3282 ndmpd_mover_error_send_v4(ndmpd_session_t *session,
3283     ndmp_mover_halt_reason reason)
3284 {
3285 	ndmp_notify_mover_halted_request_v4 req;
3286 
3287 	req.reason = reason;
3288 
3289 	return (ndmp_send_request(session->ns_connection,
3290 	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3291 }
3292 
3293 
3294 /*
3295  * ndmpd_mover_error
3296  *
3297  * This function is called when an unrecoverable mover error
3298  * has been detected. A notify message is sent to the client and the
3299  * mover is placed into the halted state.
3300  *
3301  * Parameters:
3302  *   session (input) - session pointer.
3303  *   reason  (input) - halt reason.
3304  *
3305  * Returns:
3306  *   void.
3307  */
3308 void
3309 ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3310 {
3311 	ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
3312 
3313 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
3314 	    (session->ns_protocol_version > NDMPV2 &&
3315 	    session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
3316 		return;
3317 
3318 	if (session->ns_protocol_version == NDMPV4) {
3319 		if (ndmpd_mover_error_send_v4(session, reason) < 0)
3320 			NDMP_LOG(LOG_DEBUG,
3321 			    "Error sending notify_mover_halted request");
3322 	} else {
3323 		/* No media error in V3 */
3324 		if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
3325 			reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
3326 		if (ndmpd_mover_error_send(session, reason) < 0)
3327 			NDMP_LOG(LOG_DEBUG,
3328 			    "Error sending notify_mover_halted request");
3329 	}
3330 
3331 	(void) mutex_lock(&nlp->nlp_mtx);
3332 	if (session->ns_mover.md_listen_sock != -1) {
3333 		(void) ndmpd_remove_file_handler(session,
3334 		    session->ns_mover.md_listen_sock);
3335 		(void) close(session->ns_mover.md_listen_sock);
3336 		session->ns_mover.md_listen_sock = -1;
3337 	}
3338 	if (session->ns_mover.md_sock != -1) {
3339 		(void) ndmpd_remove_file_handler(session,
3340 		    session->ns_mover.md_sock);
3341 		(void) close(session->ns_mover.md_sock);
3342 		session->ns_mover.md_sock = -1;
3343 	}
3344 
3345 	session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
3346 	session->ns_mover.md_halt_reason = reason;
3347 	(void) cond_broadcast(&nlp->nlp_cv);
3348 	(void) mutex_unlock(&nlp->nlp_mtx);
3349 }
3350 
3351 
3352 /*
3353  * mover_pause_v3
3354  *
3355  * Send an ndmp_notify_mover_paused request to the
3356  * NDMP client to inform the client that its attention is required.
3357  * Process messages until the data/mover operation is either aborted
3358  * or continued.
3359  *
3360  * Parameters:
3361  *   client_data (input) - session pointer.
3362  *   reason (input) - pause reason.
3363  *
3364  * Returns:
3365  *   0 - operation has been continued.
3366  *  -1 - operation has been aborted.
3367  */
3368 static int
3369 mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
3370 {
3371 	int rv;
3372 	ndmp_notify_mover_paused_request request;
3373 
3374 	rv = 0;
3375 	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3376 	session->ns_mover.md_pause_reason = reason;
3377 	session->ns_mover.md_pre_cond = FALSE;
3378 
3379 	request.reason = session->ns_mover.md_pause_reason;
3380 	request.seek_position =
3381 	    long_long_to_quad(session->ns_mover.md_position);
3382 
3383 	if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
3384 	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
3385 		NDMP_LOG(LOG_DEBUG,
3386 		    "Error sending notify_mover_paused_request");
3387 		return (-1);
3388 	}
3389 
3390 	/*
3391 	 * 3-way operations are single-thread.  The same thread
3392 	 * should process the messages.
3393 	 *
3394 	 * 2-way operations are multi-thread.  The main thread
3395 	 * processes the messages.  We just need to wait and
3396 	 * see if the mover state changes or the operation aborts.
3397 	 */
3398 	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
3399 		/*
3400 		 * Process messages until the state is changed by
3401 		 * an abort, continue, or close request .
3402 		 */
3403 		for (; ; ) {
3404 			if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
3405 				return (-1);
3406 
3407 			if (session->ns_eof == TRUE)
3408 				return (-1);
3409 
3410 			switch (session->ns_mover.md_state) {
3411 			case NDMP_MOVER_STATE_ACTIVE:
3412 				session->ns_tape.td_record_count = 0;
3413 				return (0);
3414 
3415 			case NDMP_MOVER_STATE_PAUSED:
3416 				continue;
3417 
3418 			default:
3419 				return (-1);
3420 			}
3421 		}
3422 
3423 	} else {
3424 		if (session->ns_mover.md_data_addr.addr_type ==
3425 		    NDMP_ADDR_LOCAL) {
3426 			rv = ndmp_wait_for_mover(session);
3427 		} else {
3428 			NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
3429 			    session->ns_mover.md_data_addr.addr_type);
3430 			rv = -1;
3431 		}
3432 	}
3433 
3434 	return (rv);
3435 }
3436 
3437 
3438 /*
3439  * mover_tape_write_v3
3440  *
3441  * Writes a data record to tape. Detects and handles EOT conditions.
3442  *
3443  * Parameters:
3444  *   session (input) - session pointer.
3445  *   data    (input) - data to be written.
3446  *   length  (input) - length of data to be written.
3447  *
3448  * Returns:
3449  *    0 - operation aborted by client.
3450  *   -1 - error.
3451  *   otherwise - number of bytes written.
3452  */
3453 static int
3454 mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
3455 {
3456 	ssize_t n;
3457 	ssize_t count = length;
3458 
3459 	while (count > 0) {
3460 		/*
3461 		 * Enforce mover window on write.
3462 		 */
3463 		if (session->ns_mover.md_position >=
3464 		    session->ns_mover.md_window_offset +
3465 		    session->ns_mover.md_window_length) {
3466 			NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
3467 
3468 			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW) < 0)
3469 				/* Operation aborted or connection terminated */
3470 				return (-1);
3471 
3472 		}
3473 
3474 		n = write(session->ns_tape.td_fd, data, count);
3475 		if (n < 0) {
3476 			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3477 			return (-1);
3478 		} else if (n > 0) {
3479 			NS_ADD(wtape, n);
3480 			count -= n;
3481 			data += n;
3482 			session->ns_tape.td_record_count++;
3483 		}
3484 
3485 		/* EOM handling */
3486 		if (count > 0) {
3487 			struct mtget mtstatus;
3488 
3489 			(void) ioctl(session->ns_tape.td_fd, MTIOCGET,
3490 			    &mtstatus);
3491 			NDMP_LOG(LOG_DEBUG, "EOM detected (%d written bytes, "
3492 			    "mover record %d, file #%d, block #%d)", n,
3493 			    session->ns_tape.td_record_count,
3494 			    mtstatus.mt_fileno, mtstatus.mt_blkno);
3495 
3496 			/*
3497 			 * Notify the client to either abort the operation
3498 			 * or change the tape.
3499 			 */
3500 			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3501 			    ++ndmp_log_msg_id,
3502 			    "End of tape reached. Load next tape");
3503 
3504 			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM) < 0)
3505 				/* Operation aborted or connection terminated */
3506 				return (-1);
3507 		}
3508 	}
3509 
3510 	return (length);
3511 }
3512 
3513 
3514 /*
3515  * mover_tape_flush_v3
3516  *
3517  * Writes all remaining buffered data to tape. A partial record is
3518  * padded out to a full record with zeros.
3519  *
3520  * Parameters:
3521  *   session (input) - session pointer.
3522  *   data    (input) - data to be written.
3523  *   length  (input) - length of data to be written.
3524  *
3525  * Returns:
3526  *   -1 - error.
3527  *   otherwise - number of bytes written.
3528  */
3529 static int
3530 mover_tape_flush_v3(ndmpd_session_t *session)
3531 {
3532 	int n;
3533 
3534 	if (session->ns_mover.md_w_index == 0)
3535 		return (0);
3536 
3537 	(void) memset((void*)&session->ns_mover.md_buf[session->
3538 	    ns_mover.md_w_index], 0,
3539 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3540 
3541 	n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3542 	    session->ns_mover.md_record_size);
3543 	if (n < 0) {
3544 		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3545 		return (-1);
3546 	}
3547 
3548 	session->ns_mover.md_w_index = 0;
3549 	session->ns_mover.md_position += n;
3550 	return (n);
3551 }
3552 
3553 
3554 /*
3555  * ndmpd_local_write_v3
3556  *
3557  * Buffers and writes data to the tape device.
3558  * A full tape record is buffered before being written.
3559  *
3560  * Parameters:
3561  *   session    (input) - session pointer.
3562  *   data       (input) - data to be written.
3563  *   length     (input) - data length.
3564  *
3565  * Returns:
3566  *   0 - data successfully written.
3567  *  -1 - error.
3568  */
3569 int
3570 ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
3571 {
3572 	ulong_t count = 0;
3573 	ssize_t n;
3574 	ulong_t len;
3575 
3576 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
3577 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
3578 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
3579 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
3580 		return (-1);
3581 	}
3582 
3583 	/*
3584 	 * A length of 0 indicates that any buffered data should be
3585 	 * flushed to tape.
3586 	 */
3587 	if (length == 0) {
3588 		if (session->ns_mover.md_w_index == 0)
3589 			return (0);
3590 
3591 		(void) memset((void*)&session->ns_mover.md_buf[session->
3592 		    ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
3593 		    session->ns_mover.md_w_index);
3594 
3595 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3596 		    session->ns_mover.md_record_size);
3597 		if (n <= 0) {
3598 			ndmpd_mover_error(session,
3599 			    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3600 			    NDMP_MOVER_HALT_MEDIA_ERROR));
3601 			return (-1);
3602 		}
3603 
3604 		session->ns_mover.md_position += n;
3605 		session->ns_mover.md_data_written +=
3606 		    session->ns_mover.md_w_index;
3607 		session->ns_mover.md_record_num++;
3608 		session->ns_mover.md_w_index = 0;
3609 		return (0);
3610 	}
3611 
3612 	/* Break the data into records. */
3613 	while (count < length) {
3614 		/*
3615 		 * Determine if data needs to be buffered or
3616 		 * can be written directly from user supplied location.
3617 		 * We can fast path the write if there is no pending
3618 		 * buffered data and there is at least a full records worth
3619 		 * of data to be written.
3620 		 */
3621 		if (session->ns_mover.md_w_index == 0 &&
3622 		    length - count >= session->ns_mover.md_record_size) {
3623 			n = mover_tape_write_v3(session, &data[count],
3624 			    session->ns_mover.md_record_size);
3625 			if (n <= 0) {
3626 				ndmpd_mover_error(session,
3627 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3628 				    NDMP_MOVER_HALT_MEDIA_ERROR));
3629 				return (-1);
3630 			}
3631 
3632 			session->ns_mover.md_position += n;
3633 			session->ns_mover.md_data_written += n;
3634 			session->ns_mover.md_record_num++;
3635 			count += n;
3636 			continue;
3637 		}
3638 
3639 		/* Buffer the data */
3640 		len = length - count;
3641 		if (len > session->ns_mover.md_record_size -
3642 		    session->ns_mover.md_w_index)
3643 			len = session->ns_mover.md_record_size -
3644 			    session->ns_mover.md_w_index;
3645 
3646 		(void) memcpy(&session->ns_mover.md_buf[session->
3647 		    ns_mover.md_w_index], &data[count], len);
3648 		session->ns_mover.md_w_index += len;
3649 		count += len;
3650 
3651 		/* Write the buffer if its full */
3652 		if (session->ns_mover.md_w_index ==
3653 		    session->ns_mover.md_record_size) {
3654 			n = mover_tape_write_v3(session,
3655 			    session->ns_mover.md_buf,
3656 			    session->ns_mover.md_record_size);
3657 			if (n <= 0) {
3658 				ndmpd_mover_error(session,
3659 				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3660 				    NDMP_MOVER_HALT_MEDIA_ERROR));
3661 				return (-1);
3662 			}
3663 
3664 			session->ns_mover.md_position += n;
3665 			session->ns_mover.md_data_written += n;
3666 			session->ns_mover.md_record_num++;
3667 			session->ns_mover.md_w_index = 0;
3668 		}
3669 	}
3670 
3671 	return (0);
3672 }
3673 
3674 
3675 /*
3676  * mover_data_read_v3
3677  *
3678  * Reads backup data from the data connection and writes the
3679  * received data to the tape device.
3680  *
3681  * Parameters:
3682  *   cookie  (input) - session pointer.
3683  *   fd      (input) - file descriptor.
3684  *   mode    (input) - select mode.
3685  *
3686  * Returns:
3687  *   void.
3688  */
3689 /*ARGSUSED*/
3690 static void
3691 mover_data_read_v3(void *cookie, int fd, ulong_t mode)
3692 {
3693 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3694 	int n;
3695 	ulong_t index;
3696 
3697 	n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
3698 	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3699 
3700 	/*
3701 	 * Since this function is only called when select believes data
3702 	 * is available to be read, a return of zero indicates the
3703 	 * connection has been closed.
3704 	 */
3705 	if (n <= 0) {
3706 		if (n < 0 && errno == EWOULDBLOCK) {
3707 			NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
3708 			return;
3709 		}
3710 		NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
3711 
3712 		/* Save the index since mover_tape_flush_v3 resets it. */
3713 		index = session->ns_mover.md_w_index;
3714 
3715 		/* Flush any buffered data to tape. */
3716 		if (mover_tape_flush_v3(session) > 0) {
3717 			session->ns_mover.md_data_written += index;
3718 			session->ns_mover.md_record_num++;
3719 		}
3720 
3721 		if (n == 0)
3722 			ndmpd_mover_error(session,
3723 			    NDMP_MOVER_HALT_CONNECT_CLOSED);
3724 		else
3725 			ndmpd_mover_error(session,
3726 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
3727 
3728 		return;
3729 	}
3730 
3731 	NDMP_LOG(LOG_DEBUG, "n %d", n);
3732 
3733 	session->ns_mover.md_w_index += n;
3734 
3735 	if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
3736 		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3737 		    session->ns_mover.md_record_size);
3738 		if (n <= 0) {
3739 			ndmpd_mover_error(session,
3740 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3741 			    NDMP_MOVER_HALT_MEDIA_ERROR));
3742 			return;
3743 		}
3744 
3745 		session->ns_mover.md_position += n;
3746 		session->ns_mover.md_w_index = 0;
3747 		session->ns_mover.md_data_written += n;
3748 		session->ns_mover.md_record_num++;
3749 	}
3750 }
3751 
3752 /*
3753  * mover_tape_read_v3
3754  *
3755  * Reads a data record from tape. Detects and handles EOT conditions.
3756  *
3757  * Parameters:
3758  *   session (input) - session pointer.
3759  *   data    (input) - location to read data to.
3760  *
3761  * Returns:
3762  *   0 - operation aborted.
3763  *   TAPE_READ_ERR - tape read IO error.
3764  *   TAPE_NO_WRITER_ERR - no writer is running during tape read
3765  *   otherwise - number of bytes read.
3766  */
3767 static int
3768 mover_tape_read_v3(ndmpd_session_t *session, char *data)
3769 {
3770 	int pause_reason;
3771 	ssize_t	 n;
3772 	int err;
3773 	int count;
3774 
3775 	count = session->ns_mover.md_record_size;
3776 	while (count > 0) {
3777 		pause_reason = NDMP_MOVER_PAUSE_NA;
3778 
3779 		n = read(session->ns_tape.td_fd, data, count);
3780 		if (n < 0) {
3781 			/*
3782 			 * If at beginning of file and read fails with EIO,
3783 			 * then it's repeated attempt to read at EOT.
3784 			 */
3785 			if (errno == EIO && tape_is_at_bof(session)) {
3786 				NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
3787 				pause_reason = NDMP_MOVER_PAUSE_EOM;
3788 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3789 				    ++ndmp_log_msg_id,
3790 				    "End of tape reached. Load next tape");
3791 			}
3792 			/*
3793 			 * According to NDMPv4 spec preferred error code when
3794 			 * trying to read from blank tape is NDMP_EOM_ERR.
3795 			 */
3796 			else if (errno == EIO && tape_is_at_bot(session)) {
3797 				NDMP_LOG(LOG_ERR,
3798 				    "Blank tape detected, returning EOM");
3799 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3800 				    ++ndmp_log_msg_id,
3801 				    "Blank tape. Load another tape");
3802 				pause_reason = NDMP_MOVER_PAUSE_EOM;
3803 			} else {
3804 				NDMP_LOG(LOG_ERR, "Tape read error: %m.");
3805 				return (TAPE_READ_ERR);
3806 			}
3807 		} else if (n > 0) {
3808 			NS_ADD(rtape, n);
3809 			data += n;
3810 			count -= n;
3811 			session->ns_tape.td_record_count++;
3812 		} else {
3813 			if (!is_writer_running_v3(session))
3814 				return (TAPE_NO_WRITER_ERR);
3815 
3816 			/*
3817 			 * End of file or media reached. Notify client and
3818 			 * wait for the client to either abort the data
3819 			 * operation or continue the operation after changing
3820 			 * the tape.
3821 			 */
3822 			if (tape_is_at_bof(session)) {
3823 				NDMP_LOG(LOG_DEBUG, "EOT detected");
3824 				pause_reason = NDMP_MOVER_PAUSE_EOM;
3825 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3826 				    ++ndmp_log_msg_id, "End of medium reached");
3827 			} else {
3828 				NDMP_LOG(LOG_DEBUG, "EOF detected");
3829 				/* reposition the tape to BOT side of FM */
3830 				fm_dance(session);
3831 				pause_reason = NDMP_MOVER_PAUSE_EOF;
3832 				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3833 				    ++ndmp_log_msg_id, "End of file reached.");
3834 			}
3835 		}
3836 
3837 		if (pause_reason != NDMP_MOVER_PAUSE_NA) {
3838 			err = mover_pause_v3(session, pause_reason);
3839 
3840 			/* Operation aborted or connection terminated? */
3841 			if (err < 0) {
3842 				return (0);
3843 			}
3844 			/* Retry the read from new location */
3845 		}
3846 	}
3847 	return (session->ns_mover.md_record_size);
3848 }
3849 
3850 
3851 /*
3852  * mover_data_write_v3
3853  *
3854  * Reads backup data from the tape device and writes the
3855  * data to the data connection.
3856  * This function is called by ndmpd_select when the data connection
3857  * is ready for more data to be written.
3858  *
3859  * Parameters:
3860  *   cookie  (input) - session pointer.
3861  *   fd      (input) - file descriptor.
3862  *   mode    (input) - select mode.
3863  *
3864  * Returns:
3865  *   void.
3866  */
3867 /*ARGSUSED*/
3868 static void
3869 mover_data_write_v3(void *cookie, int fd, ulong_t mode)
3870 {
3871 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3872 	int n;
3873 	ulong_t len;
3874 	u_longlong_t wlen;
3875 	ndmp_notify_mover_paused_request pause_request;
3876 
3877 	/*
3878 	 * If the end of the mover window has been reached,
3879 	 * then notify the client that a seek is needed.
3880 	 * Remove the file handler to prevent this function from
3881 	 * being called. The handler will be reinstalled in
3882 	 * ndmpd_mover_continue.
3883 	 */
3884 	if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
3885 	    + session->ns_mover.md_window_length) {
3886 		NDMP_LOG(LOG_DEBUG,
3887 		    "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
3888 
3889 		session->ns_mover.md_w_index = 0;
3890 		session->ns_mover.md_r_index = 0;
3891 
3892 		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3893 		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
3894 		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
3895 		pause_request.seek_position =
3896 		    long_long_to_quad(session->ns_mover.md_position);
3897 		session->ns_mover.md_seek_position =
3898 		    session->ns_mover.md_position;
3899 
3900 		(void) ndmpd_remove_file_handler(session, fd);
3901 
3902 		if (ndmp_send_request(session->ns_connection,
3903 		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
3904 		    (void *)&pause_request, 0) < 0) {
3905 			NDMP_LOG(LOG_DEBUG,
3906 			    "Sending notify_mover_paused request");
3907 			ndmpd_mover_error(session,
3908 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
3909 		}
3910 		return;
3911 	}
3912 
3913 	/*
3914 	 * Read more data into the tape buffer if the buffer is empty.
3915 	 */
3916 	if (session->ns_mover.md_w_index == 0) {
3917 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
3918 
3919 		NDMP_LOG(LOG_DEBUG,
3920 		    "read %u bytes from tape", n);
3921 
3922 		if (n <= 0) {
3923 			ndmpd_mover_error(session, (n == 0 ?
3924 			    NDMP_MOVER_HALT_ABORTED
3925 			    : NDMP_MOVER_HALT_MEDIA_ERROR));
3926 			return;
3927 		}
3928 
3929 		/*
3930 		 * Discard data if the current data stream position is
3931 		 * prior to the seek position. This is necessary if a seek
3932 		 * request set the seek pointer to a position that is not a
3933 		 * record boundary. The seek request handler can only position
3934 		 * to the start of a record.
3935 		 */
3936 		if (session->ns_mover.md_position <
3937 		    session->ns_mover.md_seek_position) {
3938 			session->ns_mover.md_r_index =
3939 			    session->ns_mover.md_seek_position -
3940 			    session->ns_mover.md_position;
3941 			session->ns_mover.md_position =
3942 			    session->ns_mover.md_seek_position;
3943 		}
3944 
3945 		session->ns_mover.md_w_index = n;
3946 		session->ns_mover.md_record_num++;
3947 	}
3948 
3949 	/*
3950 	 * The limit on the total amount of data to be sent can be
3951 	 * dictated by either the end of the mover window or the end of the
3952 	 * seek window.
3953 	 * First determine which window applies and then determine if the
3954 	 * send length needs to be less than a full record to avoid
3955 	 * exceeding the window.
3956 	 */
3957 	if (session->ns_mover.md_position +
3958 	    session->ns_mover.md_bytes_left_to_read >
3959 	    session->ns_mover.md_window_offset +
3960 	    session->ns_mover.md_window_length)
3961 		wlen = session->ns_mover.md_window_offset +
3962 		    session->ns_mover.md_window_length -
3963 		    session->ns_mover.md_position;
3964 	else
3965 		wlen = session->ns_mover.md_bytes_left_to_read;
3966 
3967 	NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
3968 
3969 	/*
3970 	 * Now limit the length to the amount of data in the buffer.
3971 	 */
3972 	if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
3973 		wlen = session->ns_mover.md_w_index -
3974 		    session->ns_mover.md_r_index;
3975 
3976 	len = wlen & 0xffffffff;
3977 	NDMP_LOG(LOG_DEBUG,
3978 	    "buffer restrictions: wlen %llu len %u", wlen, len);
3979 
3980 	/*
3981 	 * Write the data to the data connection.
3982 	 */
3983 	n = write(session->ns_mover.md_sock,
3984 	    &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
3985 
3986 	if (n < 0) {
3987 		if (errno == EWOULDBLOCK) {
3988 			NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
3989 			return;
3990 		}
3991 
3992 		NDMP_LOG(LOG_DEBUG, "n %d errno %d", n, errno);
3993 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3994 		return;
3995 	}
3996 
3997 	NDMP_LOG(LOG_DEBUG,
3998 	    "wrote %u of %u bytes to data connection position %llu r_index %lu",
3999 	    n, len, session->ns_mover.md_position,
4000 	    session->ns_mover.md_r_index);
4001 
4002 	session->ns_mover.md_r_index += n;
4003 	session->ns_mover.md_position += n;
4004 	session->ns_mover.md_bytes_left_to_read -= n;
4005 
4006 	/*
4007 	 * If all data in the buffer has been written,
4008 	 * zero the buffer indices. The next call to this function
4009 	 * will read more data from the tape device into the buffer.
4010 	 */
4011 	if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
4012 		session->ns_mover.md_r_index = 0;
4013 		session->ns_mover.md_w_index = 0;
4014 	}
4015 
4016 	/*
4017 	 * If the read limit has been reached,
4018 	 * then remove the file handler to prevent this
4019 	 * function from getting called. The next mover_read request
4020 	 * will reinstall the handler.
4021 	 */
4022 	if (session->ns_mover.md_bytes_left_to_read == 0)
4023 		(void) ndmpd_remove_file_handler(session, fd);
4024 }
4025 
4026 
4027 /*
4028  * accept_connection_v3
4029  *
4030  * Accept a data connection from a data server.
4031  * Called by ndmpd_select when a connection is pending on
4032  * the mover listen socket.
4033  *
4034  * Parameters:
4035  *   cookie  (input) - session pointer.
4036  *   fd      (input) - file descriptor.
4037  *   mode    (input) - select mode.
4038  *
4039  * Returns:
4040  *   void.
4041  */
4042 /*ARGSUSED*/
4043 static void
4044 accept_connection_v3(void *cookie, int fd, ulong_t mode)
4045 {
4046 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
4047 	int from_len;
4048 	struct sockaddr_in from;
4049 	int flag = 1;
4050 
4051 	from_len = sizeof (from);
4052 	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
4053 	    &from_len);
4054 
4055 	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
4056 	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
4057 
4058 	(void) ndmpd_remove_file_handler(session, fd);
4059 	(void) close(session->ns_mover.md_listen_sock);
4060 	session->ns_mover.md_listen_sock = -1;
4061 
4062 	if (session->ns_mover.md_sock < 0) {
4063 		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
4064 		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
4065 		return;
4066 	}
4067 
4068 	/*
4069 	 * Save the peer address.
4070 	 */
4071 	session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
4072 	session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
4073 
4074 	/*
4075 	 * Set the parameter of the new socket.
4076 	 */
4077 	(void) setsockopt(session->ns_mover.md_sock, SOL_SOCKET, SO_KEEPALIVE,
4078 	    &flag, sizeof (flag));
4079 
4080 	ndmp_set_socket_nodelay(session->ns_mover.md_sock);
4081 	if (ndmp_sbs > 0)
4082 		ndmp_set_socket_snd_buf(session->ns_mover.md_sock,
4083 		    ndmp_sbs*KILOBYTE);
4084 	if (ndmp_rbs > 0)
4085 		ndmp_set_socket_rcv_buf(session->ns_mover.md_sock,
4086 		    ndmp_rbs*KILOBYTE);
4087 
4088 	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
4089 
4090 	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
4091 		if (ndmpd_add_file_handler(session, (void*)session,
4092 		    session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
4093 		    HC_MOVER, mover_data_read_v3) < 0) {
4094 			ndmpd_mover_error(session,
4095 			    NDMP_MOVER_HALT_INTERNAL_ERROR);
4096 			return;
4097 		}
4098 		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
4099 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4100 		    ntohs(from.sin_port));
4101 	} else {
4102 		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
4103 		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4104 		    ntohs(from.sin_port));
4105 	}
4106 
4107 	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
4108 }
4109 
4110 
4111 /*
4112  * create_listen_socket_v3
4113  *
4114  * Creates a socket for listening for accepting data connections.
4115  *
4116  * Parameters:
4117  *   session (input)  - session pointer.
4118  *   addr    (output) - location to store address of socket.
4119  *   port    (output) - location to store port of socket.
4120  *
4121  * Returns:
4122  *   0 - success.
4123  *  -1 - error.
4124  */
4125 static int
4126 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
4127 {
4128 	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
4129 	if (session->ns_mover.md_listen_sock < 0)
4130 		return (-1);
4131 
4132 	/*
4133 	 * Add a file handler for the listen socket.
4134 	 * ndmpd_select will call accept_connection when a
4135 	 * connection is ready to be accepted.
4136 	 */
4137 	if (ndmpd_add_file_handler(session, (void *) session,
4138 	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
4139 	    accept_connection_v3) < 0) {
4140 		(void) close(session->ns_mover.md_listen_sock);
4141 		session->ns_mover.md_listen_sock = -1;
4142 		return (-1);
4143 	}
4144 	NDMP_LOG(LOG_DEBUG, "IP %s port %d",
4145 	    inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
4146 	return (0);
4147 }
4148 
4149 
4150 /*
4151  * mover_connect_sock_v3
4152  *
4153  * Connect the mover to the specified address
4154  *
4155  * Parameters:
4156  *   session (input)  - session pointer.
4157  *   mode    (input)  - mover mode.
4158  *   addr    (output) - location to store address of socket.
4159  *   port    (output) - location to store port of socket.
4160  *
4161  * Returns:
4162  *   error code.
4163  */
4164 static ndmp_error
4165 mover_connect_sock_v3(ndmpd_session_t *session, ndmp_mover_mode mode,
4166     ulong_t addr, ushort_t port)
4167 {
4168 	int sock;
4169 
4170 	sock = ndmp_connect_sock_v3(addr, port);
4171 	if (sock < 0)
4172 		return (NDMP_CONNECT_ERR);
4173 
4174 	if (mode == NDMP_MOVER_MODE_READ) {
4175 		if (ndmpd_add_file_handler(session, (void*)session, sock,
4176 		    NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
4177 			(void) close(sock);
4178 			return (NDMP_CONNECT_ERR);
4179 		}
4180 	}
4181 	session->ns_mover.md_sock = sock;
4182 	session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
4183 	session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
4184 	session->ns_mover.md_data_addr.tcp_port_v3 = port;
4185 	return (NDMP_NO_ERR);
4186 }
4187 
4188 
4189 /*
4190  * ndmpd_local_read_v3
4191  *
4192  * Reads data from the local tape device.
4193  * Full tape records are read and buffered.
4194  *
4195  * Parameters:
4196  *   session (input) - session pointer.
4197  *   data    (input) - location to store data.
4198  *   length  (input) - data length.
4199  *
4200  * Returns:
4201  *   1 - no read error but no writer running
4202  *   0 - data successfully read.
4203  *  -1 - error.
4204  */
4205 int
4206 ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
4207 {
4208 	ulong_t count;
4209 	ulong_t len;
4210 	ssize_t n;
4211 
4212 	count = 0;
4213 	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
4214 	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
4215 	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
4216 		NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
4217 		return (-1);
4218 	}
4219 
4220 	/*
4221 	 * Automatically increase the seek window if necessary.
4222 	 * This is needed in the event the module attempts to read
4223 	 * past a seek window set via a prior call to ndmpd_seek() or
4224 	 * the module has not issued a seek. If no seek was issued then
4225 	 * pretend that a seek was issued to read the entire tape.
4226 	 */
4227 	if (length > session->ns_mover.md_bytes_left_to_read) {
4228 		/* ndmpd_seek() never called? */
4229 		if (session->ns_data.dd_read_length == 0) {
4230 			session->ns_mover.md_bytes_left_to_read = ~0LL;
4231 			session->ns_data.dd_read_offset = 0LL;
4232 			session->ns_data.dd_read_length = ~0LL;
4233 		} else {
4234 			session->ns_mover.md_bytes_left_to_read = length;
4235 			session->ns_data.dd_read_offset =
4236 			    session->ns_mover.md_position;
4237 			session->ns_data.dd_read_length = length;
4238 		}
4239 	}
4240 
4241 	/*
4242 	 * Read as many records as necessary to satisfy the request.
4243 	 */
4244 	while (count < length) {
4245 		/*
4246 		 * If the end of the mover window has been reached,
4247 		 * then notify the client that a new data window is needed.
4248 		 */
4249 		if (session->ns_mover.md_position >=
4250 		    session->ns_mover.md_window_offset +
4251 		    session->ns_mover.md_window_length) {
4252 			if (mover_pause_v3(session,
4253 			    NDMP_MOVER_PAUSE_SEEK) < 0) {
4254 				ndmpd_mover_error(session,
4255 				    NDMP_MOVER_HALT_INTERNAL_ERROR);
4256 				return (-1);
4257 			}
4258 			continue;
4259 		}
4260 
4261 		len = length - count;
4262 
4263 		/*
4264 		 * Prevent reading past the end of the window.
4265 		 */
4266 		if (len > session->ns_mover.md_window_offset +
4267 		    session->ns_mover.md_window_length -
4268 		    session->ns_mover.md_position)
4269 			len = session->ns_mover.md_window_offset +
4270 			    session->ns_mover.md_window_length -
4271 			    session->ns_mover.md_position;
4272 
4273 		/*
4274 		 * Copy from the data buffer first.
4275 		 */
4276 		if (session->ns_mover.md_w_index -
4277 		    session->ns_mover.md_r_index != 0) {
4278 			/*
4279 			 * Limit the copy to the amount of data in the buffer.
4280 			 */
4281 			if (len > session->ns_mover.md_w_index -
4282 			    session->ns_mover.md_r_index)
4283 				len = session->ns_mover.md_w_index -
4284 				    session->ns_mover.md_r_index;
4285 			(void) memcpy((void*)&data[count],
4286 			    &session->ns_mover.md_buf[session->
4287 			    ns_mover.md_r_index], len);
4288 			count += len;
4289 			session->ns_mover.md_r_index += len;
4290 			session->ns_mover.md_bytes_left_to_read -= len;
4291 			session->ns_mover.md_position += len;
4292 			continue;
4293 		}
4294 
4295 		/*
4296 		 * Determine if data needs to be buffered or
4297 		 * can be read directly to user supplied location.
4298 		 * We can fast path the read if at least a full record
4299 		 * needs to be read and there is no seek pending.
4300 		 * This is done to eliminate a buffer copy.
4301 		 */
4302 		if (len >= session->ns_mover.md_record_size &&
4303 		    session->ns_mover.md_position >=
4304 		    session->ns_mover.md_seek_position) {
4305 			n = mover_tape_read_v3(session, &data[count]);
4306 			if (n <= 0) {
4307 				if (n == TAPE_NO_WRITER_ERR)
4308 					return (1);
4309 
4310 				ndmpd_mover_error(session,
4311 				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4312 				    NDMP_MOVER_HALT_MEDIA_ERROR));
4313 				return ((n == 0) ? 1 : -1);
4314 			}
4315 
4316 			count += n;
4317 			session->ns_mover.md_bytes_left_to_read -= n;
4318 			session->ns_mover.md_position += n;
4319 			session->ns_mover.md_record_num++;
4320 			continue;
4321 		}
4322 
4323 		/* Read the next record into the buffer. */
4324 		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4325 		if (n <= 0) {
4326 			if (n == TAPE_NO_WRITER_ERR)
4327 				return (1);
4328 
4329 			ndmpd_mover_error(session,
4330 			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4331 			    NDMP_MOVER_HALT_MEDIA_ERROR));
4332 			return ((n == 0) ? 1 : -1);
4333 		}
4334 
4335 		session->ns_mover.md_w_index = n;
4336 		session->ns_mover.md_r_index = 0;
4337 		session->ns_mover.md_record_num++;
4338 
4339 		NDMP_LOG(LOG_DEBUG, "n: %d", n);
4340 
4341 		/*
4342 		 * Discard data if the current data stream position is
4343 		 * prior to the seek position. This is necessary if a seek
4344 		 * request set the seek pointer to a position that is not a
4345 		 * record boundary. The seek request handler can only position
4346 		 * to the start of a record.
4347 		 */
4348 		if (session->ns_mover.md_position <
4349 		    session->ns_mover.md_seek_position) {
4350 			session->ns_mover.md_r_index =
4351 			    session->ns_mover.md_seek_position -
4352 			    session->ns_mover.md_position;
4353 			session->ns_mover.md_position =
4354 			    session->ns_mover.md_seek_position;
4355 		}
4356 	}
4357 
4358 	return (0);
4359 }
4360