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