20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
41
42 #include <sys/param.h>
43 #include <fcntl.h>
44 #include <sys/mtio.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include "ndmpd_common.h"
50 #include "ndmpd.h"
51
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,
57 int ndmpmode);
58 static void common_tape_close(ndmp_connection_t *connection);
59
60 /*
61 * Configurable delay & time when the tape is
62 * busy during opening the tape.
98 *
99 * This handler opens the specified tape device.
100 *
101 * Parameters:
102 * connection (input) - connection handle.
103 * body (input) - request message body.
104 *
105 * Returns:
106 * void
107 */
108 void
109 ndmpd_tape_open_v2(ndmp_connection_t *connection, void *body)
110 {
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];
114 int mode;
115 int sid, lun;
116 int err;
117 scsi_adapter_t *sa;
118 int devid;
119
120 err = NDMP_NO_ERR;
121
122 if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
123 NDMP_LOG(LOG_INFO,
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;
130 }
131
132 if ((sa = scsi_get_adapter(0)) != NULL) {
133 NDMP_LOG(LOG_DEBUG,
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';
137 sid = lun = -1;
138 }
139 /* try to get the scsi id etc.... */
140 if (sa) {
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;
148 }
149 else
150 (void) close(devid);
151 } else {
152 NDMP_LOG(LOG_ERR, "%s: No such tape device.",
153 request->device.name);
154 err = NDMP_NO_DEVICE_ERR;
155 }
156 if (err != NDMP_NO_ERR) {
157 tape_open_send_reply(connection, err);
158 return;
159 }
160
161 switch (ndmp_open_list_add(connection, adptnm, sid, lun, devid)) {
162 case 0:
163 err = NDMP_NO_ERR;
164 break;
165 case EBUSY:
166 err = NDMP_DEVICE_BUSY_ERR;
167 break;
168 case ENOMEM:
169 err = NDMP_NO_MEM_ERR;
170 break;
171 default:
172 err = NDMP_IO_ERR;
175 tape_open_send_reply(connection, err);
176 return;
177 }
178
179 /*
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.
184 */
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);
189 return;
190 }
191
192 mode = (request->mode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
193 mode |= O_NDELAY;
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);
197 switch (errno) {
198 case EACCES:
199 err = NDMP_WRITE_PROTECT_ERR;
200 break;
201 case ENXIO:
202 case ENOENT:
203 err = NDMP_NO_DEVICE_ERR;
204 break;
205 case EBUSY:
206 err = NDMP_DEVICE_BUSY_ERR;
207 break;
208 default:
209 err = NDMP_IO_ERR;
210 }
211
212 (void) ndmp_open_list_del(adptnm, sid, lun);
213 tape_open_send_reply(connection, err);
214 return;
215 }
216
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;
222
223 NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
224
225 tape_open_send_reply(connection, NDMP_NO_ERR);
226 }
227
228
229 /*
230 * ndmpd_tape_close_v2
231 *
232 * This handler closes the currently open tape device.
233 *
234 * Parameters:
235 * connection (input) - connection handle.
236 * body (input) - request message body.
237 *
238 * Returns:
239 * void
240 */
241 /*ARGSUSED*/
242 void
243 ndmpd_tape_close_v2(ndmp_connection_t *connection, void *body)
244 {
245 ndmp_tape_close_reply reply;
246 ndmpd_session_t *session = ndmp_get_client_data(connection);
247
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");
253 return;
254 }
255 common_tape_close(connection);
256
257 }
258
259 /*
260 * ndmpd_tape_get_state_v2
261 *
262 * This handler handles the tape_get_state request.
263 * Status information for the currently open tape device is returned.
264 *
265 * Parameters:
266 * connection (input) - connection handle.
267 * body (input) - request message body.
268 *
269 * Returns:
270 * void
271 */
272 /*ARGSUSED*/
273 void
274 ndmpd_tape_get_state_v2(ndmp_connection_t *connection, void *body)
275
276 {
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;
282
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");
288 return;
289 }
290
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");
297 return;
298 }
299
300 dtpr.size = sizeof (struct mtdrivetype);
301 dtpr.mtdtp = &dtp;
302 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
303 NDMP_LOG(LOG_ERR,
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");
309 return;
310 }
311
312 reply.flags = 0;
313
314 reply.file_num = mtstatus.mt_fileno;
315 reply.soft_errors = 0;
316 reply.block_size = dtp.bsize;
317 if (dtp.bsize == 0)
318 reply.blockno = mtstatus.mt_blkno;
319 else
320 reply.blockno = mtstatus.mt_blkno *
321 (session->ns_mover.md_record_size / dtp.bsize);
322
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 */
326
327 NDMP_LOG(LOG_DEBUG,
328 "flags: 0x%x, file_num: %d, block_size: %d, blockno: %d",
329 reply.flags, reply.file_num, reply.block_size, reply.blockno);
330
331 reply.error = NDMP_NO_ERR;
332 ndmp_send_reply(connection, (void *) &reply,
333 "sending tape_get_state reply");
334 }
335
336
337 /*
338 * ndmpd_tape_mtio_v2
339 *
340 * This handler handles tape_mtio requests.
341 *
342 * Parameters:
343 * connection (input) - connection handle.
344 * body (input) - request message body.
345 *
346 * Returns:
347 * void
348 */
349 void
350 ndmpd_tape_mtio_v2(ndmp_connection_t *connection, void *body)
351 {
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);
355
356 struct mtop tapeop;
357 struct mtget mtstatus;
358 int retry = 0;
359 int rc;
360
361 reply.resid_count = 0;
362
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");
368 return;
369 }
370
371 reply.error = NDMP_NO_ERR;
372 switch (request->tape_op) {
373 case NDMP_MTIO_FSF:
374 tapeop.mt_op = MTFSF;
375 break;
376 case NDMP_MTIO_BSF:
377 tapeop.mt_op = MTBSF;
378 break;
379 case NDMP_MTIO_FSR:
380 tapeop.mt_op = MTFSR;
381 break;
382 case NDMP_MTIO_BSR:
383 tapeop.mt_op = MTBSR;
384 break;
397 case NDMP_MTIO_TUR: /* test unit ready */
398
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;
403 break;
404
405 default:
406 reply.error = NDMP_ILLEGAL_ARGS_ERR;
407 }
408
409 if (reply.error == NDMP_NO_ERR && request->tape_op != NDMP_MTIO_TUR) {
410 tapeop.mt_count = request->count;
411
412 do {
413 NS_UPD(twait, trun);
414 errno = 0;
415 rc = ioctl(session->ns_tape.td_fd, MTIOCTOP, &tapeop);
416 NS_UPD(trun, twait);
417 NDMP_LOG(LOG_DEBUG,
418 "ioctl MTIO rc:%d, cmd:%d, retry:%d, error: %d",
419 rc, tapeop.mt_op, retry, errno);
420 } while (rc < 0 && errno == EIO &&
421 retry++ < 5);
422
423 /*
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.
428 */
429 if (rc < 0) {
430 NDMP_LOG(LOG_ERR,
431 "Failed to send command to tape: %m.");
432 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCTOP) error: %m.");
433
434 /* MTWEOF doesnt have residual count */
435 if (tapeop.mt_op == MTWEOF)
436 reply.error = NDMP_IO_ERR;
437 else
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");
442 return;
443 }
444
445 if (request->tape_op != NDMP_MTIO_REW &&
446 request->tape_op != NDMP_MTIO_OFF) {
447 if (ioctl(session->ns_tape.td_fd, MTIOCGET,
448 &mtstatus) < 0) {
449 NDMP_LOG(LOG_ERR,
450 "Failed to send command to tape: %m.");
451 NDMP_LOG(LOG_DEBUG,
452 "ioctl(MTIOCGET) error: %m.");
453 reply.error = NDMP_IO_ERR;
454 ndmp_send_reply(connection, (void *)&reply,
455 "sending tape_mtio reply");
456
457 return;
458 }
459
460 reply.resid_count = labs(mtstatus.mt_resid);
461 }
462 }
463
464 NDMP_LOG(LOG_DEBUG, "resid_count: %d",
465 reply.resid_count);
466 ndmp_send_reply(connection, (void *) &reply, "sending tape_mtio reply");
467 }
468
469
470 /*
471 * ndmpd_tape_read_v2
472 *
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.
483 *
484 * Parameters:
485 * connection (input) - connection handle.
486 * body (input) - request message body.
487 *
488 * Returns:
489 * void
490 */
491 void
492 ndmpd_tape_read_v2(ndmp_connection_t *connection, void *body)
493 {
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);
497 char *buf;
498
499 reply.data_in.data_in_len = 0;
500
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");
506 return;
507 }
508 if (request->count == 0) {
509 reply.error = NDMP_NO_ERR;
510 ndmp_send_reply(connection, (void *)&reply,
511 "sending tape_read reply");
512 return;
513 }
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");
518 return;
519 }
520
521 unbuffered_read(session, buf, request->count, &reply);
522
532 *
533 * Parameters:
534 * connection (input) - connection handle.
535 * body (input) - request message body.
536 *
537 * Returns:
538 * void
539 */
540 void
541 ndmpd_tape_execute_cdb_v2(ndmp_connection_t *connection, void *body)
542 {
543 ndmp_tape_execute_cdb_request *request;
544 ndmp_tape_execute_cdb_reply reply;
545 ndmpd_session_t *session = ndmp_get_client_data(connection);
546
547 request = (ndmp_tape_execute_cdb_request *) body;
548
549 if (session->ns_tape.td_fd == -1) {
550 (void) memset((void *) &reply, 0, sizeof (reply));
551
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");
556 } else {
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);
560 }
561 }
562
563
564 /*
565 * ************************************************************************
566 * NDMP V3 HANDLERS
567 * ************************************************************************
568 */
569
570 /*
571 * ndmpd_tape_open_v3
572 *
595 * Status information for the currently open tape device is returned.
596 *
597 * Parameters:
598 * connection (input) - connection handle.
599 * body (input) - request message body.
600 *
601 * Returns:
602 * void
603 */
604 /*ARGSUSED*/
605 void
606 ndmpd_tape_get_state_v3(ndmp_connection_t *connection, void *body)
607 {
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;
613
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");
619 return;
620 }
621
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.");
625
626 reply.error = NDMP_IO_ERR;
627 ndmp_send_reply(connection, (void *)&reply,
628 "sending tape_get_state reply");
629 return;
630 }
631
632 dtpr.size = sizeof (struct mtdrivetype);
633 dtpr.mtdtp = &dtp;
634 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
635 NDMP_LOG(LOG_ERR,
636 "Failed to get drive type information from tape: %m.");
637 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
638
639 reply.error = NDMP_IO_ERR;
640 ndmp_send_reply(connection, (void *)&reply,
641 "sending tape_get_state reply");
642 return;
643 }
644
645 reply.flags = 0;
646
647 reply.file_num = mtstatus.mt_fileno;
648 reply.soft_errors = 0;
649 reply.block_size = dtp.bsize;
650 if (dtp.bsize == 0)
651 reply.blockno = mtstatus.mt_blkno;
652 else
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 */
658
659 reply.soft_errors = 0;
660 reply.total_space = long_long_to_quad(0LL);
661 reply.space_remain = long_long_to_quad(0LL);
662
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;
667
668
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);
671
672 reply.error = NDMP_NO_ERR;
673 ndmp_send_reply(connection, (void *) &reply,
674 "sending tape_get_state reply");
675 }
676
677 /*
678 * tape_is_at_bot
679 *
680 * Returns 1 if tape is at BOT, 0 on error or not at BOT.
681 *
682 */
683 int
684 tape_is_at_bot(ndmpd_session_t *session)
685 {
686 struct mtget mtstatus;
687
688 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == 0 &&
689 mtstatus.mt_fileno == 0 && mtstatus.mt_blkno == 0)
690 return (1);
691
747 * length is a multiple of the tape block size if the tape device is in fixed
748 * block mode.
749 *
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
753 * reached.
754 *
755 * Parameters:
756 * connection (input) - connection handle.
757 * body (input) - request message body.
758 */
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;
763
764 reply.count = 0;
765
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");
771 return;
772 }
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");
778 return;
779 }
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");
784 return;
785 }
786
787 /*
788 * V4 suggests that this should not be accepted
789 * when mover is in listen or active state
790 */
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)) {
794
795 reply.error = NDMP_DEVICE_BUSY_ERR;
796 ndmp_send_reply(connection, (void *) &reply,
797 "sending tape_write reply");
798 return;
799 }
800
801 n = write(session->ns_tape.td_fd, request->data_out.data_out_val,
802 request->data_out.data_out_len);
803
804 if (n < 0) {
805 NDMP_LOG(LOG_ERR, "Tape write error: %m.");
806 reply.error = NDMP_IO_ERR;
807 } else if (n == 0) {
808 NDMP_LOG(LOG_INFO, "EOM detected");
809 reply.error = NDMP_EOM_ERR;
810 } else {
811 NS_ADD(wtape, n);
812 reply.count = n;
813 reply.error = NDMP_NO_ERR;
814
815 if (n < request->data_out.data_out_len)
816 NDMP_LOG(LOG_DEBUG,
817 "EOM is coming (partial write of %d bytes)", n);
818 }
819
820 ndmp_send_reply(connection, (void *) &reply,
821 "sending tape_write reply");
822 }
823
824 /*
825 * ndmpd_tape_read_v3
826 *
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.
835 *
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.
839 *
840 * Parameters:
841 * connection (input) - connection handle.
842 * body (input) - request message body.
843 */
844 void
845 ndmpd_tape_read_v3(ndmp_connection_t *connection, void *body)
846 {
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);
850 char *buf;
851 int n;
852
853 reply.data_in.data_in_len = 0;
854
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");
860 return;
861 }
862 if (request->count == 0) {
863 reply.error = NDMP_NO_ERR;
864 ndmp_send_reply(connection, (void *) &reply,
865 "sending tape_read reply");
866 return;
867 }
868
869 /*
870 * V4 suggests that this should not be accepted
871 * when mover is in listen or active state
872 */
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)) {
876
884 reply.error = NDMP_NO_MEM_ERR;
885 ndmp_send_reply(connection, (void *) &reply,
886 "sending tape_read reply");
887 return;
888 }
889
890 n = read(session->ns_tape.td_fd, buf, request->count);
891 if (n < 0) {
892 /*
893 * This fix is for Symantec during importing
894 * of spanned data between the tapes.
895 */
896 if (errno == ENOSPC) {
897 reply.error = NDMP_EOF_ERR;
898 }
899 /*
900 * If at beginning of file and read fails with EIO, then it's
901 * repeated attempt to read at EOT.
902 */
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;
906 }
907 /*
908 * According to NDMPv4 spec preferred error code when
909 * trying to read from blank tape is NDMP_EOM_ERR.
910 */
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;
914 } else {
915 NDMP_LOG(LOG_ERR, "Tape read error: %m.");
916 reply.error = NDMP_IO_ERR;
917 }
918 } else if (n == 0) {
919 if (tape_is_at_bof(session)) {
920 NDMP_LOG(LOG_DEBUG, "EOT detected");
921 reply.error = NDMP_EOM_ERR;
922 } else {
923 /* reposition the tape to BOT side of FM */
924 fm_dance(session);
925 NDMP_LOG(LOG_DEBUG, "EOF detected");
926 reply.error = NDMP_EOF_ERR;
927 }
928 } else {
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;
933 NS_ADD(rtape, n);
934 }
935
936 ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
937 free(buf);
938 }
939
940
941 /*
942 * ************************************************************************
943 * NDMP V4 HANDLERS
944 * ************************************************************************
945 */
951 * Status information for the currently open tape device is returned.
952 *
953 * Parameters:
954 * connection (input) - connection handle.
955 * body (input) - request message body.
956 *
957 * Returns:
958 * void
959 */
960 /*ARGSUSED*/
961 void
962 ndmpd_tape_get_state_v4(ndmp_connection_t *connection, void *body)
963 {
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;
969
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");
975 return;
976 }
977
978 /*
979 * Need code to detect NDMP_TAPE_STATE_NOREWIND
980 */
981
982 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
983 NDMP_LOG(LOG_ERR,
984 "Failed to get status information from tape: %m.");
985 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
986
987 reply.error = NDMP_IO_ERR;
988 ndmp_send_reply(connection, (void *)&reply,
989 "sending tape_get_state reply");
990 return;
991 }
992
993 dtpr.size = sizeof (struct mtdrivetype);
994 dtpr.mtdtp = &dtp;
995 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
996 NDMP_LOG(LOG_ERR,
997 "Failed to get drive type information from tape: %m.");
998 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
999
1000 reply.error = NDMP_IO_ERR;
1001 ndmp_send_reply(connection, (void *)&reply,
1002 "sending tape_get_state reply");
1003 return;
1004 }
1005
1006 reply.flags = NDMP_TAPE_NOREWIND;
1007
1008 reply.file_num = mtstatus.mt_fileno;
1009 reply.soft_errors = 0;
1010 reply.block_size = dtp.bsize;
1011
1012 if (dtp.bsize == 0)
1013 reply.blockno = mtstatus.mt_blkno;
1014 else
1015 reply.blockno = mtstatus.mt_blkno /
1016 (session->ns_mover.md_record_size / dtp.bsize);
1017
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;
1025
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);
1028
1029 reply.error = NDMP_NO_ERR;
1030 ndmp_send_reply(connection, (void *) &reply,
1031 "sending tape_get_state reply");
1032 }
1033 /*
1034 * ndmpd_tape_close_v4
1035 *
1036 * This handler (v4) closes the currently open tape device.
1037 *
1038 * Parameters:
1039 * connection (input) - connection handle.
1040 * body (input) - request message body.
1041 *
1042 * Returns:
1043 * void
1044 */
1045 /*ARGSUSED*/
1046 void
1047 ndmpd_tape_close_v4(ndmp_connection_t *connection, void *body)
1048 {
1049 ndmp_tape_close_reply reply;
1050 ndmpd_session_t *session = ndmp_get_client_data(connection);
1051
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");
1057 return;
1058 }
1059
1060 /*
1061 * V4 suggests that this should not be accepted
1062 * when mover is in listen or active state
1063 */
1064 if (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
1065 session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
1066
1067 reply.error = NDMP_DEVICE_BUSY_ERR;
1068 ndmp_send_reply(connection, (void *) &reply,
1069 "sending tape_close reply");
1070 return;
1071 }
1072
1073 common_tape_close(connection);
1112 * reply (output) - tape read reply message
1113 *
1114 * Returns:
1115 * void
1116 */
1117 static void
1118 unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
1119 ndmp_tape_read_reply *reply)
1120 {
1121 int n, len;
1122
1123 n = read(session->ns_tape.td_fd, buf, wanted);
1124 if (n < 0) {
1125 /*
1126 * This fix is for Symantec during importing
1127 * of spanned data between the tapes.
1128 */
1129 if (errno == ENOSPC) {
1130 reply->error = NDMP_EOF_ERR;
1131 } else {
1132 NDMP_LOG(LOG_ERR, "Tape read error: %m.");
1133 reply->error = NDMP_IO_ERR;
1134 }
1135 } else if (n == 0) {
1136 NDMP_LOG(LOG_DEBUG, "NDMP_EOF_ERR");
1137
1138 reply->error = NDMP_EOF_ERR;
1139
1140 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
1141
1142 len = strlen(NDMP_EOM_MAGIC);
1143 (void) memset(buf, 0, len);
1144 n = read(session->ns_tape.td_fd, buf, len);
1145 buf[len] = '\0';
1146
1147 NDMP_LOG(LOG_DEBUG, "Checking EOM: nread %d [%s]", n, buf);
1148
1149 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
1150
1151 if (strncmp(buf, NDMP_EOM_MAGIC, len) != 0)
1152 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
1153 } else {
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;
1158 NS_ADD(rtape, n);
1159 }
1160 }
1161
1162
1163 /*
1164 * validmode
1165 *
1166 * Check the tape read mode is valid
1167 */
1168 static boolean_t
1190 *
1191 * Generic function for opening the tape for all versions
1192 *
1193 * Parameters:
1194 * connection (input) - connection handle.
1195 * devname (input) - tape device name to open.
1196 * ndmpmode (input) - mode of opening (read, write, raw)
1197 *
1198 * Returns:
1199 * void
1200 */
1201 static void
1202 common_tape_open(ndmp_connection_t *connection, char *devname, int ndmpmode)
1203 {
1204 ndmpd_session_t *session = ndmp_get_client_data(connection);
1205 char adptnm[SCSI_MAX_NAME];
1206 int err;
1207 int mode;
1208 int sid, lun;
1209 scsi_adapter_t *sa;
1210 int devid;
1211
1212 err = NDMP_NO_ERR;
1213
1214 if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
1215 NDMP_LOG(LOG_INFO,
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';
1224 sid = lun = -1;
1225 }
1226 if (sa) {
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) {
1230 NDMP_LOG(LOG_ERR,
1231 "Failed to open device %s: %m.", devname);
1232 err = NDMP_NO_DEVICE_ERR;
1233 } else {
1234 (void) close(devid);
1235 }
1236 } else {
1237 NDMP_LOG(LOG_ERR, "%s: No such tape device.", devname);
1238 err = NDMP_NO_DEVICE_ERR;
1239 }
1240
1241 if (err != NDMP_NO_ERR) {
1242 tape_open_send_reply(connection, err);
1243 return;
1244 }
1245
1246 /*
1247 * If tape is not opened in raw mode and tape is not loaded
1248 * return error.
1249 */
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);
1254 return;
1255 }
1256
1257 mode = (ndmpmode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
1258 mode |= O_NDELAY;
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) {
1263 /*
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.
1267 */
1268 ndmpmode = NDMP_TAPE_READ_MODE;
1269 session->ns_tape.td_fd = open(devname, O_RDONLY);
1270 }
1271 if (session->ns_tape.td_fd < 0) {
1272 NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
1273 devname);
1274 switch (errno) {
1275 case EACCES:
1276 err = NDMP_WRITE_PROTECT_ERR;
1277 break;
1278 case ENOENT:
1279 err = NDMP_NO_DEVICE_ERR;
1280 break;
1281 case EBUSY:
1282 err = NDMP_DEVICE_BUSY_ERR;
1283 break;
1284 case EPERM:
1285 err = NDMP_PERMISSION_ERR;
1286 break;
1287 default:
1288 err = NDMP_IO_ERR;
1289 }
1290
1291 tape_open_send_reply(connection, err);
1292 return;
1300 case EBUSY:
1301 err = NDMP_DEVICE_BUSY_ERR;
1302 break;
1303 case ENOMEM:
1304 err = NDMP_NO_MEM_ERR;
1305 break;
1306 default:
1307 err = NDMP_IO_ERR;
1308 }
1309 if (err != NDMP_NO_ERR) {
1310 tape_open_send_reply(connection, err);
1311 return;
1312 }
1313
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;
1319
1320 NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
1321
1322 tape_open_send_reply(connection, NDMP_NO_ERR);
1323 }
1324
1325
1326 /*
1327 * common_tape_close
1328 *
1329 * Generic function for closing the tape
1330 *
1331 * Parameters:
1332 * connection (input) - connection handle.
1333 *
1334 * Returns:
1335 * void
1336 */
1337 static void
1338 common_tape_close(ndmp_connection_t *connection)
1339 {
1340 ndmpd_session_t *session = ndmp_get_client_data(connection);
1341 ndmp_tape_close_reply reply;
|
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.
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;
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;
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
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 *
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
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
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 */
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);
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
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;
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;
|