xref: /titanic_44/usr/src/cmd/ndmpd/ndmp/ndmpd_tape.c (revision 9ee94b97c8654689d6a034daec08757fda75d21a)
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