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 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 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; 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 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 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 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 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 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 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 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 */ 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 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 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); 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 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 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 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 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 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 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