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 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.
63 */
64 int ndmp_tape_open_retries = 5;
65 int ndmp_tape_open_delay = 1000;
66
67 /*
68 * A few words about EOT (end-of-tape) and EOM handling on tapes with SVR4
69 * semantic:
70 *
71 * We adhere to terminology as used in st driver. EOT means end of recorded
72 * data on a tape. This is different from EOM (somewhere referred to as LEOT)
73 * which is the end of tape medium. EOT is meaningful only for reads while EOM
74 * is meaningful only for writes. It's not possible to read after EOT (fails
75 * with EIO), but it's possible to write data after EOM. EOM returned by st
76 * driver on modern tape drives is just indication that the physical end of
77 * tape medium is nearing and that writer should write just the necessary
78 * minimum and stop writing. When physical end of tape is reached all writes
79 * return EIO. If EOM is crossed during read operation then st driver doesn't
80 * bother to report it to client and that's alright because reads don't care
81 * where medium physically ends but they care about meaningful data recorded on
82 * the tape and as long as there are such data reads should continue to work.
83 *
84 * When reading EOT is signalled by st driver by two empty consecutive reads
85 * (with FSF done between them). When writing EOM is signalled by empty write
86 * (a write which writes zero bytes). Following writes succeed until physical
87 * end of tape is reached in which case EIO is returned.
88 */
89
90 /*
91 * ************************************************************************
92 * NDMP V2 HANDLERS
93 * ************************************************************************
94 */
95
96 /*
97 * ndmpd_tape_open_v2
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
ndmpd_tape_open_v2(ndmp_connection_t * connection,void * body)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;
173 }
174 if (err != NDMP_NO_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
ndmpd_tape_close_v2(ndmp_connection_t * connection,void * body)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
ndmpd_tape_get_state_v2(ndmp_connection_t * connection,void * body)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
ndmpd_tape_mtio_v2(ndmp_connection_t * connection,void * body)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;
385 case NDMP_MTIO_REW:
386 tapeop.mt_op = MTREW;
387 break;
388 case NDMP_MTIO_EOF:
389 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE)
390 reply.error = NDMP_PERMISSION_ERR;
391 tapeop.mt_op = MTWEOF;
392 break;
393 case NDMP_MTIO_OFF:
394 tapeop.mt_op = MTOFFL;
395 break;
396
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
ndmpd_tape_read_v2(ndmp_connection_t * connection,void * body)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
523 ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
524 (void) free(buf);
525 }
526
527
528 /*
529 * ndmpd_tape_execute_cdb_v2
530 *
531 * This handler handles tape_execute_cdb requests.
532 *
533 * Parameters:
534 * connection (input) - connection handle.
535 * body (input) - request message body.
536 *
537 * Returns:
538 * void
539 */
540 void
ndmpd_tape_execute_cdb_v2(ndmp_connection_t * connection,void * body)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 *
573 * This handler opens the specified tape device.
574 *
575 * Parameters:
576 * connection (input) - connection handle.
577 * body (input) - request message body.
578 *
579 * Returns:
580 * void
581 */
582 void
ndmpd_tape_open_v3(ndmp_connection_t * connection,void * body)583 ndmpd_tape_open_v3(ndmp_connection_t *connection, void *body)
584 {
585 ndmp_tape_open_request_v3 *request = (ndmp_tape_open_request_v3 *)body;
586
587 common_tape_open(connection, request->device, request->mode);
588 }
589
590
591 /*
592 * ndmpd_tape_get_state_v3
593 *
594 * This handler handles the ndmp_tape_get_state_request.
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
ndmpd_tape_get_state_v3(ndmp_connection_t * connection,void * body)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
tape_is_at_bot(ndmpd_session_t * session)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
692 return (0);
693 }
694
695 /*
696 * If we are at the beginning of a file (block # is zero) and read returns
697 * zero bytes then this has to be end of recorded data on the tape. Repeated
698 * reads at EOT return EIO. In both cases (zero read and EIO read) this
699 * function should be used to test if we are at EOT.
700 *
701 * Returns 1 if tape is at BOF, 0 on error or not at BOF.
702 */
703 int
tape_is_at_bof(ndmpd_session_t * session)704 tape_is_at_bof(ndmpd_session_t *session)
705 {
706 struct mtget mtstatus;
707
708 if ((ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == 0) &&
709 (mtstatus.mt_fileno > 0) && (mtstatus.mt_blkno == 0))
710 return (1);
711
712 return (0);
713 }
714
715 /*
716 * Skips forward over a file mark and then back before the file mark. Why is
717 * this needed? There are two reasons for it:
718 *
719 * 1) Because NDMPv4 spec requires that when EOF is encountered, the tape
720 * position should remain on BOT side of the file mark. When st driver reaches
721 * end of file get-position mtioctl reports position before file mark, however
722 * the file mark has already been read and the real position is thus after the
723 * file mark (real position as reported for example by uscsi commands). Thus we
724 * need to do FSF, which does nothing but only updates file & block counter in
725 * st driver and then BSF, which sets the position before the file mark. Thus
726 * current position as reported by scsi and mtioctl will be in sync.
727 *
728 * 2) st driver returns EIO for repeated reads at EOF while according to NDMP
729 * spec we should continue to return zero bytes until FSF is done. By skipping
730 * forward and backward, st driver will return zero bytes for the next read
731 * again and we don't need to specifically handle this case.
732 */
733 void
fm_dance(ndmpd_session_t * session)734 fm_dance(ndmpd_session_t *session)
735 {
736 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
737 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
738 }
739
740 /*
741 * ndmpd_tape_write_v3
742 *
743 * This handler handles tape_write requests. This interface is a non-buffered
744 * interface. Each write request maps directly to a write to the tape device.
745 * It is the responsibility of the NDMP client to pad the data to the desired
746 * record size. It is the responsibility of the NDMP client to ensure that the
747 * length is a multiple of the tape block size if the tape device is in fixed
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 */
ndmpd_tape_write_v3(ndmp_connection_t * connection,void * body)759 void ndmpd_tape_write_v3(ndmp_connection_t *connection, void *body) {
760 ndmp_tape_write_request *request = (ndmp_tape_write_request *)body;
761 ndmp_tape_write_reply reply; ndmpd_session_t *session =
762 ndmp_get_client_data(connection); ssize_t n;
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
ndmpd_tape_read_v3(ndmp_connection_t * connection,void * body)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
877 reply.error = NDMP_DEVICE_BUSY_ERR;
878 ndmp_send_reply(connection, (void *) &reply,
879 "sending tape_read reply");
880 return;
881 }
882
883 if ((buf = ndmp_malloc(request->count)) == NULL) {
884 reply.error = NDMP_NO_MEM_ERR;
885 ndmp_send_reply(connection, (void *) &reply,
886 "sending tape_read reply");
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 */
946
947 /*
948 * ndmpd_tape_get_state_v4
949 *
950 * This handler handles the ndmp_tape_get_state_request.
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
ndmpd_tape_get_state_v4(ndmp_connection_t * connection,void * body)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
ndmpd_tape_close_v4(ndmp_connection_t * connection,void * body)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);
1074 }
1075
1076
1077 /*
1078 * ************************************************************************
1079 * LOCALS
1080 * ************************************************************************
1081 */
1082 /*
1083 * tape_open_send_reply
1084 *
1085 * Send a reply to the tape open message
1086 *
1087 * Parameters:
1088 * connection (input) - connection handle.
1089 * err (input) - NDMP error
1090 *
1091 * Returns:
1092 * void
1093 */
1094 static void
tape_open_send_reply(ndmp_connection_t * connection,int err)1095 tape_open_send_reply(ndmp_connection_t *connection, int err)
1096 {
1097 ndmp_tape_open_reply reply;
1098
1099 reply.error = err;
1100 ndmp_send_reply(connection, (void *) &reply, "sending tape_open reply");
1101 }
1102
1103 /*
1104 * unbuffered_read
1105 *
1106 * Perform tape read without read-ahead
1107 *
1108 * Parameters:
1109 * session (input) - session handle
1110 * bp (output) - read buffer
1111 * wanted (input) - number of bytes wanted
1112 * reply (output) - tape read reply message
1113 *
1114 * Returns:
1115 * void
1116 */
1117 static void
unbuffered_read(ndmpd_session_t * session,char * buf,long wanted,ndmp_tape_read_reply * reply)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
validmode(int mode)1169 validmode(int mode)
1170 {
1171 boolean_t rv;
1172
1173 switch (mode) {
1174 case NDMP_TAPE_READ_MODE:
1175 case NDMP_TAPE_WRITE_MODE:
1176 case NDMP_TAPE_RAW1_MODE:
1177 case NDMP_TAPE_RAW2_MODE:
1178 rv = TRUE;
1179 break;
1180 default:
1181 rv = FALSE;
1182 }
1183
1184 return (rv);
1185 }
1186
1187
1188 /*
1189 * common_tape_open
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
common_tape_open(ndmp_connection_t * connection,char * devname,int ndmpmode)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;
1293 }
1294
1295 switch (ndmp_open_list_add(connection,
1296 adptnm, sid, lun, session->ns_tape.td_fd)) {
1297 case 0:
1298 err = NDMP_NO_ERR;
1299 break;
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
common_tape_close(ndmp_connection_t * connection)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;
1342
1343 (void) ndmp_open_list_del(session->ns_tape.td_adapter_name,
1344 session->ns_tape.td_sid, session->ns_tape.td_lun);
1345 (void) close(session->ns_tape.td_fd);
1346 session->ns_tape.td_fd = -1;
1347 session->ns_tape.td_sid = 0;
1348 session->ns_tape.td_lun = 0;
1349 (void) memset(session->ns_tape.td_adapter_name, 0,
1350 sizeof (session->ns_tape.td_adapter_name));
1351 session->ns_tape.td_record_count = 0;
1352
1353 reply.error = NDMP_NO_ERR;
1354 ndmp_send_reply(connection, (void *) &reply,
1355 "sending tape_close reply");
1356 }
1357
1358 /*
1359 * tape_open
1360 *
1361 * Will try to open the tape with the given flags and
1362 * path using the given retries and delay intervals
1363 */
1364 int
tape_open(char * path,int flags)1365 tape_open(char *path, int flags)
1366 {
1367 int fd;
1368 int i = 0;
1369
1370 while ((fd = open(path, flags)) == -1 &&
1371 i++ < ndmp_tape_open_retries) {
1372 if (errno != EBUSY)
1373 break;
1374 (void) usleep(ndmp_tape_open_delay);
1375 }
1376 return (fd);
1377 }
1378