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