2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 * Copyright (c) 2007, The Storage Networking Industry Association.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
42 #include <sys/param.h>
49 #include "ndmpd_common.h"
52 static void tape_open_send_reply(ndmp_connection_t
*connection
, int err
);
53 static void unbuffered_read(ndmpd_session_t
*session
, char *buf
, long wanted
,
54 ndmp_tape_read_reply
*reply
);
55 static boolean_t
validmode(int mode
);
56 static void common_tape_open(ndmp_connection_t
*connection
, char *devname
,
58 static void common_tape_close(ndmp_connection_t
*connection
);
61 * Configurable delay & time when the tape is
62 * busy during opening the tape.
64 int ndmp_tape_open_retries
= 5;
65 int ndmp_tape_open_delay
= 1000;
68 * A few words about EOT (end-of-tape) and EOM handling on tapes with SVR4
71 * We adhere to terminology as used in st driver. EOT means end of recorded
72 * data on a tape. This is different from EOM (somewhere referred to as LEOT)
73 * which is the end of tape medium. EOT is meaningful only for reads while EOM
74 * is meaningful only for writes. It's not possible to read after EOT (fails
75 * with EIO), but it's possible to write data after EOM. EOM returned by st
76 * driver on modern tape drives is just indication that the physical end of
77 * tape medium is nearing and that writer should write just the necessary
78 * minimum and stop writing. When physical end of tape is reached all writes
79 * return EIO. If EOM is crossed during read operation then st driver doesn't
80 * bother to report it to client and that's alright because reads don't care
81 * where medium physically ends but they care about meaningful data recorded on
82 * the tape and as long as there are such data reads should continue to work.
84 * When reading EOT is signalled by st driver by two empty consecutive reads
85 * (with FSF done between them). When writing EOM is signalled by empty write
86 * (a write which writes zero bytes). Following writes succeed until physical
87 * end of tape is reached in which case EIO is returned.
91 * ************************************************************************
93 * ************************************************************************
99 * This handler opens the specified tape device.
102 * connection (input) - connection handle.
103 * body (input) - request message body.
109 ndmpd_tape_open_v2(ndmp_connection_t
*connection
, void *body
)
111 ndmp_tape_open_request_v2
*request
= (ndmp_tape_open_request_v2
*) body
;
112 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
113 char adptnm
[SCSI_MAX_NAME
];
122 if (session
->ns_tape
.td_fd
!= -1 || session
->ns_scsi
.sd_is_open
!= -1) {
124 "Connection already has a tape or scsi device open");
125 err
= NDMP_DEVICE_OPENED_ERR
;
126 } else if (request
->mode
!= NDMP_TAPE_READ_MODE
&&
127 request
->mode
!= NDMP_TAPE_WRITE_MODE
&&
128 request
->mode
!= NDMP_TAPE_RAW1_MODE
) {
129 err
= NDMP_ILLEGAL_ARGS_ERR
;
132 if ((sa
= scsi_get_adapter(0)) != NULL
) {
134 "Adapter device opened: %s", request
->device
.name
);
135 (void) strlcpy(adptnm
, request
->device
.name
, SCSI_MAX_NAME
-2);
136 adptnm
[SCSI_MAX_NAME
-1] = '\0';
139 /* try to get the scsi id etc.... */
141 scsi_find_sid_lun(sa
, request
->device
.name
, &sid
, &lun
);
142 if (ndmp_open_list_find(request
->device
.name
, sid
, lun
) == 0 &&
143 (devid
= tape_open(request
->device
.name
,
144 O_RDWR
| O_NDELAY
)) < 0) {
145 NDMP_LOG(LOG_ERR
, "Failed to open device %s: %m.",
146 request
->device
.name
);
147 err
= NDMP_NO_DEVICE_ERR
;
152 NDMP_LOG(LOG_ERR
, "%s: No such tape device.",
153 request
->device
.name
);
154 err
= NDMP_NO_DEVICE_ERR
;
156 if (err
!= NDMP_NO_ERR
) {
157 tape_open_send_reply(connection
, err
);
161 switch (ndmp_open_list_add(connection
, adptnm
, sid
, lun
, devid
)) {
166 err
= NDMP_DEVICE_BUSY_ERR
;
169 err
= NDMP_NO_MEM_ERR
;
174 if (err
!= NDMP_NO_ERR
) {
175 tape_open_send_reply(connection
, err
);
180 * According to Connectathon 2001, the 0x7fffffff is a secret
181 * code between "Workstartion Solutions" and * net_app.
182 * If mode is set to this value, tape_open() won't fail if
183 * the tape device is not ready.
185 if (request
->mode
!= NDMP_TAPE_RAW1_MODE
&&
186 !is_tape_unit_ready(adptnm
, 0)) {
187 (void) ndmp_open_list_del(adptnm
, sid
, lun
);
188 tape_open_send_reply(connection
, NDMP_NO_TAPE_LOADED_ERR
);
192 mode
= (request
->mode
== NDMP_TAPE_READ_MODE
) ? O_RDONLY
: O_RDWR
;
194 if ((session
->ns_tape
.td_fd
= open(request
->device
.name
, mode
)) < 0) {
195 NDMP_LOG(LOG_ERR
, "Failed to open tape device %s: %m.",
196 request
->device
.name
);
199 err
= NDMP_WRITE_PROTECT_ERR
;
203 err
= NDMP_NO_DEVICE_ERR
;
206 err
= NDMP_DEVICE_BUSY_ERR
;
212 (void) ndmp_open_list_del(adptnm
, sid
, lun
);
213 tape_open_send_reply(connection
, err
);
217 session
->ns_tape
.td_mode
= request
->mode
;
218 session
->ns_tape
.td_sid
= sid
;
219 session
->ns_tape
.td_lun
= lun
;
220 (void) strlcpy(session
->ns_tape
.td_adapter_name
, adptnm
, SCSI_MAX_NAME
);
221 session
->ns_tape
.td_record_count
= 0;
223 NDMP_LOG(LOG_DEBUG
, "Tape is opened fd: %d", session
->ns_tape
.td_fd
);
225 tape_open_send_reply(connection
, NDMP_NO_ERR
);
230 * ndmpd_tape_close_v2
232 * This handler closes the currently open tape device.
235 * connection (input) - connection handle.
236 * body (input) - request message body.
243 ndmpd_tape_close_v2(ndmp_connection_t
*connection
, void *body
)
245 ndmp_tape_close_reply reply
;
246 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
248 if (session
->ns_tape
.td_fd
== -1) {
249 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
250 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
251 ndmp_send_reply(connection
, (void *) &reply
,
252 "sending tape_close reply");
255 common_tape_close(connection
);
260 * ndmpd_tape_get_state_v2
262 * This handler handles the tape_get_state request.
263 * Status information for the currently open tape device is returned.
266 * connection (input) - connection handle.
267 * body (input) - request message body.
274 ndmpd_tape_get_state_v2(ndmp_connection_t
*connection
, void *body
)
277 ndmp_tape_get_state_reply_v2 reply
;
278 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
279 struct mtget mtstatus
;
280 struct mtdrivetype_request dtpr
;
281 struct mtdrivetype dtp
;
283 if (session
->ns_tape
.td_fd
== -1) {
284 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
285 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
286 ndmp_send_reply(connection
, (void *) &reply
,
287 "sending tape_get_state reply");
291 if (ioctl(session
->ns_tape
.td_fd
, MTIOCGET
, &mtstatus
) < 0) {
292 NDMP_LOG(LOG_ERR
, "Failed to get status from tape: %m.");
293 NDMP_LOG(LOG_DEBUG
, "ioctl(MTIOCGET) error: %m.");
294 reply
.error
= NDMP_IO_ERR
;
295 ndmp_send_reply(connection
, (void *)&reply
,
296 "sending tape_get_state reply");
300 dtpr
.size
= sizeof (struct mtdrivetype
);
302 if (ioctl(session
->ns_tape
.td_fd
, MTIOCGETDRIVETYPE
, &dtpr
) == -1) {
304 "Failed to get drive type information from tape: %m.");
305 NDMP_LOG(LOG_DEBUG
, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
306 reply
.error
= NDMP_IO_ERR
;
307 ndmp_send_reply(connection
, (void *)&reply
,
308 "sending tape_get_state reply");
314 reply
.file_num
= mtstatus
.mt_fileno
;
315 reply
.soft_errors
= 0;
316 reply
.block_size
= dtp
.bsize
;
318 reply
.blockno
= mtstatus
.mt_blkno
;
320 reply
.blockno
= mtstatus
.mt_blkno
*
321 (session
->ns_mover
.md_record_size
/ dtp
.bsize
);
323 reply
.soft_errors
= 0;
324 reply
.total_space
= long_long_to_quad(0); /* not supported */
325 reply
.space_remain
= long_long_to_quad(0); /* not supported */
328 "flags: 0x%x, file_num: %d, block_size: %d, blockno: %d",
329 reply
.flags
, reply
.file_num
, reply
.block_size
, reply
.blockno
);
331 reply
.error
= NDMP_NO_ERR
;
332 ndmp_send_reply(connection
, (void *) &reply
,
333 "sending tape_get_state reply");
340 * This handler handles tape_mtio requests.
343 * connection (input) - connection handle.
344 * body (input) - request message body.
350 ndmpd_tape_mtio_v2(ndmp_connection_t
*connection
, void *body
)
352 ndmp_tape_mtio_request
*request
= (ndmp_tape_mtio_request
*) body
;
353 ndmp_tape_mtio_reply reply
;
354 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
357 struct mtget mtstatus
;
361 reply
.resid_count
= 0;
363 if (session
->ns_tape
.td_fd
== -1) {
364 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
365 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
366 ndmp_send_reply(connection
, (void *) &reply
,
367 "sending tape_mtio reply");
371 reply
.error
= NDMP_NO_ERR
;
372 switch (request
->tape_op
) {
374 tapeop
.mt_op
= MTFSF
;
377 tapeop
.mt_op
= MTBSF
;
380 tapeop
.mt_op
= MTFSR
;
383 tapeop
.mt_op
= MTBSR
;
386 tapeop
.mt_op
= MTREW
;
389 if (session
->ns_tape
.td_mode
== NDMP_TAPE_READ_MODE
)
390 reply
.error
= NDMP_PERMISSION_ERR
;
391 tapeop
.mt_op
= MTWEOF
;
394 tapeop
.mt_op
= MTOFFL
;
397 case NDMP_MTIO_TUR
: /* test unit ready */
399 if (is_tape_unit_ready(session
->ns_tape
.td_adapter_name
,
400 session
->ns_tape
.td_fd
) == 0)
401 /* tape not ready ? */
402 reply
.error
= NDMP_NO_TAPE_LOADED_ERR
;
406 reply
.error
= NDMP_ILLEGAL_ARGS_ERR
;
409 if (reply
.error
== NDMP_NO_ERR
&& request
->tape_op
!= NDMP_MTIO_TUR
) {
410 tapeop
.mt_count
= request
->count
;
415 rc
= ioctl(session
->ns_tape
.td_fd
, MTIOCTOP
, &tapeop
);
418 "ioctl MTIO rc:%d, cmd:%d, retry:%d, error: %d",
419 rc
, tapeop
.mt_op
, retry
, errno
);
420 } while (rc
< 0 && errno
== EIO
&&
424 * Ignore I/O errors since these usually are the result of
425 * attempting to position past the beginning or end of the tape.
426 * The residual count will be returned and can be used to
427 * determine that the call was not completely successful.
431 "Failed to send command to tape: %m.");
432 NDMP_LOG(LOG_DEBUG
, "ioctl(MTIOCTOP) error: %m.");
434 /* MTWEOF doesnt have residual count */
435 if (tapeop
.mt_op
== MTWEOF
)
436 reply
.error
= NDMP_IO_ERR
;
438 reply
.error
= NDMP_NO_ERR
;
439 reply
.resid_count
= tapeop
.mt_count
;
440 ndmp_send_reply(connection
, (void *)&reply
,
441 "sending tape_mtio reply");
445 if (request
->tape_op
!= NDMP_MTIO_REW
&&
446 request
->tape_op
!= NDMP_MTIO_OFF
) {
447 if (ioctl(session
->ns_tape
.td_fd
, MTIOCGET
,
450 "Failed to send command to tape: %m.");
452 "ioctl(MTIOCGET) error: %m.");
453 reply
.error
= NDMP_IO_ERR
;
454 ndmp_send_reply(connection
, (void *)&reply
,
455 "sending tape_mtio reply");
460 reply
.resid_count
= labs(mtstatus
.mt_resid
);
464 NDMP_LOG(LOG_DEBUG
, "resid_count: %d",
466 ndmp_send_reply(connection
, (void *) &reply
, "sending tape_mtio reply");
473 * This handler handles tape_read requests.
474 * This interface is a non-buffered interface. Each read request
475 * maps directly to a read to the tape device. It is the responsibility
476 * of the NDMP client to issue read requests with a length that is at
477 * least as large as the record size used write the tape. The tape driver
478 * always reads a full record. Data is discarded if the read request is
479 * smaller than the record size.
480 * It is the responsibility of the NDMP client to ensure that the
481 * length is a multiple of the tape block size if the tape device
482 * is in fixed block mode.
485 * connection (input) - connection handle.
486 * body (input) - request message body.
492 ndmpd_tape_read_v2(ndmp_connection_t
*connection
, void *body
)
494 ndmp_tape_read_request
*request
= (ndmp_tape_read_request
*) body
;
495 ndmp_tape_read_reply reply
;
496 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
499 reply
.data_in
.data_in_len
= 0;
501 if (session
->ns_tape
.td_fd
== -1) {
502 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
503 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
504 ndmp_send_reply(connection
, (void *)&reply
,
505 "sending tape_read reply");
508 if (request
->count
== 0) {
509 reply
.error
= NDMP_NO_ERR
;
510 ndmp_send_reply(connection
, (void *)&reply
,
511 "sending tape_read reply");
514 if ((buf
= ndmp_malloc(request
->count
)) == 0) {
515 reply
.error
= NDMP_NO_MEM_ERR
;
516 ndmp_send_reply(connection
, (void *)&reply
,
517 "sending tape_read reply");
521 unbuffered_read(session
, buf
, request
->count
, &reply
);
523 ndmp_send_reply(connection
, (void *) &reply
, "sending tape_read reply");
529 * ndmpd_tape_execute_cdb_v2
531 * This handler handles tape_execute_cdb requests.
534 * connection (input) - connection handle.
535 * body (input) - request message body.
541 ndmpd_tape_execute_cdb_v2(ndmp_connection_t
*connection
, void *body
)
543 ndmp_tape_execute_cdb_request
*request
;
544 ndmp_tape_execute_cdb_reply reply
;
545 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
547 request
= (ndmp_tape_execute_cdb_request
*) body
;
549 if (session
->ns_tape
.td_fd
== -1) {
550 (void) memset((void *) &reply
, 0, sizeof (reply
));
552 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
553 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
554 ndmp_send_reply(connection
, (void *) &reply
,
555 "sending tape_execute_cdb reply");
557 ndmp_execute_cdb(session
, session
->ns_tape
.td_adapter_name
,
558 session
->ns_tape
.td_sid
, session
->ns_tape
.td_lun
,
559 (ndmp_execute_cdb_request
*)request
);
565 * ************************************************************************
567 * ************************************************************************
573 * This handler opens the specified tape device.
576 * connection (input) - connection handle.
577 * body (input) - request message body.
583 ndmpd_tape_open_v3(ndmp_connection_t
*connection
, void *body
)
585 ndmp_tape_open_request_v3
*request
= (ndmp_tape_open_request_v3
*)body
;
587 common_tape_open(connection
, request
->device
, request
->mode
);
592 * ndmpd_tape_get_state_v3
594 * This handler handles the ndmp_tape_get_state_request.
595 * Status information for the currently open tape device is returned.
598 * connection (input) - connection handle.
599 * body (input) - request message body.
606 ndmpd_tape_get_state_v3(ndmp_connection_t
*connection
, void *body
)
608 ndmp_tape_get_state_reply_v3 reply
;
609 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
610 struct mtdrivetype_request dtpr
;
611 struct mtdrivetype dtp
;
612 struct mtget mtstatus
;
614 if (session
->ns_tape
.td_fd
== -1) {
615 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
616 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
617 ndmp_send_reply(connection
, (void *) &reply
,
618 "sending tape_get_state reply");
622 if (ioctl(session
->ns_tape
.td_fd
, MTIOCGET
, &mtstatus
) == -1) {
623 NDMP_LOG(LOG_ERR
, "Failed to get status from tape: %m.");
624 NDMP_LOG(LOG_DEBUG
, "ioctl(MTIOCGET) error: %m.");
626 reply
.error
= NDMP_IO_ERR
;
627 ndmp_send_reply(connection
, (void *)&reply
,
628 "sending tape_get_state reply");
632 dtpr
.size
= sizeof (struct mtdrivetype
);
634 if (ioctl(session
->ns_tape
.td_fd
, MTIOCGETDRIVETYPE
, &dtpr
) == -1) {
636 "Failed to get drive type information from tape: %m.");
637 NDMP_LOG(LOG_DEBUG
, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
639 reply
.error
= NDMP_IO_ERR
;
640 ndmp_send_reply(connection
, (void *)&reply
,
641 "sending tape_get_state reply");
647 reply
.file_num
= mtstatus
.mt_fileno
;
648 reply
.soft_errors
= 0;
649 reply
.block_size
= dtp
.bsize
;
651 reply
.blockno
= mtstatus
.mt_blkno
;
653 reply
.blockno
= mtstatus
.mt_blkno
*
654 (session
->ns_mover
.md_record_size
/ dtp
.bsize
);
655 reply
.total_space
= long_long_to_quad(0); /* not supported */
656 reply
.space_remain
= long_long_to_quad(0); /* not supported */
657 reply
.partition
= 0; /* not supported */
659 reply
.soft_errors
= 0;
660 reply
.total_space
= long_long_to_quad(0LL);
661 reply
.space_remain
= long_long_to_quad(0LL);
663 reply
.invalid
= NDMP_TAPE_STATE_SOFT_ERRORS_INVALID
|
664 NDMP_TAPE_STATE_TOTAL_SPACE_INVALID
|
665 NDMP_TAPE_STATE_SPACE_REMAIN_INVALID
|
666 NDMP_TAPE_STATE_PARTITION_INVALID
;
669 NDMP_LOG(LOG_DEBUG
, "f 0x%x, fnum %d, bsize %d, bno: %d",
670 reply
.flags
, reply
.file_num
, reply
.block_size
, reply
.blockno
);
672 reply
.error
= NDMP_NO_ERR
;
673 ndmp_send_reply(connection
, (void *) &reply
,
674 "sending tape_get_state reply");
680 * Returns 1 if tape is at BOT, 0 on error or not at BOT.
684 tape_is_at_bot(ndmpd_session_t
*session
)
686 struct mtget mtstatus
;
688 if (ioctl(session
->ns_tape
.td_fd
, MTIOCGET
, &mtstatus
) == 0 &&
689 mtstatus
.mt_fileno
== 0 && mtstatus
.mt_blkno
== 0)
696 * If we are at the beginning of a file (block # is zero) and read returns
697 * zero bytes then this has to be end of recorded data on the tape. Repeated
698 * reads at EOT return EIO. In both cases (zero read and EIO read) this
699 * function should be used to test if we are at EOT.
701 * Returns 1 if tape is at BOF, 0 on error or not at BOF.
704 tape_is_at_bof(ndmpd_session_t
*session
)
706 struct mtget mtstatus
;
708 if ((ioctl(session
->ns_tape
.td_fd
, MTIOCGET
, &mtstatus
) == 0) &&
709 (mtstatus
.mt_fileno
> 0) && (mtstatus
.mt_blkno
== 0))
716 * Skips forward over a file mark and then back before the file mark. Why is
717 * this needed? There are two reasons for it:
719 * 1) Because NDMPv4 spec requires that when EOF is encountered, the tape
720 * position should remain on BOT side of the file mark. When st driver reaches
721 * end of file get-position mtioctl reports position before file mark, however
722 * the file mark has already been read and the real position is thus after the
723 * file mark (real position as reported for example by uscsi commands). Thus we
724 * need to do FSF, which does nothing but only updates file & block counter in
725 * st driver and then BSF, which sets the position before the file mark. Thus
726 * current position as reported by scsi and mtioctl will be in sync.
728 * 2) st driver returns EIO for repeated reads at EOF while according to NDMP
729 * spec we should continue to return zero bytes until FSF is done. By skipping
730 * forward and backward, st driver will return zero bytes for the next read
731 * again and we don't need to specifically handle this case.
734 fm_dance(ndmpd_session_t
*session
)
736 (void) ndmp_mtioctl(session
->ns_tape
.td_fd
, MTFSF
, 1);
737 (void) ndmp_mtioctl(session
->ns_tape
.td_fd
, MTBSF
, 1);
741 * ndmpd_tape_write_v3
743 * This handler handles tape_write requests. This interface is a non-buffered
744 * interface. Each write request maps directly to a write to the tape device.
745 * It is the responsibility of the NDMP client to pad the data to the desired
746 * record size. It is the responsibility of the NDMP client to ensure that the
747 * length is a multiple of the tape block size if the tape device is in fixed
750 * A logical end of tape will return number of bytes written less than
751 * requested, and one more request to write will give 0 and NDMP_EOM_ERR,
752 * followed by NDMP_NO_ERR until NDMP_IO_ERR when physical end of tape is
756 * connection (input) - connection handle.
757 * body (input) - request message body.
759 void ndmpd_tape_write_v3(ndmp_connection_t
*connection
, void *body
) {
760 ndmp_tape_write_request
*request
= (ndmp_tape_write_request
*)body
;
761 ndmp_tape_write_reply reply
; ndmpd_session_t
*session
=
762 ndmp_get_client_data(connection
); ssize_t n
;
766 if (session
->ns_tape
.td_fd
== -1) {
767 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
768 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
769 ndmp_send_reply(connection
, (void *) &reply
,
770 "sending tape_write reply");
773 if (session
->ns_tape
.td_mode
== NDMP_TAPE_READ_MODE
) {
774 NDMP_LOG(LOG_INFO
, "Tape device opened in read-only mode");
775 reply
.error
= NDMP_PERMISSION_ERR
;
776 ndmp_send_reply(connection
, (void *) &reply
,
777 "sending tape_write reply");
780 if (request
->data_out
.data_out_len
== 0) {
781 reply
.error
= NDMP_NO_ERR
;
782 ndmp_send_reply(connection
, (void *) &reply
,
783 "sending tape_write reply");
788 * V4 suggests that this should not be accepted
789 * when mover is in listen or active state
791 if (session
->ns_protocol_version
== NDMPV4
&&
792 (session
->ns_mover
.md_state
== NDMP_MOVER_STATE_LISTEN
||
793 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_ACTIVE
)) {
795 reply
.error
= NDMP_DEVICE_BUSY_ERR
;
796 ndmp_send_reply(connection
, (void *) &reply
,
797 "sending tape_write reply");
801 n
= write(session
->ns_tape
.td_fd
, request
->data_out
.data_out_val
,
802 request
->data_out
.data_out_len
);
805 NDMP_LOG(LOG_ERR
, "Tape write error: %m.");
806 reply
.error
= NDMP_IO_ERR
;
808 NDMP_LOG(LOG_INFO
, "EOM detected");
809 reply
.error
= NDMP_EOM_ERR
;
813 reply
.error
= NDMP_NO_ERR
;
815 if (n
< request
->data_out
.data_out_len
)
817 "EOM is coming (partial write of %d bytes)", n
);
820 ndmp_send_reply(connection
, (void *) &reply
,
821 "sending tape_write reply");
827 * This handler handles tape_read requests. This interface is a non-buffered
828 * interface. Each read request maps directly to a read to the tape device. It
829 * is the responsibility of the NDMP client to issue read requests with a
830 * length that is at least as large as the record size used write the tape. The
831 * tape driver always reads a full record. Data is discarded if the read
832 * request is smaller than the record size. It is the responsibility of the
833 * NDMP client to ensure that the length is a multiple of the tape block size
834 * if the tape device is in fixed block mode.
836 * A logical end of tape will return less bytes than requested, and one more
837 * request to read will give 0 and NDMP_EOM_ERR. All subsequent reads will
838 * return NDMP_EOM_ERR until the tape is repositioned.
841 * connection (input) - connection handle.
842 * body (input) - request message body.
845 ndmpd_tape_read_v3(ndmp_connection_t
*connection
, void *body
)
847 ndmp_tape_read_request
*request
= (ndmp_tape_read_request
*) body
;
848 ndmp_tape_read_reply reply
;
849 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
853 reply
.data_in
.data_in_len
= 0;
855 if (session
->ns_tape
.td_fd
== -1) {
856 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
857 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
858 ndmp_send_reply(connection
, (void *) &reply
,
859 "sending tape_read reply");
862 if (request
->count
== 0) {
863 reply
.error
= NDMP_NO_ERR
;
864 ndmp_send_reply(connection
, (void *) &reply
,
865 "sending tape_read reply");
870 * V4 suggests that this should not be accepted
871 * when mover is in listen or active state
873 if (session
->ns_protocol_version
== NDMPV4
&&
874 (session
->ns_mover
.md_state
== NDMP_MOVER_STATE_LISTEN
||
875 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_ACTIVE
)) {
877 reply
.error
= NDMP_DEVICE_BUSY_ERR
;
878 ndmp_send_reply(connection
, (void *) &reply
,
879 "sending tape_read reply");
883 if ((buf
= ndmp_malloc(request
->count
)) == NULL
) {
884 reply
.error
= NDMP_NO_MEM_ERR
;
885 ndmp_send_reply(connection
, (void *) &reply
,
886 "sending tape_read reply");
890 n
= read(session
->ns_tape
.td_fd
, buf
, request
->count
);
893 * This fix is for Symantec during importing
894 * of spanned data between the tapes.
896 if (errno
== ENOSPC
) {
897 reply
.error
= NDMP_EOF_ERR
;
900 * If at beginning of file and read fails with EIO, then it's
901 * repeated attempt to read at EOT.
903 else if (errno
== EIO
&& tape_is_at_bof(session
)) {
904 NDMP_LOG(LOG_DEBUG
, "Repeated read at EOT");
905 reply
.error
= NDMP_EOM_ERR
;
908 * According to NDMPv4 spec preferred error code when
909 * trying to read from blank tape is NDMP_EOM_ERR.
911 else if (errno
== EIO
&& tape_is_at_bot(session
)) {
912 NDMP_LOG(LOG_ERR
, "Blank tape detected, returning EOM");
913 reply
.error
= NDMP_EOM_ERR
;
915 NDMP_LOG(LOG_ERR
, "Tape read error: %m.");
916 reply
.error
= NDMP_IO_ERR
;
919 if (tape_is_at_bof(session
)) {
920 NDMP_LOG(LOG_DEBUG
, "EOT detected");
921 reply
.error
= NDMP_EOM_ERR
;
923 /* reposition the tape to BOT side of FM */
925 NDMP_LOG(LOG_DEBUG
, "EOF detected");
926 reply
.error
= NDMP_EOF_ERR
;
929 session
->ns_tape
.td_pos
+= n
;
930 reply
.data_in
.data_in_len
= n
;
931 reply
.data_in
.data_in_val
= buf
;
932 reply
.error
= NDMP_NO_ERR
;
936 ndmp_send_reply(connection
, (void *) &reply
, "sending tape_read reply");
942 * ************************************************************************
944 * ************************************************************************
948 * ndmpd_tape_get_state_v4
950 * This handler handles the ndmp_tape_get_state_request.
951 * Status information for the currently open tape device is returned.
954 * connection (input) - connection handle.
955 * body (input) - request message body.
962 ndmpd_tape_get_state_v4(ndmp_connection_t
*connection
, void *body
)
964 ndmp_tape_get_state_reply_v4 reply
;
965 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
966 struct mtget mtstatus
;
967 struct mtdrivetype_request dtpr
;
968 struct mtdrivetype dtp
;
970 if (session
->ns_tape
.td_fd
== -1) {
971 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
972 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
973 ndmp_send_reply(connection
, (void *) &reply
,
974 "sending tape_get_state reply");
979 * Need code to detect NDMP_TAPE_STATE_NOREWIND
982 if (ioctl(session
->ns_tape
.td_fd
, MTIOCGET
, &mtstatus
) == -1) {
984 "Failed to get status information from tape: %m.");
985 NDMP_LOG(LOG_DEBUG
, "ioctl(MTIOCGET) error: %m.");
987 reply
.error
= NDMP_IO_ERR
;
988 ndmp_send_reply(connection
, (void *)&reply
,
989 "sending tape_get_state reply");
993 dtpr
.size
= sizeof (struct mtdrivetype
);
995 if (ioctl(session
->ns_tape
.td_fd
, MTIOCGETDRIVETYPE
, &dtpr
) == -1) {
997 "Failed to get drive type information from tape: %m.");
998 NDMP_LOG(LOG_DEBUG
, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
1000 reply
.error
= NDMP_IO_ERR
;
1001 ndmp_send_reply(connection
, (void *)&reply
,
1002 "sending tape_get_state reply");
1006 reply
.flags
= NDMP_TAPE_NOREWIND
;
1008 reply
.file_num
= mtstatus
.mt_fileno
;
1009 reply
.soft_errors
= 0;
1010 reply
.block_size
= dtp
.bsize
;
1013 reply
.blockno
= mtstatus
.mt_blkno
;
1015 reply
.blockno
= mtstatus
.mt_blkno
/
1016 (session
->ns_mover
.md_record_size
/ dtp
.bsize
);
1018 reply
.total_space
= long_long_to_quad(0LL); /* not supported */
1019 reply
.space_remain
= long_long_to_quad(0LL); /* not supported */
1020 reply
.soft_errors
= 0;
1021 reply
.unsupported
= NDMP_TAPE_STATE_SOFT_ERRORS_INVALID
|
1022 NDMP_TAPE_STATE_TOTAL_SPACE_INVALID
|
1023 NDMP_TAPE_STATE_SPACE_REMAIN_INVALID
|
1024 NDMP_TAPE_STATE_PARTITION_INVALID
;
1026 NDMP_LOG(LOG_DEBUG
, "f 0x%x, fnum %d, bsize %d, bno: %d",
1027 reply
.flags
, reply
.file_num
, reply
.block_size
, reply
.blockno
);
1029 reply
.error
= NDMP_NO_ERR
;
1030 ndmp_send_reply(connection
, (void *) &reply
,
1031 "sending tape_get_state reply");
1034 * ndmpd_tape_close_v4
1036 * This handler (v4) closes the currently open tape device.
1039 * connection (input) - connection handle.
1040 * body (input) - request message body.
1047 ndmpd_tape_close_v4(ndmp_connection_t
*connection
, void *body
)
1049 ndmp_tape_close_reply reply
;
1050 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
1052 if (session
->ns_tape
.td_fd
== -1) {
1053 NDMP_LOG(LOG_ERR
, "Tape device is not open.");
1054 reply
.error
= NDMP_DEV_NOT_OPEN_ERR
;
1055 ndmp_send_reply(connection
, (void *) &reply
,
1056 "sending tape_close reply");
1061 * V4 suggests that this should not be accepted
1062 * when mover is in listen or active state
1064 if (session
->ns_mover
.md_state
== NDMP_MOVER_STATE_LISTEN
||
1065 session
->ns_mover
.md_state
== NDMP_MOVER_STATE_ACTIVE
) {
1067 reply
.error
= NDMP_DEVICE_BUSY_ERR
;
1068 ndmp_send_reply(connection
, (void *) &reply
,
1069 "sending tape_close reply");
1073 common_tape_close(connection
);
1078 * ************************************************************************
1080 * ************************************************************************
1083 * tape_open_send_reply
1085 * Send a reply to the tape open message
1088 * connection (input) - connection handle.
1089 * err (input) - NDMP error
1095 tape_open_send_reply(ndmp_connection_t
*connection
, int err
)
1097 ndmp_tape_open_reply reply
;
1100 ndmp_send_reply(connection
, (void *) &reply
, "sending tape_open reply");
1106 * Perform tape read without read-ahead
1109 * session (input) - session handle
1110 * bp (output) - read buffer
1111 * wanted (input) - number of bytes wanted
1112 * reply (output) - tape read reply message
1118 unbuffered_read(ndmpd_session_t
*session
, char *buf
, long wanted
,
1119 ndmp_tape_read_reply
*reply
)
1123 n
= read(session
->ns_tape
.td_fd
, buf
, wanted
);
1126 * This fix is for Symantec during importing
1127 * of spanned data between the tapes.
1129 if (errno
== ENOSPC
) {
1130 reply
->error
= NDMP_EOF_ERR
;
1132 NDMP_LOG(LOG_ERR
, "Tape read error: %m.");
1133 reply
->error
= NDMP_IO_ERR
;
1135 } else if (n
== 0) {
1136 NDMP_LOG(LOG_DEBUG
, "NDMP_EOF_ERR");
1138 reply
->error
= NDMP_EOF_ERR
;
1140 (void) ndmp_mtioctl(session
->ns_tape
.td_fd
, MTFSF
, 1);
1142 len
= strlen(NDMP_EOM_MAGIC
);
1143 (void) memset(buf
, 0, len
);
1144 n
= read(session
->ns_tape
.td_fd
, buf
, len
);
1147 NDMP_LOG(LOG_DEBUG
, "Checking EOM: nread %d [%s]", n
, buf
);
1149 (void) ndmp_mtioctl(session
->ns_tape
.td_fd
, MTBSF
, 1);
1151 if (strncmp(buf
, NDMP_EOM_MAGIC
, len
) != 0)
1152 (void) ndmp_mtioctl(session
->ns_tape
.td_fd
, MTFSF
, 1);
1154 session
->ns_tape
.td_pos
+= n
;
1155 reply
->data_in
.data_in_len
= n
;
1156 reply
->data_in
.data_in_val
= buf
;
1157 reply
->error
= NDMP_NO_ERR
;
1166 * Check the tape read mode is valid
1174 case NDMP_TAPE_READ_MODE
:
1175 case NDMP_TAPE_WRITE_MODE
:
1176 case NDMP_TAPE_RAW1_MODE
:
1177 case NDMP_TAPE_RAW2_MODE
:
1191 * Generic function for opening the tape for all versions
1194 * connection (input) - connection handle.
1195 * devname (input) - tape device name to open.
1196 * ndmpmode (input) - mode of opening (read, write, raw)
1202 common_tape_open(ndmp_connection_t
*connection
, char *devname
, int ndmpmode
)
1204 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
1205 char adptnm
[SCSI_MAX_NAME
];
1214 if (session
->ns_tape
.td_fd
!= -1 || session
->ns_scsi
.sd_is_open
!= -1) {
1216 "Connection already has a tape or scsi device open");
1217 err
= NDMP_DEVICE_OPENED_ERR
;
1218 } else if (!validmode(ndmpmode
))
1219 err
= NDMP_ILLEGAL_ARGS_ERR
;
1220 if ((sa
= scsi_get_adapter(0)) != NULL
) {
1221 NDMP_LOG(LOG_DEBUG
, "Adapter device opened: %s", devname
);
1222 (void) strlcpy(adptnm
, devname
, SCSI_MAX_NAME
-2);
1223 adptnm
[SCSI_MAX_NAME
-1] = '\0';
1227 scsi_find_sid_lun(sa
, devname
, &sid
, &lun
);
1228 if (ndmp_open_list_find(devname
, sid
, lun
) == 0 &&
1229 (devid
= open(devname
, O_RDWR
| O_NDELAY
)) < 0) {
1231 "Failed to open device %s: %m.", devname
);
1232 err
= NDMP_NO_DEVICE_ERR
;
1234 (void) close(devid
);
1237 NDMP_LOG(LOG_ERR
, "%s: No such tape device.", devname
);
1238 err
= NDMP_NO_DEVICE_ERR
;
1241 if (err
!= NDMP_NO_ERR
) {
1242 tape_open_send_reply(connection
, err
);
1247 * If tape is not opened in raw mode and tape is not loaded
1250 if (ndmpmode
!= NDMP_TAPE_RAW1_MODE
&&
1251 ndmpmode
!= NDMP_TAPE_RAW2_MODE
&&
1252 !is_tape_unit_ready(adptnm
, 0)) {
1253 tape_open_send_reply(connection
, NDMP_NO_TAPE_LOADED_ERR
);
1257 mode
= (ndmpmode
== NDMP_TAPE_READ_MODE
) ? O_RDONLY
: O_RDWR
;
1259 session
->ns_tape
.td_fd
= open(devname
, mode
);
1260 if (session
->ns_protocol_version
== NDMPV4
&&
1261 session
->ns_tape
.td_fd
< 0 &&
1262 ndmpmode
== NDMP_TAPE_RAW_MODE
&& errno
== EACCES
) {
1264 * V4 suggests that if the tape is open in raw mode
1265 * and could not be opened with write access, it should
1266 * be opened read only instead.
1268 ndmpmode
= NDMP_TAPE_READ_MODE
;
1269 session
->ns_tape
.td_fd
= open(devname
, O_RDONLY
);
1271 if (session
->ns_tape
.td_fd
< 0) {
1272 NDMP_LOG(LOG_ERR
, "Failed to open tape device %s: %m.",
1276 err
= NDMP_WRITE_PROTECT_ERR
;
1279 err
= NDMP_NO_DEVICE_ERR
;
1282 err
= NDMP_DEVICE_BUSY_ERR
;
1285 err
= NDMP_PERMISSION_ERR
;
1291 tape_open_send_reply(connection
, err
);
1295 switch (ndmp_open_list_add(connection
,
1296 adptnm
, sid
, lun
, session
->ns_tape
.td_fd
)) {
1301 err
= NDMP_DEVICE_BUSY_ERR
;
1304 err
= NDMP_NO_MEM_ERR
;
1309 if (err
!= NDMP_NO_ERR
) {
1310 tape_open_send_reply(connection
, err
);
1314 session
->ns_tape
.td_mode
= ndmpmode
;
1315 session
->ns_tape
.td_sid
= sid
;
1316 session
->ns_tape
.td_lun
= lun
;
1317 (void) strlcpy(session
->ns_tape
.td_adapter_name
, adptnm
, SCSI_MAX_NAME
);
1318 session
->ns_tape
.td_record_count
= 0;
1320 NDMP_LOG(LOG_DEBUG
, "Tape is opened fd: %d", session
->ns_tape
.td_fd
);
1322 tape_open_send_reply(connection
, NDMP_NO_ERR
);
1329 * Generic function for closing the tape
1332 * connection (input) - connection handle.
1338 common_tape_close(ndmp_connection_t
*connection
)
1340 ndmpd_session_t
*session
= ndmp_get_client_data(connection
);
1341 ndmp_tape_close_reply reply
;
1343 (void) ndmp_open_list_del(session
->ns_tape
.td_adapter_name
,
1344 session
->ns_tape
.td_sid
, session
->ns_tape
.td_lun
);
1345 (void) close(session
->ns_tape
.td_fd
);
1346 session
->ns_tape
.td_fd
= -1;
1347 session
->ns_tape
.td_sid
= 0;
1348 session
->ns_tape
.td_lun
= 0;
1349 (void) memset(session
->ns_tape
.td_adapter_name
, 0,
1350 sizeof (session
->ns_tape
.td_adapter_name
));
1351 session
->ns_tape
.td_record_count
= 0;
1353 reply
.error
= NDMP_NO_ERR
;
1354 ndmp_send_reply(connection
, (void *) &reply
,
1355 "sending tape_close reply");
1361 * Will try to open the tape with the given flags and
1362 * path using the given retries and delay intervals
1365 tape_open(char *path
, int flags
)
1370 while ((fd
= open(path
, flags
)) == -1 &&
1371 i
++ < ndmp_tape_open_retries
) {
1374 (void) usleep(ndmp_tape_open_delay
);