1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 /*
6 * BSD 3 Clause License
7 *
8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
41
42 #include <sys/param.h>
43 #include <syslog.h>
44 #include <fcntl.h>
45 #include <sys/mtio.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include "ndmpd_common.h"
51 #include "ndmpd.h"
52
53 static void tape_open_send_reply(ndmp_connection_t *connection, int err);
54 static void unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
55 ndmp_tape_read_reply *reply);
56 static boolean_t validmode(int mode);
57 static void common_tape_open(ndmp_connection_t *connection, char *devname,
58 int ndmpmode);
59 static void common_tape_close(ndmp_connection_t *connection);
60
61 /*
62 * Configurable delay & time when the tape is
63 * busy during opening the tape.
64 */
65 int ndmp_tape_open_retries = 5;
66 int ndmp_tape_open_delay = 1000;
67
68 /*
69 * A few words about EOT (end-of-tape) and EOM handling on tapes with SVR4
70 * semantic:
71 *
72 * We adhere to terminology as used in st driver. EOT means end of recorded
73 * data on a tape. This is different from EOM (somewhere referred to as LEOT)
74 * which is the end of tape medium. EOT is meaningful only for reads while EOM
75 * is meaningful only for writes. It's not possible to read after EOT (fails
76 * with EIO), but it's possible to write data after EOM. EOM returned by st
77 * driver on modern tape drives is just indication that the physical end of
78 * tape medium is nearing and that writer should write just the necessary
79 * minimum and stop writing. When physical end of tape is reached all writes
80 * return EIO. If EOM is crossed during read operation then st driver doesn't
81 * bother to report it to client and that's alright because reads don't care
82 * where medium physically ends but they care about meaningful data recorded on
83 * the tape and as long as there are such data reads should continue to work.
84 *
85 * When reading EOT is signalled by st driver by two empty consecutive reads
86 * (with FSF done between them). When writing EOM is signalled by empty write
87 * (a write which writes zero bytes). Following writes succeed until physical
88 * end of tape is reached in which case EIO is returned.
89 */
90
91 /*
92 * ************************************************************************
93 * NDMP V2 HANDLERS
94 * ************************************************************************
95 */
96
97 /*
98 * ndmpd_tape_open_v2
99 *
100 * This handler opens the specified tape device.
101 *
102 * Parameters:
103 * connection (input) - connection handle.
104 * body (input) - request message body.
105 *
106 * Returns:
107 * void
108 */
109 void
110 ndmpd_tape_open_v2(ndmp_connection_t *connection, void *body)
111 {
112 ndmp_tape_open_request_v2 *request = (ndmp_tape_open_request_v2 *) body;
113 ndmpd_session_t *session = ndmp_get_client_data(connection);
114 char adptnm[SCSI_MAX_NAME];
115 int mode;
116 int sid, lun;
117 int err;
118 scsi_adapter_t *sa;
119 int devid = -1;
120
121 err = NDMP_NO_ERR;
122
123 if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
124 syslog(LOG_INFO,
125 "Connection already has a tape or scsi device open");
126 err = NDMP_DEVICE_OPENED_ERR;
127 } else if (request->mode != NDMP_TAPE_READ_MODE &&
128 request->mode != NDMP_TAPE_WRITE_MODE &&
129 request->mode != NDMP_TAPE_RAW1_MODE) {
130 err = NDMP_ILLEGAL_ARGS_ERR;
131 }
132
133 if ((sa = scsi_get_adapter(0)) != NULL) {
134 (void) strlcpy(adptnm, request->device.name, SCSI_MAX_NAME-2);
135 adptnm[SCSI_MAX_NAME-1] = '\0';
136 sid = lun = -1;
137 }
138 /* try to get the scsi id etc.... */
139 if (sa) {
140 scsi_find_sid_lun(sa, request->device.name, &sid, &lun);
141 if (ndmp_open_list_find(request->device.name, sid, lun) == 0 &&
142 (devid = tape_open(request->device.name,
143 O_RDWR | O_NDELAY)) < 0) {
144 syslog(LOG_ERR, "Failed to open device %s: %m.",
145 request->device.name);
146 err = NDMP_NO_DEVICE_ERR;
147 }
148 else
149 (void) close(devid);
150 } else {
151 syslog(LOG_ERR, "%s: No such tape device.",
152 request->device.name);
153 err = NDMP_NO_DEVICE_ERR;
154 }
155 if (err != NDMP_NO_ERR) {
156 tape_open_send_reply(connection, err);
157 return;
158 }
159
160 switch (ndmp_open_list_add(connection, adptnm, sid, lun, devid)) {
161 case 0:
162 err = NDMP_NO_ERR;
163 break;
164 case EBUSY:
165 err = NDMP_DEVICE_BUSY_ERR;
166 break;
167 case ENOMEM:
168 err = NDMP_NO_MEM_ERR;
169 break;
170 default:
171 err = NDMP_IO_ERR;
172 }
173 if (err != NDMP_NO_ERR) {
174 tape_open_send_reply(connection, err);
175 return;
176 }
177
178 /*
179 * According to Connectathon 2001, the 0x7fffffff is a secret
180 * code between "Workstartion Solutions" and * net_app.
181 * If mode is set to this value, tape_open() won't fail if
182 * the tape device is not ready.
183 */
184 if (request->mode != NDMP_TAPE_RAW1_MODE &&
185 !is_tape_unit_ready(adptnm, 0)) {
186 (void) ndmp_open_list_del(adptnm, sid, lun);
187 tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
188 return;
189 }
190
191 mode = (request->mode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
192 mode |= O_NDELAY;
193 if ((session->ns_tape.td_fd = open(request->device.name, mode)) < 0) {
194 syslog(LOG_ERR, "Failed to open tape device %s: %m.",
195 request->device.name);
196 switch (errno) {
197 case EACCES:
198 err = NDMP_WRITE_PROTECT_ERR;
199 break;
200 case ENXIO:
201 case ENOENT:
202 err = NDMP_NO_DEVICE_ERR;
203 break;
204 case EBUSY:
205 err = NDMP_DEVICE_BUSY_ERR;
206 break;
207 default:
208 err = NDMP_IO_ERR;
209 }
210
211 (void) ndmp_open_list_del(adptnm, sid, lun);
212 tape_open_send_reply(connection, err);
213 return;
214 }
215
216 session->ns_tape.td_mode = request->mode;
217 session->ns_tape.td_sid = sid;
218 session->ns_tape.td_lun = lun;
219 (void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
220 session->ns_tape.td_record_count = 0;
221
222 tape_open_send_reply(connection, NDMP_NO_ERR);
223 }
224
225
226 /*
227 * ndmpd_tape_close_v2
228 *
229 * This handler closes the currently open tape device.
230 *
231 * Parameters:
232 * connection (input) - connection handle.
233 * body (input) - request message body.
234 *
235 * Returns:
236 * void
237 */
238 /*ARGSUSED*/
239 void
240 ndmpd_tape_close_v2(ndmp_connection_t *connection, void *body)
241 {
242 ndmp_tape_close_reply reply;
243 ndmpd_session_t *session = ndmp_get_client_data(connection);
244
245 if (session->ns_tape.td_fd == -1) {
246 syslog(LOG_ERR, "Tape device is not open.");
247 reply.error = NDMP_DEV_NOT_OPEN_ERR;
248 ndmp_send_reply(connection, (void *) &reply,
249 "sending tape_close reply");
250 return;
251 }
252 common_tape_close(connection);
253
254 }
255
256 /*
257 * ndmpd_tape_get_state_v2
258 *
259 * This handler handles the tape_get_state request.
260 * Status information for the currently open tape device is returned.
261 *
262 * Parameters:
263 * connection (input) - connection handle.
264 * body (input) - request message body.
265 *
266 * Returns:
267 * void
268 */
269 /*ARGSUSED*/
270 void
271 ndmpd_tape_get_state_v2(ndmp_connection_t *connection, void *body)
272
273 {
274 ndmp_tape_get_state_reply_v2 reply;
275 ndmpd_session_t *session = ndmp_get_client_data(connection);
276 struct mtget mtstatus;
277 struct mtdrivetype_request dtpr;
278 struct mtdrivetype dtp;
279
280 if (session->ns_tape.td_fd == -1) {
281 syslog(LOG_ERR, "Tape device is not open.");
282 reply.error = NDMP_DEV_NOT_OPEN_ERR;
283 ndmp_send_reply(connection, (void *) &reply,
284 "sending tape_get_state reply");
285 return;
286 }
287
288 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) < 0) {
289 syslog(LOG_ERR, "Failed to get status from tape: %m.");
290 reply.error = NDMP_IO_ERR;
291 ndmp_send_reply(connection, (void *)&reply,
292 "sending tape_get_state reply");
293 return;
294 }
295
296 dtpr.size = sizeof (struct mtdrivetype);
297 dtpr.mtdtp = &dtp;
298 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
299 syslog(LOG_ERR,
300 "Failed to get drive type information from tape: %m.");
301 reply.error = NDMP_IO_ERR;
302 ndmp_send_reply(connection, (void *)&reply,
303 "sending tape_get_state reply");
304 return;
305 }
306
307 reply.flags = 0;
308
309 reply.file_num = mtstatus.mt_fileno;
310 reply.soft_errors = 0;
311 reply.block_size = dtp.bsize;
312 if (dtp.bsize == 0)
313 reply.blockno = mtstatus.mt_blkno;
314 else
315 reply.blockno = mtstatus.mt_blkno *
316 (session->ns_mover.md_record_size / dtp.bsize);
317
318 reply.soft_errors = 0;
319 reply.total_space = long_long_to_quad(0); /* not supported */
320 reply.space_remain = long_long_to_quad(0); /* not supported */
321
322 reply.error = NDMP_NO_ERR;
323 ndmp_send_reply(connection, (void *) &reply,
324 "sending tape_get_state reply");
325 }
326
327
328 /*
329 * ndmpd_tape_mtio_v2
330 *
331 * This handler handles tape_mtio requests.
332 *
333 * Parameters:
334 * connection (input) - connection handle.
335 * body (input) - request message body.
336 *
337 * Returns:
338 * void
339 */
340 void
341 ndmpd_tape_mtio_v2(ndmp_connection_t *connection, void *body)
342 {
343 ndmp_tape_mtio_request *request = (ndmp_tape_mtio_request *) body;
344 ndmp_tape_mtio_reply reply;
345 ndmpd_session_t *session = ndmp_get_client_data(connection);
346
347 struct mtop tapeop;
348 struct mtget mtstatus;
349 int retry = 0;
350 int rc;
351
352 reply.resid_count = 0;
353
354 if (session->ns_tape.td_fd == -1) {
355 syslog(LOG_ERR, "Tape device is not open.");
356 reply.error = NDMP_DEV_NOT_OPEN_ERR;
357 ndmp_send_reply(connection, (void *) &reply,
358 "sending tape_mtio reply");
359 return;
360 }
361
362 reply.error = NDMP_NO_ERR;
363 switch (request->tape_op) {
364 case NDMP_MTIO_FSF:
365 tapeop.mt_op = MTFSF;
366 break;
367 case NDMP_MTIO_BSF:
368 tapeop.mt_op = MTBSF;
369 break;
370 case NDMP_MTIO_FSR:
371 tapeop.mt_op = MTFSR;
372 break;
373 case NDMP_MTIO_BSR:
374 tapeop.mt_op = MTBSR;
375 break;
376 case NDMP_MTIO_REW:
377 tapeop.mt_op = MTREW;
378 break;
379 case NDMP_MTIO_EOF:
380 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE)
381 reply.error = NDMP_PERMISSION_ERR;
382 tapeop.mt_op = MTWEOF;
383 break;
384 case NDMP_MTIO_OFF:
385 tapeop.mt_op = MTOFFL;
386 break;
387
388 case NDMP_MTIO_TUR: /* test unit ready */
389
390 if (is_tape_unit_ready(session->ns_tape.td_adapter_name,
391 session->ns_tape.td_fd) == 0)
392 /* tape not ready ? */
393 reply.error = NDMP_NO_TAPE_LOADED_ERR;
394 break;
395
396 default:
397 reply.error = NDMP_ILLEGAL_ARGS_ERR;
398 }
399
400 if (reply.error == NDMP_NO_ERR && request->tape_op != NDMP_MTIO_TUR) {
401 tapeop.mt_count = request->count;
402
403 do {
404 NS_UPD(twait, trun);
405 errno = 0;
406 rc = ioctl(session->ns_tape.td_fd, MTIOCTOP, &tapeop);
407 NS_UPD(trun, twait);
408 } while (rc < 0 && errno == EIO &&
409 retry++ < 5);
410
411 /*
412 * Ignore I/O errors since these usually are the result of
413 * attempting to position past the beginning or end of the tape.
414 * The residual count will be returned and can be used to
415 * determine that the call was not completely successful.
416 */
417 if (rc < 0) {
418 syslog(LOG_ERR,
419 "Failed to send command to tape: %m.");
420
421 /* MTWEOF doesnt have residual count */
422 if (tapeop.mt_op == MTWEOF)
423 reply.error = NDMP_IO_ERR;
424 else
425 reply.error = NDMP_NO_ERR;
426 reply.resid_count = tapeop.mt_count;
427 ndmp_send_reply(connection, (void *)&reply,
428 "sending tape_mtio reply");
429 return;
430 }
431
432 if (request->tape_op != NDMP_MTIO_REW &&
433 request->tape_op != NDMP_MTIO_OFF) {
434 if (ioctl(session->ns_tape.td_fd, MTIOCGET,
435 &mtstatus) < 0) {
436 syslog(LOG_ERR,
437 "Failed to send command to tape: %m.");
438 reply.error = NDMP_IO_ERR;
439 ndmp_send_reply(connection, (void *)&reply,
440 "sending tape_mtio reply");
441
442 return;
443 }
444
445 reply.resid_count = labs(mtstatus.mt_resid);
446 }
447 }
448
449 ndmp_send_reply(connection, (void *) &reply, "sending tape_mtio reply");
450 }
451
452
453 /*
454 * ndmpd_tape_read_v2
455 *
456 * This handler handles tape_read requests.
457 * This interface is a non-buffered interface. Each read request
458 * maps directly to a read to the tape device. It is the responsibility
459 * of the NDMP client to issue read requests with a length that is at
460 * least as large as the record size used write the tape. The tape driver
461 * always reads a full record. Data is discarded if the read request is
462 * smaller than the record size.
463 * It is the responsibility of the NDMP client to ensure that the
464 * length is a multiple of the tape block size if the tape device
465 * is in fixed block mode.
466 *
467 * Parameters:
468 * connection (input) - connection handle.
469 * body (input) - request message body.
470 *
471 * Returns:
472 * void
473 */
474 void
475 ndmpd_tape_read_v2(ndmp_connection_t *connection, void *body)
476 {
477 ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
478 ndmp_tape_read_reply reply;
479 ndmpd_session_t *session = ndmp_get_client_data(connection);
480 char *buf;
481
482 reply.data_in.data_in_len = 0;
483
484 if (session->ns_tape.td_fd == -1) {
485 syslog(LOG_ERR, "Tape device is not open.");
486 reply.error = NDMP_DEV_NOT_OPEN_ERR;
487 ndmp_send_reply(connection, (void *)&reply,
488 "sending tape_read reply");
489 return;
490 }
491 if (request->count == 0) {
492 reply.error = NDMP_NO_ERR;
493 ndmp_send_reply(connection, (void *)&reply,
494 "sending tape_read reply");
495 return;
496 }
497 if ((buf = ndmp_malloc(request->count)) == 0) {
498 reply.error = NDMP_NO_MEM_ERR;
499 ndmp_send_reply(connection, (void *)&reply,
500 "sending tape_read reply");
501 return;
502 }
503
504 unbuffered_read(session, buf, request->count, &reply);
505
506 ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
507 (void) free(buf);
508 }
509
510
511 /*
512 * ndmpd_tape_execute_cdb_v2
513 *
514 * This handler handles tape_execute_cdb requests.
515 *
516 * Parameters:
517 * connection (input) - connection handle.
518 * body (input) - request message body.
519 *
520 * Returns:
521 * void
522 */
523 void
524 ndmpd_tape_execute_cdb_v2(ndmp_connection_t *connection, void *body)
525 {
526 ndmp_tape_execute_cdb_request *request;
527 ndmp_tape_execute_cdb_reply reply;
528 ndmpd_session_t *session = ndmp_get_client_data(connection);
529
530 request = (ndmp_tape_execute_cdb_request *) body;
531
532 if (session->ns_tape.td_fd == -1) {
533 (void) memset((void *) &reply, 0, sizeof (reply));
534
535 syslog(LOG_ERR, "Tape device is not open.");
536 reply.error = NDMP_DEV_NOT_OPEN_ERR;
537 ndmp_send_reply(connection, (void *) &reply,
538 "sending tape_execute_cdb reply");
539 } else {
540 ndmp_execute_cdb(session, session->ns_tape.td_adapter_name,
541 session->ns_tape.td_sid, session->ns_tape.td_lun,
542 (ndmp_execute_cdb_request *)request);
543 }
544 }
545
546
547 /*
548 * ************************************************************************
549 * NDMP V3 HANDLERS
550 * ************************************************************************
551 */
552
553 /*
554 * ndmpd_tape_open_v3
555 *
556 * This handler opens the specified tape device.
557 *
558 * Parameters:
559 * connection (input) - connection handle.
560 * body (input) - request message body.
561 *
562 * Returns:
563 * void
564 */
565 void
566 ndmpd_tape_open_v3(ndmp_connection_t *connection, void *body)
567 {
568 ndmp_tape_open_request_v3 *request = (ndmp_tape_open_request_v3 *)body;
569
570 common_tape_open(connection, request->device, request->mode);
571 }
572
573
574 /*
575 * ndmpd_tape_get_state_v3
576 *
577 * This handler handles the ndmp_tape_get_state_request.
578 * Status information for the currently open tape device is returned.
579 *
580 * Parameters:
581 * connection (input) - connection handle.
582 * body (input) - request message body.
583 *
584 * Returns:
585 * void
586 */
587 /*ARGSUSED*/
588 void
589 ndmpd_tape_get_state_v3(ndmp_connection_t *connection, void *body)
590 {
591 ndmp_tape_get_state_reply_v3 reply;
592 ndmpd_session_t *session = ndmp_get_client_data(connection);
593 struct mtdrivetype_request dtpr;
594 struct mtdrivetype dtp;
595 struct mtget mtstatus;
596
597 if (session->ns_tape.td_fd == -1) {
598 syslog(LOG_ERR, "Tape device is not open.");
599 reply.error = NDMP_DEV_NOT_OPEN_ERR;
600 ndmp_send_reply(connection, (void *) &reply,
601 "sending tape_get_state reply");
602 return;
603 }
604
605 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
606 syslog(LOG_ERR, "Failed to get status from tape: %m.");
607
608 reply.error = NDMP_IO_ERR;
609 ndmp_send_reply(connection, (void *)&reply,
610 "sending tape_get_state reply");
611 return;
612 }
613
614 dtpr.size = sizeof (struct mtdrivetype);
615 dtpr.mtdtp = &dtp;
616 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
617 syslog(LOG_ERR,
618 "Failed to get drive type information from tape: %m.");
619
620 reply.error = NDMP_IO_ERR;
621 ndmp_send_reply(connection, (void *)&reply,
622 "sending tape_get_state reply");
623 return;
624 }
625
626 reply.flags = 0;
627
628 reply.file_num = mtstatus.mt_fileno;
629 reply.soft_errors = 0;
630 reply.block_size = dtp.bsize;
631 if (dtp.bsize == 0)
632 reply.blockno = mtstatus.mt_blkno;
633 else
634 reply.blockno = mtstatus.mt_blkno *
635 (session->ns_mover.md_record_size / dtp.bsize);
636 reply.total_space = long_long_to_quad(0); /* not supported */
637 reply.space_remain = long_long_to_quad(0); /* not supported */
638 reply.partition = 0; /* not supported */
639
640 reply.soft_errors = 0;
641 reply.total_space = long_long_to_quad(0LL);
642 reply.space_remain = long_long_to_quad(0LL);
643
644 reply.invalid = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
645 NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
646 NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
647 NDMP_TAPE_STATE_PARTITION_INVALID;
648
649 reply.error = NDMP_NO_ERR;
650 ndmp_send_reply(connection, (void *) &reply,
651 "sending tape_get_state reply");
652 }
653
654 /*
655 * tape_is_at_bot
656 *
657 * Returns 1 if tape is at BOT, 0 on error or not at BOT.
658 *
659 */
660 int
661 tape_is_at_bot(ndmpd_session_t *session)
662 {
663 struct mtget mtstatus;
664
665 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == 0 &&
666 mtstatus.mt_fileno == 0 && mtstatus.mt_blkno == 0)
667 return (1);
668
669 return (0);
670 }
671
672 /*
673 * If we are at the beginning of a file (block # is zero) and read returns
674 * zero bytes then this has to be end of recorded data on the tape. Repeated
675 * reads at EOT return EIO. In both cases (zero read and EIO read) this
676 * function should be used to test if we are at EOT.
677 *
678 * Returns 1 if tape is at BOF, 0 on error or not at BOF.
679 */
680 int
681 tape_is_at_bof(ndmpd_session_t *session)
682 {
683 struct mtget mtstatus;
684
685 if ((ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == 0) &&
686 (mtstatus.mt_fileno > 0) && (mtstatus.mt_blkno == 0))
687 return (1);
688
689 return (0);
690 }
691
692 /*
693 * Skips forward over a file mark and then back before the file mark. Why is
694 * this needed? There are two reasons for it:
695 *
696 * 1) Because NDMPv4 spec requires that when EOF is encountered, the tape
697 * position should remain on BOT side of the file mark. When st driver reaches
698 * end of file get-position mtioctl reports position before file mark, however
699 * the file mark has already been read and the real position is thus after the
700 * file mark (real position as reported for example by uscsi commands). Thus we
701 * need to do FSF, which does nothing but only updates file & block counter in
702 * st driver and then BSF, which sets the position before the file mark. Thus
703 * current position as reported by scsi and mtioctl will be in sync.
704 *
705 * 2) st driver returns EIO for repeated reads at EOF while according to NDMP
706 * spec we should continue to return zero bytes until FSF is done. By skipping
707 * forward and backward, st driver will return zero bytes for the next read
708 * again and we don't need to specifically handle this case.
709 */
710 void
711 fm_dance(ndmpd_session_t *session)
712 {
713 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
714 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
715 }
716
717 /*
718 * ndmpd_tape_write_v3
719 *
720 * This handler handles tape_write requests. This interface is a non-buffered
721 * interface. Each write request maps directly to a write to the tape device.
722 * It is the responsibility of the NDMP client to pad the data to the desired
723 * record size. It is the responsibility of the NDMP client to ensure that the
724 * length is a multiple of the tape block size if the tape device is in fixed
725 * block mode.
726 *
727 * A logical end of tape will return number of bytes written less than
728 * requested, and one more request to write will give 0 and NDMP_EOM_ERR,
729 * followed by NDMP_NO_ERR until NDMP_IO_ERR when physical end of tape is
730 * reached.
731 *
732 * Parameters:
733 * connection (input) - connection handle.
734 * body (input) - request message body.
735 */
736 void ndmpd_tape_write_v3(ndmp_connection_t *connection, void *body) {
737 ndmp_tape_write_request *request = (ndmp_tape_write_request *)body;
738 ndmp_tape_write_reply reply; ndmpd_session_t *session =
739 ndmp_get_client_data(connection); ssize_t n;
740
741 reply.count = 0;
742
743 if (session->ns_tape.td_fd == -1) {
744 syslog(LOG_ERR, "Tape device is not open.");
745 reply.error = NDMP_DEV_NOT_OPEN_ERR;
746 ndmp_send_reply(connection, (void *) &reply,
747 "sending tape_write reply");
748 return;
749 }
750 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
751 syslog(LOG_INFO, "Tape device opened in read-only mode");
752 reply.error = NDMP_PERMISSION_ERR;
753 ndmp_send_reply(connection, (void *) &reply,
754 "sending tape_write reply");
755 return;
756 }
757 if (request->data_out.data_out_len == 0) {
758 reply.error = NDMP_NO_ERR;
759 ndmp_send_reply(connection, (void *) &reply,
760 "sending tape_write reply");
761 return;
762 }
763
764 /*
765 * V4 suggests that this should not be accepted
766 * when mover is in listen or active state
767 */
768 if (session->ns_protocol_version == NDMPV4 &&
769 (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
770 session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
771
772 reply.error = NDMP_DEVICE_BUSY_ERR;
773 ndmp_send_reply(connection, (void *) &reply,
774 "sending tape_write reply");
775 return;
776 }
777
778 n = write(session->ns_tape.td_fd, request->data_out.data_out_val,
779 request->data_out.data_out_len);
780
781 if (n < 0) {
782 syslog(LOG_ERR, "Tape write error: %m.");
783 reply.error = NDMP_IO_ERR;
784 } else if (n == 0) {
785 syslog(LOG_INFO, "EOM detected");
786 reply.error = NDMP_EOM_ERR;
787 } else {
788 NS_ADD(wtape, n);
789 reply.count = n;
790 reply.error = NDMP_NO_ERR;
791
792 if (n < request->data_out.data_out_len)
793 syslog(LOG_DEBUG,
794 "EOM is coming (partial write of %d bytes)", n);
795 }
796
797 ndmp_send_reply(connection, (void *) &reply,
798 "sending tape_write reply");
799 }
800
801 /*
802 * ndmpd_tape_read_v3
803 *
804 * This handler handles tape_read requests. This interface is a non-buffered
805 * interface. Each read request maps directly to a read to the tape device. It
806 * is the responsibility of the NDMP client to issue read requests with a
807 * length that is at least as large as the record size used write the tape. The
808 * tape driver always reads a full record. Data is discarded if the read
809 * request is smaller than the record size. It is the responsibility of the
810 * NDMP client to ensure that the length is a multiple of the tape block size
811 * if the tape device is in fixed block mode.
812 *
813 * A logical end of tape will return less bytes than requested, and one more
814 * request to read will give 0 and NDMP_EOM_ERR. All subsequent reads will
815 * return NDMP_EOM_ERR until the tape is repositioned.
816 *
817 * Parameters:
818 * connection (input) - connection handle.
819 * body (input) - request message body.
820 */
821 void
822 ndmpd_tape_read_v3(ndmp_connection_t *connection, void *body)
823 {
824 ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
825 ndmp_tape_read_reply reply;
826 ndmpd_session_t *session = ndmp_get_client_data(connection);
827 char *buf;
828 int n;
829
830 reply.data_in.data_in_len = 0;
831
832 if (session->ns_tape.td_fd == -1) {
833 syslog(LOG_ERR, "Tape device is not open.");
834 reply.error = NDMP_DEV_NOT_OPEN_ERR;
835 ndmp_send_reply(connection, (void *) &reply,
836 "sending tape_read reply");
837 return;
838 }
839 if (request->count == 0) {
840 reply.error = NDMP_NO_ERR;
841 ndmp_send_reply(connection, (void *) &reply,
842 "sending tape_read reply");
843 return;
844 }
845
846 /*
847 * V4 suggests that this should not be accepted
848 * when mover is in listen or active state
849 */
850 if (session->ns_protocol_version == NDMPV4 &&
851 (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
852 session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
853
854 reply.error = NDMP_DEVICE_BUSY_ERR;
855 ndmp_send_reply(connection, (void *) &reply,
856 "sending tape_read reply");
857 return;
858 }
859
860 if ((buf = ndmp_malloc(request->count)) == NULL) {
861 reply.error = NDMP_NO_MEM_ERR;
862 ndmp_send_reply(connection, (void *) &reply,
863 "sending tape_read reply");
864 return;
865 }
866
867 n = read(session->ns_tape.td_fd, buf, request->count);
868 if (n < 0) {
869 /*
870 * This fix is for Symantec during importing
871 * of spanned data between the tapes.
872 */
873 if (errno == ENOSPC) {
874 reply.error = NDMP_EOF_ERR;
875 }
876 /*
877 * If at beginning of file and read fails with EIO, then it's
878 * repeated attempt to read at EOT.
879 */
880 else if (errno == EIO && tape_is_at_bof(session)) {
881 syslog(LOG_DEBUG, "Repeated read at EOT");
882 reply.error = NDMP_EOM_ERR;
883 }
884 /*
885 * According to NDMPv4 spec preferred error code when
886 * trying to read from blank tape is NDMP_EOM_ERR.
887 */
888 else if (errno == EIO && tape_is_at_bot(session)) {
889 syslog(LOG_ERR, "Blank tape detected, returning EOM");
890 reply.error = NDMP_EOM_ERR;
891 } else {
892 syslog(LOG_ERR, "Tape read error: %m.");
893 reply.error = NDMP_IO_ERR;
894 }
895 } else if (n == 0) {
896 if (tape_is_at_bof(session)) {
897 syslog(LOG_DEBUG, "EOT detected");
898 reply.error = NDMP_EOM_ERR;
899 } else {
900 /* reposition the tape to BOT side of FM */
901 fm_dance(session);
902 syslog(LOG_DEBUG, "EOF detected");
903 reply.error = NDMP_EOF_ERR;
904 }
905 } else {
906 session->ns_tape.td_pos += n;
907 reply.data_in.data_in_len = n;
908 reply.data_in.data_in_val = buf;
909 reply.error = NDMP_NO_ERR;
910 NS_ADD(rtape, n);
911 }
912
913 ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
914 free(buf);
915 }
916
917
918 /*
919 * ************************************************************************
920 * NDMP V4 HANDLERS
921 * ************************************************************************
922 */
923
924 /*
925 * ndmpd_tape_get_state_v4
926 *
927 * This handler handles the ndmp_tape_get_state_request.
928 * Status information for the currently open tape device is returned.
929 *
930 * Parameters:
931 * connection (input) - connection handle.
932 * body (input) - request message body.
933 *
934 * Returns:
935 * void
936 */
937 /*ARGSUSED*/
938 void
939 ndmpd_tape_get_state_v4(ndmp_connection_t *connection, void *body)
940 {
941 ndmp_tape_get_state_reply_v4 reply;
942 ndmpd_session_t *session = ndmp_get_client_data(connection);
943 struct mtget mtstatus;
944 struct mtdrivetype_request dtpr;
945 struct mtdrivetype dtp;
946
947 if (session->ns_tape.td_fd == -1) {
948 syslog(LOG_ERR, "Tape device is not open.");
949 reply.error = NDMP_DEV_NOT_OPEN_ERR;
950 ndmp_send_reply(connection, (void *) &reply,
951 "sending tape_get_state reply");
952 return;
953 }
954
955 /*
956 * Need code to detect NDMP_TAPE_STATE_NOREWIND
957 */
958
959 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
960 syslog(LOG_ERR,
961 "Failed to get status information from tape: %m.");
962
963 reply.error = NDMP_IO_ERR;
964 ndmp_send_reply(connection, (void *)&reply,
965 "sending tape_get_state reply");
966 return;
967 }
968
969 dtpr.size = sizeof (struct mtdrivetype);
970 dtpr.mtdtp = &dtp;
971 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
972 syslog(LOG_ERR,
973 "Failed to get drive type information from tape: %m.");
974
975 reply.error = NDMP_IO_ERR;
976 ndmp_send_reply(connection, (void *)&reply,
977 "sending tape_get_state reply");
978 return;
979 }
980
981 reply.flags = NDMP_TAPE_NOREWIND;
982
983 reply.file_num = mtstatus.mt_fileno;
984 reply.soft_errors = 0;
985 reply.block_size = dtp.bsize;
986
987 if (dtp.bsize == 0)
988 reply.blockno = mtstatus.mt_blkno;
989 else
990 reply.blockno = mtstatus.mt_blkno /
991 (session->ns_mover.md_record_size / dtp.bsize);
992
993 reply.total_space = long_long_to_quad(0LL); /* not supported */
994 reply.space_remain = long_long_to_quad(0LL); /* not supported */
995 reply.soft_errors = 0;
996 reply.unsupported = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
997 NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
998 NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
999 NDMP_TAPE_STATE_PARTITION_INVALID;
1000
1001 reply.error = NDMP_NO_ERR;
1002 ndmp_send_reply(connection, (void *) &reply,
1003 "sending tape_get_state reply");
1004 }
1005 /*
1006 * ndmpd_tape_close_v4
1007 *
1008 * This handler (v4) closes the currently open tape device.
1009 *
1010 * Parameters:
1011 * connection (input) - connection handle.
1012 * body (input) - request message body.
1013 *
1014 * Returns:
1015 * void
1016 */
1017 /*ARGSUSED*/
1018 void
1019 ndmpd_tape_close_v4(ndmp_connection_t *connection, void *body)
1020 {
1021 ndmp_tape_close_reply reply;
1022 ndmpd_session_t *session = ndmp_get_client_data(connection);
1023
1024 if (session->ns_tape.td_fd == -1) {
1025 syslog(LOG_ERR, "Tape device is not open.");
1026 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1027 ndmp_send_reply(connection, (void *) &reply,
1028 "sending tape_close reply");
1029 return;
1030 }
1031
1032 /*
1033 * V4 suggests that this should not be accepted
1034 * when mover is in listen or active state
1035 */
1036 if (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
1037 session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
1038
1039 reply.error = NDMP_DEVICE_BUSY_ERR;
1040 ndmp_send_reply(connection, (void *) &reply,
1041 "sending tape_close reply");
1042 return;
1043 }
1044
1045 common_tape_close(connection);
1046 }
1047
1048
1049 /*
1050 * ************************************************************************
1051 * LOCALS
1052 * ************************************************************************
1053 */
1054 /*
1055 * tape_open_send_reply
1056 *
1057 * Send a reply to the tape open message
1058 *
1059 * Parameters:
1060 * connection (input) - connection handle.
1061 * err (input) - NDMP error
1062 *
1063 * Returns:
1064 * void
1065 */
1066 static void
1067 tape_open_send_reply(ndmp_connection_t *connection, int err)
1068 {
1069 ndmp_tape_open_reply reply;
1070
1071 reply.error = err;
1072 ndmp_send_reply(connection, (void *) &reply, "sending tape_open reply");
1073 }
1074
1075 /*
1076 * unbuffered_read
1077 *
1078 * Perform tape read without read-ahead
1079 *
1080 * Parameters:
1081 * session (input) - session handle
1082 * bp (output) - read buffer
1083 * wanted (input) - number of bytes wanted
1084 * reply (output) - tape read reply message
1085 *
1086 * Returns:
1087 * void
1088 */
1089 static void
1090 unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
1091 ndmp_tape_read_reply *reply)
1092 {
1093 int n, len;
1094
1095 n = read(session->ns_tape.td_fd, buf, wanted);
1096 if (n < 0) {
1097 /*
1098 * This fix is for Symantec during importing
1099 * of spanned data between the tapes.
1100 */
1101 if (errno == ENOSPC) {
1102 reply->error = NDMP_EOF_ERR;
1103 } else {
1104 syslog(LOG_ERR, "Tape read error: %m.");
1105 reply->error = NDMP_IO_ERR;
1106 }
1107 } else if (n == 0) {
1108 reply->error = NDMP_EOF_ERR;
1109
1110 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
1111
1112 len = strlen(NDMP_EOM_MAGIC);
1113 (void) memset(buf, 0, len);
1114 n = read(session->ns_tape.td_fd, buf, len);
1115 buf[len] = '\0';
1116
1117 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
1118
1119 if (strncmp(buf, NDMP_EOM_MAGIC, len) != 0)
1120 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
1121 } else {
1122 session->ns_tape.td_pos += n;
1123 reply->data_in.data_in_len = n;
1124 reply->data_in.data_in_val = buf;
1125 reply->error = NDMP_NO_ERR;
1126 NS_ADD(rtape, n);
1127 }
1128 }
1129
1130
1131 /*
1132 * validmode
1133 *
1134 * Check the tape read mode is valid
1135 */
1136 static boolean_t
1137 validmode(int mode)
1138 {
1139 boolean_t rv;
1140
1141 switch (mode) {
1142 case NDMP_TAPE_READ_MODE:
1143 case NDMP_TAPE_WRITE_MODE:
1144 case NDMP_TAPE_RAW1_MODE:
1145 case NDMP_TAPE_RAW2_MODE:
1146 rv = TRUE;
1147 break;
1148 default:
1149 rv = FALSE;
1150 }
1151
1152 return (rv);
1153 }
1154
1155
1156 /*
1157 * common_tape_open
1158 *
1159 * Generic function for opening the tape for all versions
1160 *
1161 * Parameters:
1162 * connection (input) - connection handle.
1163 * devname (input) - tape device name to open.
1164 * ndmpmode (input) - mode of opening (read, write, raw)
1165 *
1166 * Returns:
1167 * void
1168 */
1169 static void
1170 common_tape_open(ndmp_connection_t *connection, char *devname, int ndmpmode)
1171 {
1172 ndmpd_session_t *session = ndmp_get_client_data(connection);
1173 char adptnm[SCSI_MAX_NAME];
1174 int err;
1175 int mode;
1176 int sid, lun;
1177 scsi_adapter_t *sa;
1178 int devid = -1;
1179
1180 err = NDMP_NO_ERR;
1181
1182 if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
1183 syslog(LOG_INFO,
1184 "Connection already has a tape or scsi device open");
1185 err = NDMP_DEVICE_OPENED_ERR;
1186 } else if (!validmode(ndmpmode))
1187 err = NDMP_ILLEGAL_ARGS_ERR;
1188 if ((sa = scsi_get_adapter(0)) != NULL) {
1189 (void) strlcpy(adptnm, devname, SCSI_MAX_NAME-2);
1190 adptnm[SCSI_MAX_NAME-1] = '\0';
1191 sid = lun = -1;
1192 }
1193 if (sa) {
1194 scsi_find_sid_lun(sa, devname, &sid, &lun);
1195 if (ndmp_open_list_find(devname, sid, lun) == 0 &&
1196 (devid = open(devname, O_RDWR | O_NDELAY)) < 0) {
1197 syslog(LOG_ERR,
1198 "Failed to open device %s: %m.", devname);
1199 err = NDMP_NO_DEVICE_ERR;
1200 } else {
1201 (void) close(devid);
1202 }
1203 } else {
1204 syslog(LOG_ERR, "%s: No such tape device.", devname);
1205 err = NDMP_NO_DEVICE_ERR;
1206 }
1207
1208 if (err != NDMP_NO_ERR) {
1209 tape_open_send_reply(connection, err);
1210 return;
1211 }
1212
1213 /*
1214 * If tape is not opened in raw mode and tape is not loaded
1215 * return error.
1216 */
1217 if (ndmpmode != NDMP_TAPE_RAW1_MODE &&
1218 ndmpmode != NDMP_TAPE_RAW2_MODE &&
1219 !is_tape_unit_ready(adptnm, 0)) {
1220 tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
1221 return;
1222 }
1223
1224 mode = (ndmpmode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
1225 mode |= O_NDELAY;
1226 session->ns_tape.td_fd = open(devname, mode);
1227 if (session->ns_protocol_version == NDMPV4 &&
1228 session->ns_tape.td_fd < 0 &&
1229 ndmpmode == NDMP_TAPE_RAW_MODE && errno == EACCES) {
1230 /*
1231 * V4 suggests that if the tape is open in raw mode
1232 * and could not be opened with write access, it should
1233 * be opened read only instead.
1234 */
1235 ndmpmode = NDMP_TAPE_READ_MODE;
1236 session->ns_tape.td_fd = open(devname, O_RDONLY);
1237 }
1238 if (session->ns_tape.td_fd < 0) {
1239 syslog(LOG_ERR, "Failed to open tape device %s: %m.",
1240 devname);
1241 switch (errno) {
1242 case EACCES:
1243 err = NDMP_WRITE_PROTECT_ERR;
1244 break;
1245 case ENOENT:
1246 err = NDMP_NO_DEVICE_ERR;
1247 break;
1248 case EBUSY:
1249 err = NDMP_DEVICE_BUSY_ERR;
1250 break;
1251 case EPERM:
1252 err = NDMP_PERMISSION_ERR;
1253 break;
1254 default:
1255 err = NDMP_IO_ERR;
1256 }
1257
1258 tape_open_send_reply(connection, err);
1259 return;
1260 }
1261
1262 switch (ndmp_open_list_add(connection,
1263 adptnm, sid, lun, session->ns_tape.td_fd)) {
1264 case 0:
1265 err = NDMP_NO_ERR;
1266 break;
1267 case EBUSY:
1268 err = NDMP_DEVICE_BUSY_ERR;
1269 break;
1270 case ENOMEM:
1271 err = NDMP_NO_MEM_ERR;
1272 break;
1273 default:
1274 err = NDMP_IO_ERR;
1275 }
1276 if (err != NDMP_NO_ERR) {
1277 tape_open_send_reply(connection, err);
1278 return;
1279 }
1280
1281 session->ns_tape.td_mode = ndmpmode;
1282 session->ns_tape.td_sid = sid;
1283 session->ns_tape.td_lun = lun;
1284 (void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
1285 session->ns_tape.td_record_count = 0;
1286
1287 tape_open_send_reply(connection, NDMP_NO_ERR);
1288 }
1289
1290
1291 /*
1292 * common_tape_close
1293 *
1294 * Generic function for closing the tape
1295 *
1296 * Parameters:
1297 * connection (input) - connection handle.
1298 *
1299 * Returns:
1300 * void
1301 */
1302 static void
1303 common_tape_close(ndmp_connection_t *connection)
1304 {
1305 ndmpd_session_t *session = ndmp_get_client_data(connection);
1306 ndmp_tape_close_reply reply;
1307
1308 (void) ndmp_open_list_del(session->ns_tape.td_adapter_name,
1309 session->ns_tape.td_sid, session->ns_tape.td_lun);
1310 (void) close(session->ns_tape.td_fd);
1311 session->ns_tape.td_fd = -1;
1312 session->ns_tape.td_sid = 0;
1313 session->ns_tape.td_lun = 0;
1314 (void) memset(session->ns_tape.td_adapter_name, 0,
1315 sizeof (session->ns_tape.td_adapter_name));
1316 session->ns_tape.td_record_count = 0;
1317
1318 reply.error = NDMP_NO_ERR;
1319 ndmp_send_reply(connection, (void *) &reply,
1320 "sending tape_close reply");
1321 }
1322
1323 /*
1324 * tape_open
1325 *
1326 * Will try to open the tape with the given flags and
1327 * path using the given retries and delay intervals
1328 */
1329 int
1330 tape_open(char *path, int flags)
1331 {
1332 int fd;
1333 int i = 0;
1334
1335 while ((fd = open(path, flags)) == -1 &&
1336 i++ < ndmp_tape_open_retries) {
1337 if (errno != EBUSY)
1338 break;
1339 (void) usleep(ndmp_tape_open_delay);
1340 }
1341 return (fd);
1342 }