1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 */ 24 25 26 /* 27 * Driver for Disk Archiving (dda) 28 * 29 * DDA emulates the st tape driver BSD mode for MMS disk archiving. 30 * 31 * A limited number of MTIO operations are implemented by DDA. 32 * 33 * USCSI commands are not implemented by DDA. 34 * 35 * Tape drive operations such as load, capacity and read block limits 36 * are DDA ioctl commands. 37 * 38 * DDA media is implemented as a cartridge directory containing three 39 * files: metadata, index and data. 40 * 41 * The metadata file contains cartridge information such as version, 42 * capacity, stripe alignment, direct I/O alignment, and the write 43 * protect tab. The user application sets the alignments when the dda 44 * media is created. 45 * 46 * The index file contains index records which describes the data file. 47 * An index record contains the data file offset, number of consecutive 48 * same size records and filemarks. An new index record is generated 49 * when a write changes record sizes or data follows a filemark. A on 50 * disk binary search is used for locate or space filemarks operations. 51 * An advisory file lock is held on the index file to prevent multiple 52 * loads for the same piece of dda media and to prevent a load when 53 * the user is changing the cartridge write protect tab. The data file 54 * offset is adjusted for alignment at bot, when data follows a filemark, 55 * or the record size changes. Stripe alignment occurs at bot or after a 56 * filemark. Direct I/O alignment occurs for every read or write operation 57 * and is applied after the stripe alignment. 58 * 59 * The data file contains user data along with holes for stripe and 60 * direct I/O alignment. 61 * 62 * The metadata and index file records are used in native endian format 63 * in memory and are stored on disk in big endian format. The data file 64 * is in the host's native endian format. 65 */ 66 67 #include <sys/devops.h> /* used by dev_ops */ 68 #include <sys/conf.h> /* used by dev_ops and cb_ops */ 69 #include <sys/modctl.h> /* used by modlinkage, modldrv, */ 70 /* _init, _info, and _fini */ 71 #include <sys/types.h> /* used by open, close, read, write, */ 72 /* prop_op, and ddi_prop_op */ 73 #include <sys/file.h> /* used by open, close */ 74 #include <sys/errno.h> /* used by open, close, read, write */ 75 #include <sys/open.h> /* used by open, close, read, write */ 76 #include <sys/cred.h> /* used by open, close, read */ 77 #include <sys/uio.h> /* used by read */ 78 #include <sys/stat.h> /* defines S_IFCHR used by */ 79 /* ddi_create_minor_node */ 80 #include <sys/cmn_err.h> /* used by all entry points for */ 81 /* this driver */ 82 #include <sys/ddi.h> /* used by all entry points for */ 83 /* this driver also used by cb_ops, */ 84 /* ddi_get_instance, and ddi_prop_op */ 85 #include <sys/sunddi.h> /* used by all entry points for */ 86 /* this driver also used by cb_ops, */ 87 /* ddi_create_minor_node, */ 88 /* ddi_get_instance, and ddi_prop_op */ 89 #include <sys/scsi/impl/uscsi.h> /* uscsi commands */ 90 #include <sys/ioctl.h> 91 #include <sys/mtio.h> /* tape io */ 92 #include <sys/systeminfo.h> /* for hostid access */ 93 #include <sys/scsi/targets/stdef.h> 94 #include <sys/vfs.h> 95 #include <limits.h> 96 #include <sys/sdt.h> /* d-trace */ 97 #include <sys/flock.h> /* advisory non-blocking file lock */ 98 #include "dda.h" 99 100 /* vnode mode is read, write, large files, allow symlinks */ 101 #define DDA_VNODE_MODE FREAD|FWRITE|FOFFMAX 102 103 /* maximum block size */ 104 #define DDA_MAX_REC_SIZE 262144 /* maximum media block size */ 105 106 /* early warning capacity - space */ 107 #define DDA_EARLY_WARN 98 /* media early warning percentage */ 108 109 /* block number unknown */ 110 #define DDA_BLKNO_UNKNOWN 1000000000 111 112 /* file name unknown */ 113 #define DDA_UNKNOWN_FNAME "?" 114 115 /* operation flags and macros */ 116 #define DDA_FLAG_TRUNC 0x1 /* write truncate */ 117 #define DDA_FLAG_FM_FWD_PEND 0x2 /* file mark forward pending */ 118 #define DDA_FLAG_FM_NOSKIP 0x4 /* fsr set fm forward pending */ 119 #define DDA_FLAG_FM_NEEDED 0x8 /* file mark needed */ 120 #define DDA_FLAG_EOT_EIO 0x10 /* read return code for eot */ 121 #define DDA_FLAG_EW 0x20 /* alternating ew write failure */ 122 #define DDA_FLAG_INDEX 0x40 /* index record needs file write */ 123 124 #define DDA_GET_TRUNC(x) (x->dda_flags & DDA_FLAG_TRUNC) 125 #define DDA_GET_FM_FWD_PEND(x) (x->dda_flags & DDA_FLAG_FM_FWD_PEND) 126 #define DDA_GET_FM_NOSKIP(x) (x->dda_flags & DDA_FLAG_FM_NOSKIP) 127 #define DDA_GET_FM_NEEDED(x) (x->dda_flags & DDA_FLAG_FM_NEEDED) 128 #define DDA_GET_EOT_EIO(x) (x->dda_flags & DDA_FLAG_EOT_EIO) 129 #define DDA_GET_EW(x) (x->dda_flags & DDA_FLAG_EW) 130 #define DDA_GET_INDEX(x) (x->dda_flags & DDA_FLAG_INDEX) 131 132 #define DDA_SET_TRUNC(x) (x->dda_flags |= DDA_FLAG_TRUNC) 133 #define DDA_SET_FM_FWD_PEND(x) (x->dda_flags |= DDA_FLAG_FM_FWD_PEND) 134 #define DDA_SET_FM_NOSKIP(x) (x->dda_flags |= DDA_FLAG_FM_NOSKIP) 135 #define DDA_SET_FM_NEEDED(x) (x->dda_flags |= DDA_FLAG_FM_NEEDED) 136 #define DDA_SET_EOT_EIO(x) (x->dda_flags |= DDA_FLAG_EOT_EIO) 137 #define DDA_SET_EW(x) (x->dda_flags |= DDA_FLAG_EW) 138 #define DDA_SET_INDEX(x) (x->dda_flags |= DDA_FLAG_INDEX) 139 140 #define DDA_CLR_TRUNC(x) (x->dda_flags &= ~DDA_FLAG_TRUNC) 141 #define DDA_CLR_FM_FWD_PEND(x) (x->dda_flags &= ~(DDA_FLAG_FM_FWD_PEND | \ 142 DDA_FLAG_FM_NOSKIP)) 143 #define DDA_CLR_FM_NOSKIP(x) (x->dda_flags &= ~DDA_FLAG_FM_NOSKIP) 144 #define DDA_CLR_FM_NEEDED(x) (x->dda_flags &= ~DDA_FLAG_FM_NEEDED) 145 #define DDA_CLR_EOT_EIO(x) (x->dda_flags &= ~DDA_FLAG_EOT_EIO) 146 #define DDA_CLR_EW(x) (x->dda_flags &= ~DDA_FLAG_EW) 147 #define DDA_CLR_INDEX(x) (x->dda_flags &= ~DDA_FLAG_INDEX) 148 149 /* metadata flag */ 150 #define DDA_GET_WPROTECT(x) (x->dda_metadata.dda_flags & DDA_FLAG_WPROTECT) 151 152 /* read only tape */ 153 #define DDA_GET_READ_ONLY(x) ((x->dda_read_only || \ 154 DDA_GET_WPROTECT(x)) ? 1 : 0) 155 156 /* alignment macros */ 157 #define DDA_OFF_ALIGNED(off, sz) (off & (int64_t)(sz - 1)) 158 #define DDA_LEN_ALIGNED(len, sz) ((size_t)len & (sz - 1)) 159 160 /* index record calculations */ 161 #define DDA_IS_BOT(x) (x->dda_index_offset == 0 && \ 162 x->dda_pos == 0 ? 1 : 0) 163 #define DDA_IS_BLANK(x) (x->dda_index_offset == 0 && \ 164 DDA_INDEX_COUNT(x) == 0 ? 1 : 0) 165 #define DDA_IS_FM(x) (DDA_IS_BLANK(x) ? 0 : \ 166 x->dda_index.dda_fmcount && \ 167 x->dda_pos >= x->dda_index. \ 168 dda_blkcount && \ 169 x->dda_pos <= DDA_INDEX_COUNT(x) ? 1 : 0) 170 #define DDA_LBA(x) (x->dda_index.dda_lba + x->dda_pos) 171 #define DDA_INDEX_COUNT(x) (x->dda_index.dda_blkcount + \ 172 x->dda_index.dda_fmcount) 173 174 #ifdef DEBUG 175 #define DDA_DEBUG(y) y 176 #else 177 #define DDA_DEBUG(y) 178 #endif 179 180 #define DDA_DEBUG1(x) DDA_DEBUG(DTRACE_PROBE1 x) 181 #define DDA_DEBUG2(x) DDA_DEBUG(DTRACE_PROBE2 x) 182 #define DDA_DEBUG3(x) DDA_DEBUG(DTRACE_PROBE3 x) 183 #define DDA_DEBUG4(x) DDA_DEBUG(DTRACE_PROBE4 x) 184 185 /* index record state */ 186 typedef struct dda_istate { 187 dda_index_t dda_index; 188 off64_t dda_index_offset; 189 int64_t dda_pos; 190 uint32_t dda_flags; 191 } dda_istate_t; 192 193 /* driver operations */ 194 static int dda_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 195 static int dda_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 196 static int dda_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 197 void **resultp); 198 static int dda_open(dev_t *devp, int flag, int otyp, cred_t *credp); 199 static int dda_close(dev_t dev, int flag, int otyp, cred_t *credp); 200 static int dda_read(dev_t dev, struct uio *uio, cred_t *credp); 201 static int dda_write(dev_t dev, struct uio *uio, cred_t *credp); 202 static int dda_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 203 int *rvalp); 204 205 /* tape operations */ 206 static int dda_tape_op(dda_t *dda, struct mtlop *mtop); 207 static int dda_tape_load(dda_t *dda, char *path); 208 static int dda_tape_unload(dda_t *dda); 209 static int dda_tape_rewind(dda_t *dda); 210 static int dda_tape_write(dda_t *dda, struct uio *uio); 211 static int dda_tape_read(dda_t *dda, struct uio *uio); 212 static int dda_tape_wfm(dda_t *dda, int count); 213 static int dda_tape_eom(dda_t *dda); 214 static int dda_tape_fsf(dda_t *dda, int count); 215 static int dda_tape_bsf(dda_t *dda, int count); 216 static int dda_tape_fsr(dda_t *dda, int count); 217 static int dda_tape_bsr(dda_t *dda, int count); 218 static int dda_tape_locate(dda_t *dda, int64_t position); 219 static int dda_tape_erase(dda_t *dda); 220 221 /* support routines */ 222 static void dda_set_unloaded(dda_t *dda); 223 static int64_t dda_get_fileno(dda_t *dda); 224 static int dda_get_blkno(dda_t *dda, int64_t *blkno); 225 static int dda_write_truncate(dda_t *dda); 226 227 /* index record write, read, generate, save and restore */ 228 static int dda_write_index(dda_t *dda); 229 static int dda_read_index(dda_t *dda); 230 static void dda_gen_next_index(dda_t *dda, int32_t blksize); 231 static void dda_save_istate(dda_t *dda, dda_istate_t *istate); 232 static void dda_restore_istate(dda_t *dda, dda_istate_t *istate); 233 234 /* data file offset */ 235 static off64_t dda_stripe_align(dda_t *dda); 236 static off64_t dda_data_offset(dda_t *dda); 237 238 /* space */ 239 static int dda_tape_capacity(dda_t *dda, int64_t *space); 240 static int dda_ew_eom(dda_t *dda, int32_t count, int64_t *avail, int *ew); 241 242 /* search */ 243 static int dda_locate_compare(dda_t *dda, int64_t lba); 244 static int dda_fsf_compare(dda_t *dda, int64_t fileno); 245 static int dda_bsf_compare(dda_t *dda, int64_t fileno); 246 static int dda_bsearch(dda_t *dda, 247 int64_t key, 248 int (*compare)(dda_t *, int64_t), 249 int *found); 250 251 /* vnode operations */ 252 static int dda_vn_open(dda_t *dda, struct vnode **vpp, char *fname); 253 static int dda_vn_close(dda_t *dda, struct vnode **vpp); 254 static int dda_vn_lock(dda_t *dda, struct vnode *vp, short lock); 255 static int dda_vn_read(dda_t *dda, struct vnode *vp, void *buf, int len, 256 off64_t offset); 257 static int dda_vn_write(dda_t *dda, struct vnode *vp, void *buf, int len, 258 off64_t offset); 259 static int dda_vn_truncate(dda_t *dda, struct vnode *vp, off64_t offset); 260 static int dda_vn_sync(dda_t *dda, struct vnode *vp); 261 static int dda_vn_size(dda_t *dda, struct vnode *vp, off64_t *fsize); 262 static char *dda_vn_get_fname(dda_t *dda, struct vnode *vp); 263 static void dda_vn_error_skey(dda_t *dda, int err); 264 265 /* cb_ops structure */ 266 static struct cb_ops dda_cb_ops = { 267 dda_open, 268 dda_close, 269 nodev, /* no strategy - nodev returns ENXIO */ 270 nodev, /* no print */ 271 nodev, /* no dump */ 272 dda_read, 273 dda_write, 274 dda_ioctl, 275 nodev, /* no devmap */ 276 nodev, /* no mmap */ 277 nodev, /* no segmap */ 278 nochpoll, /* returns ENXIO for non-pollable devices */ 279 ddi_prop_op, 280 NULL, /* streamtab struct; if not NULL, all above */ 281 /* fields are ignored */ 282 D_NEW | D_MP, /* compatibility flags: see conf.h */ 283 CB_REV, /* cb_ops revision number */ 284 nodev, /* no aread */ 285 nodev /* no awrite */ 286 }; 287 288 /* dev_ops structure */ 289 static struct dev_ops dda_dev_ops = { 290 DEVO_REV, 291 0, /* reference count */ 292 dda_getinfo, 293 nulldev, /* no identify - nulldev returns 0 */ 294 nulldev, /* no probe */ 295 dda_attach, 296 dda_detach, 297 nodev, /* no reset - nodev returns ENXIO */ 298 &dda_cb_ops, 299 (struct bus_ops *)NULL, 300 nodev /* no power */ 301 }; 302 303 /* modldrv structure */ 304 #define DDA_LINKINFO "driver for disk archiving" 305 static char dda_linkinfo[100]; 306 static struct modldrv dda_md = { 307 &mod_driverops, 308 dda_linkinfo, 309 &dda_dev_ops 310 }; 311 312 /* modlinkage structure */ 313 static struct modlinkage dda_ml = { 314 MODREV_1, 315 &dda_md, 316 NULL 317 }; 318 319 /* dev_info structure, one instance per dda device */ 320 static void *dda_state; 321 322 /* Loadable module configuration entry points */ 323 324 /* 325 * _init 326 * 327 * Parameters: 328 * None 329 * 330 * Globals: 331 * - dda_state: Uninitialized list of DDA drives. 332 * - dda_linkinfo: DDA description string. 333 * - dda_ml: DDA module linkage structure. 334 * 335 * Initialize list of emulated tape drives. 336 * Create driver description reported to user. 337 * Export driver specification to the kernel. 338 * 339 * Return Values: 340 * 0 : success 341 * non-zero : failure 342 * 343 */ 344 int 345 _init(void) 346 { 347 int rc; 348 349 if ((rc = ddi_soft_state_init(&dda_state, sizeof (dda_t), 0)) != 0) { 350 cmn_err(CE_WARN, "_init: soft state init error %d", rc); 351 return (rc); 352 } 353 (void) snprintf(dda_linkinfo, sizeof (dda_linkinfo), "%s %d.%d", 354 DDA_LINKINFO, DDA_MAJOR_VERSION, DDA_MINOR_VERSION); 355 if ((rc = mod_install(&dda_ml)) != 0) { 356 cmn_err(CE_WARN, "_init: mod install error %d", rc); 357 ddi_soft_state_fini(&dda_state); 358 } 359 return (rc); 360 } 361 362 /* 363 * _info 364 * 365 * Parameters: 366 * - modinfop: Opaque module information structure. 367 * 368 * Globals: 369 * - dda_ml: DDA module linkage structure. 370 * 371 * Report DDA module information. 372 * 373 * Return Values: 374 * non-zero : success 375 * 0 : failure 376 * 377 */ 378 int 379 _info(struct modinfo *modinfop) 380 { 381 int rc; 382 383 if ((rc = mod_info(&dda_ml, modinfop)) == 0) { 384 cmn_err(CE_WARN, "_info: mod info error %d", rc); 385 } 386 return (rc); 387 } 388 389 /* 390 * _fini 391 * 392 * Parameters: 393 * - none 394 * 395 * Globals: 396 * - dda_ml: DDA module linkage structure. 397 * - dda_state: DDA drive list. 398 * 399 * Prepare to unload the DDA driver from the kernel. 400 * Release DDA drive list to the system. 401 * 402 * Return Values: 403 * 0 : success 404 * non-zero : failure 405 * 406 */ 407 int 408 _fini(void) 409 { 410 int rc; 411 412 if ((rc = mod_remove(&dda_ml)) != 0) { 413 return (rc); 414 } 415 ddi_soft_state_fini(&dda_state); 416 return (rc); 417 } 418 419 /* Device configuration entry points */ 420 421 /* 422 * dda_attach 423 * 424 * Parameters: 425 * - dip: Device information structure. 426 * - cmd: Attach command. 427 * 428 * Globals: 429 * - dda_state: Pointer to list of DDA drives. 430 * 431 * Create and initialize one DDA tape drive for each dda.conf instance. 432 * Create BSD no-rewind tape drive minor node. 433 * Assign generated serial number to the drive. 434 * Initialize exclusive drive access mutex. 435 * Set drive state to unload. 436 * 437 * Return Values: 438 * DDI_SUCCESS : success 439 * DDI_FAILURE : failure 440 * 441 */ 442 static int 443 dda_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 444 { 445 int instance = ddi_get_instance(dip); 446 dda_t *dda; 447 448 switch (cmd) { 449 case DDI_ATTACH: 450 if (ddi_soft_state_zalloc(dda_state, instance) != DDI_SUCCESS) { 451 cmn_err(CE_WARN, "%d attach soft state alloc failed", 452 instance); 453 return (DDI_FAILURE); 454 } 455 456 if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) { 457 ddi_soft_state_free(dda_state, instance); 458 cmn_err(CE_WARN, "%d attach get soft state failed", 459 instance); 460 return (DDI_FAILURE); 461 } 462 dda->dda_inst = -1; 463 464 if (ddi_create_minor_node(dip, "bn", S_IFCHR, 465 instance, DDI_PSEUDO, 0) != DDI_SUCCESS) { 466 ddi_soft_state_free(dda_state, instance); 467 cmn_err(CE_WARN, "%d attach create minor node failed", 468 instance); 469 return (DDI_FAILURE); 470 } 471 472 dda->dda_dip = dip; 473 dda->dda_inst = instance; 474 mutex_init(&dda->dda_mutex, NULL, MUTEX_DRIVER, NULL); 475 dda_set_unloaded(dda); 476 return (DDI_SUCCESS); 477 default: 478 return (DDI_FAILURE); 479 } 480 } 481 482 /* 483 * dda_detach 484 * 485 * Parameters: 486 * - dip: Device information structure. 487 * - cmd: Detach command. 488 * 489 * Globals: 490 * - dda_state: Pointer to list of DDA drives. 491 * 492 * Get drive instance from the list of drives. 493 * If media is loaded in the drive then unload the media. 494 * Remove minor device node. 495 * Release exclusive access mutex. 496 * Release memory. 497 * 498 * Return Values: 499 * DDI_SUCCESS : success 500 * DDI_FAILURE : failure 501 * 502 */ 503 static int 504 dda_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 505 { 506 int instance = ddi_get_instance(dip); 507 dda_t *dda; 508 509 switch (cmd) { 510 case DDI_DETACH: 511 if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) { 512 cmn_err(CE_WARN, "%d detach get soft state failed", 513 instance); 514 return (DDI_FAILURE); 515 } 516 if (dda->dda_loaded) { 517 dda->dda_cred = kcred; 518 (void) dda_tape_unload(dda); 519 } 520 ddi_remove_minor_node(dip, "bn"); 521 mutex_destroy(&dda->dda_mutex); 522 ddi_soft_state_free(dda_state, instance); 523 return (DDI_SUCCESS); 524 default: 525 return (DDI_FAILURE); 526 } 527 } 528 529 /* 530 * dda_getinfo 531 * 532 * Parameters: 533 * - dip: Device information structure. 534 * - cmd: Information command. 535 * - arg: Device structure. 536 * - resultp: Pointer for information requested. 537 * 538 * Globals: 539 * - dda_state: List of DDA emulated tape drives. 540 * 541 * Return drive instance information to the kernel. 542 * 543 * Return Values: 544 * DDI_SUCCESS : success 545 * DDI_FAILURE : failure 546 * 547 */ 548 /*ARGSUSED*/ 549 static int 550 dda_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 551 { 552 int instance = getminor((dev_t)arg); 553 dda_t *dda; 554 555 switch (cmd) { 556 case DDI_INFO_DEVT2DEVINFO: 557 if ((dda = ddi_get_soft_state(dda_state, 558 instance)) == NULL) { 559 cmn_err(CE_WARN, "%d getinfo get soft state failed", 560 instance); 561 *resultp = NULL; 562 return (DDI_FAILURE); 563 } 564 *resultp = dda->dda_dip; 565 return (DDI_SUCCESS); 566 case DDI_INFO_DEVT2INSTANCE: 567 *resultp = (void *)(uintptr_t)instance; 568 return (DDI_SUCCESS); 569 default: 570 *resultp = NULL; 571 return (DDI_FAILURE); 572 } 573 } 574 575 /* Main entry points */ 576 577 /* 578 * dda_open 579 * 580 * Parameters: 581 * - devp: Device structure. 582 * - flag: Device open mode. 583 * - otyp: Character or block device open. 584 * - credp: User credentials. 585 * 586 * Globals: 587 * - dda_state: List of DDA emulated tape drives. 588 * 589 * Verify character device open. 590 * Get drive structure. 591 * Lock drive to ensure sequential access. 592 * If drive is already in-use then unlock drive and return busy. 593 * If drive is not loaded then prevent read only or write non-blocking 594 * access to the drive. 595 * Save open process pid as the test for drive in-use. 596 * Set read only mode. 597 * Unlock drive. 598 * 599 * Return Values: 600 * DDI_SUCCESS : success 601 * DDI_FAILURE : failure 602 * 603 */ 604 static int 605 dda_open(dev_t *devp, int flag, int otyp, cred_t *credp) 606 { 607 int instance = getminor(*devp); 608 dda_t *dda; 609 610 if (otyp != OTYP_CHR) { 611 return (EINVAL); 612 } 613 if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) { 614 return (ENXIO); 615 } 616 mutex_enter(&dda->dda_mutex); 617 if (dda->dda_pid) { 618 /* 619 * The real tape driver does not allow a drive to be 620 * opened multiple times. 621 */ 622 mutex_exit(&dda->dda_mutex); 623 return (EBUSY); 624 } 625 if (!dda->dda_loaded) { 626 /* 627 * The real tape driver does not allow an unloaded tape 628 * drive to be opened in read only or blocking mode. 629 */ 630 if ((flag & FWRITE) == 0 || 631 ((flag & FWRITE) == FWRITE && 632 (flag & (FNDELAY | FNONBLOCK)) == 0)) { 633 mutex_exit(&dda->dda_mutex); 634 return (EIO); 635 } 636 } 637 638 /* user credentials */ 639 dda->dda_cred = credp; 640 641 /* set open flag */ 642 dda->dda_pid = ddi_get_pid(); 643 644 /* get read only mode */ 645 dda->dda_read_only = (flag & FWRITE) ? 0 : 1; 646 DDA_DEBUG2((dda_pid, 647 int, dda->dda_inst, 648 pid_t, dda->dda_pid)); 649 mutex_exit(&dda->dda_mutex); 650 return (0); 651 } 652 653 /* 654 * dda_open 655 * 656 * Parameters: 657 * - devp: Device structure. 658 * - flag: Device open mode. 659 * - otyp: Character or block device open. 660 * - credp: User credentials. 661 * 662 * Globals: 663 * - dda_state: List of DDA emulated tape drives. 664 * 665 * Verify character device close. 666 * Get drive structure. 667 * Lock drive to ensure sequential access. 668 * Append filemark if loaded and needed. 669 * Unlock drive. 670 * 671 * Return Values: 672 * 0 : success 673 * errno : failure 674 * 675 */ 676 static int 677 dda_close(dev_t dev, int flag, int otyp, cred_t *credp) 678 { 679 int instance = getminor(dev); 680 dda_t *dda; 681 int err = 0; 682 683 if (otyp != OTYP_CHR) { 684 return (EINVAL); 685 } 686 if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) { 687 return (ENXIO); 688 } 689 mutex_enter(&dda->dda_mutex); 690 dda->dda_cred = credp; 691 DDA_DEBUG2((dda_pid, 692 int, dda->dda_inst, 693 pid_t, dda->dda_pid)); 694 if (DDA_GET_FM_FWD_PEND(dda)) { 695 DDA_CLR_FM_FWD_PEND(dda); 696 DDA_CLR_FM_NEEDED(dda); 697 } 698 if ((flag & FWRITE) && 699 DDA_GET_FM_NEEDED(dda) && 700 DDA_GET_READ_ONLY(dda) == 0) { 701 err = dda_tape_wfm(dda, 1); 702 } else { 703 dda->dda_resid = 0; 704 } 705 dda->dda_pid = 0; 706 /* only reset record size at bot for bsb no rewind */ 707 if (DDA_IS_BOT(dda)) { 708 dda->dda_rec_size = 0; 709 dda->dda_ili = 0; 710 } 711 mutex_exit(&dda->dda_mutex); 712 return (err); 713 } 714 715 /* 716 * dda_read 717 * 718 * Parameters: 719 * - dev: Device structure. 720 * - uio: Vector I/O operations. 721 * - credp: User credentials. 722 * 723 * Globals: 724 * - dda_state: List of DDA emulated tape drives. 725 * 726 * Get drive structure. 727 * Lock drive to ensure sequential access. 728 * Call tape read function. 729 * Unlock drive. 730 * 731 * Return Values: 732 * 0 : success 733 * errno : failure 734 * 735 */ 736 static int 737 dda_read(dev_t dev, struct uio *uio, cred_t *credp) 738 { 739 int instance = getminor(dev); 740 dda_t *dda; 741 int err; 742 743 if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) { 744 return (ENXIO); 745 } 746 mutex_enter(&dda->dda_mutex); 747 dda->dda_cred = credp; 748 err = dda_tape_read(dda, uio); 749 mutex_exit(&dda->dda_mutex); 750 return (err); 751 } 752 753 /* 754 * dda_write 755 * 756 * Parameters: 757 * - dev: Device structure. 758 * - uio: Vector I/O operations. 759 * - credp: User credentials. 760 * 761 * Globals: 762 * - dda_state: List of DDA emulated tape drives. 763 * 764 * Get drive structure. 765 * Lock drive to ensure sequential access. 766 * Call tape write function. 767 * Unlock drive. 768 * 769 * Return Values: 770 * 0 : success 771 * errno : failure 772 * 773 */ 774 static int 775 dda_write(dev_t dev, struct uio *uio, cred_t *credp) 776 { 777 int instance = getminor(dev); 778 dda_t *dda; 779 int err; 780 781 if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) { 782 return (ENXIO); 783 } 784 mutex_enter(&dda->dda_mutex); 785 dda->dda_cred = credp; 786 err = dda_tape_write(dda, uio); 787 mutex_exit(&dda->dda_mutex); 788 return (err); 789 } 790 791 /* 792 * dda_ioctl 793 * 794 * Parameters: 795 * - dev: Device structure. 796 * - cmd: DDA or MTIO command. 797 * - flag: User data model. 798 * - credp: User credentials. 799 * - rvalp: Return error number. 800 * 801 * Globals: 802 * - dda_state: List of DDA emulated tape drives. 803 * 804 * Interface to execute DDA commands and selected MTIO commands. 805 * 806 * The DDA commands perform operations normally handled by a real tape 807 * drive such as load, capacity, write protect tab, read block limits, 808 * loaded cartridge pcl. 809 * 810 * MTIO commands support unload, motion, write filemark, erase, drive status, 811 * drive type, record size, and setting incorrect length indicator. 812 * 813 * Get drive structure. 814 * Determine command to execute. 815 * Lock drive to ensure sequential access. 816 * Call function to emulate MTIO functionality. 817 * Unlock drive. 818 * 819 * Return Values: 820 * Cartridge write protect command: 821 * 0 : read only 822 * -1 : read write 823 * 824 * All other commands: 825 * 0 : success 826 * errno : failure 827 * 828 * Note: 829 * DDA emulates BSD no-rewind behavior. 830 * 831 */ 832 /*ARGSUSED5*/ 833 static int 834 dda_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) 835 { 836 int instance = getminor(dev); 837 dda_t *dda; 838 int tmp; 839 char *path; 840 int err = 0; 841 842 843 if ((dda = ddi_get_soft_state(dda_state, instance)) == NULL) { 844 return (ENXIO); 845 } 846 847 switch (cmd) { 848 case DDA_CMD_LOAD: { 849 path = kmem_alloc(PATH_MAX, KM_SLEEP); 850 if (ddi_copyin((void *)arg, path, PATH_MAX, flag)) { 851 err = EFAULT; 852 } else { 853 mutex_enter(&dda->dda_mutex); 854 dda->dda_cred = credp; 855 err = dda_tape_load(dda, path); 856 mutex_exit(&dda->dda_mutex); 857 } 858 kmem_free(path, PATH_MAX); 859 return (err); 860 } 861 case DDA_CMD_NAME: { 862 mutex_enter(&dda->dda_mutex); 863 if (!dda->dda_loaded) { 864 mutex_exit(&dda->dda_mutex); 865 return (EIO); 866 } 867 path = kmem_alloc(PATH_MAX, KM_SLEEP); 868 (void) snprintf(path, PATH_MAX, "%s", dda->dda_path); 869 mutex_exit(&dda->dda_mutex); 870 if (ddi_copyout(path, (void *)arg, PATH_MAX, flag)) { 871 err = EFAULT; 872 } 873 kmem_free(path, PATH_MAX); 874 return (err); 875 } 876 case DDA_CMD_CAPACITY: { 877 dda_capacity_t capacity; 878 879 mutex_enter(&dda->dda_mutex); 880 dda->dda_cred = credp; 881 if (!dda->dda_loaded) { 882 mutex_exit(&dda->dda_mutex); 883 return (EIO); 884 } 885 dda->dda_resid = 0; 886 capacity.dda_capacity = dda->dda_metadata.dda_capacity; 887 if (err = dda_tape_capacity(dda, &capacity.dda_space)) { 888 mutex_exit(&dda->dda_mutex); 889 return (err); 890 } 891 mutex_exit(&dda->dda_mutex); 892 if (ddi_copyout(&capacity, (void *)arg, 893 sizeof (dda_capacity_t), flag)) { 894 return (EFAULT); 895 } 896 return (0); 897 } 898 case DDA_CMD_WPROTECT: { 899 mutex_enter(&dda->dda_mutex); 900 if (!dda->dda_loaded) { 901 mutex_exit(&dda->dda_mutex); 902 return (EIO); 903 } 904 dda->dda_resid = 0; 905 if (DDA_GET_WPROTECT(dda) != 0) { 906 mutex_exit(&dda->dda_mutex); 907 /* write protect tab on */ 908 return (0); 909 } 910 mutex_exit(&dda->dda_mutex); 911 /* write protect tab off */ 912 return (-1); 913 } 914 case DDA_CMD_BLKLMT: { 915 dda_blklmt_t blklmt; 916 917 blklmt.dda_blkmax = DDA_MAX_REC_SIZE; 918 blklmt.dda_blkmin = 1; 919 920 mutex_enter(&dda->dda_mutex); 921 dda->dda_resid = 0; 922 mutex_exit(&dda->dda_mutex); 923 924 if (ddi_copyout(&blklmt, (void *)arg, 925 sizeof (dda_blklmt_t), flag)) { 926 return (EFAULT); 927 } 928 return (0); 929 } 930 case USCSICMD: { 931 return (ENOTTY); 932 } 933 case MTIOCGETPOS: { 934 tapepos_t pos; 935 int64_t blkno; 936 937 mutex_enter(&dda->dda_mutex); 938 dda->dda_cred = credp; 939 if (!dda->dda_loaded) { 940 mutex_exit(&dda->dda_mutex); 941 return (EIO); 942 } 943 dda->dda_resid = 0; 944 945 bzero(&pos, sizeof (tapepos_t)); 946 pos.lgclblkno = DDA_LBA(dda); 947 pos.fileno = dda_get_fileno(dda); 948 (void) dda_get_blkno(dda, &blkno); 949 pos.blkno = (UINT32_MAX & blkno); 950 pos.pmode = logical; 951 952 mutex_exit(&dda->dda_mutex); 953 if (ddi_copyout(&pos, (void *)arg, 954 sizeof (tapepos_t), flag)) { 955 return (EFAULT); 956 } 957 return (0); 958 } 959 case MTIOCRESTPOS: { 960 tapepos_t pos; 961 962 if (ddi_copyin((void *)arg, &pos, 963 sizeof (tapepos_t), flag)) { 964 return (EFAULT); 965 } 966 mutex_enter(&dda->dda_mutex); 967 dda->dda_cred = credp; 968 if (!dda->dda_loaded) { 969 mutex_exit(&dda->dda_mutex); 970 return (EIO); 971 } 972 if (pos.pmode != logical) { 973 mutex_exit(&dda->dda_mutex); 974 return (EINVAL); 975 } 976 err = dda_tape_locate(dda, pos.lgclblkno); 977 mutex_exit(&dda->dda_mutex); 978 return (err); 979 } 980 case MTIOCLTOP: { 981 struct mtlop local; 982 int rval; 983 984 if (ddi_copyin((void *)arg, &local, sizeof (local), flag)) { 985 return (EFAULT); 986 } 987 988 mutex_enter(&dda->dda_mutex); 989 dda->dda_cred = credp; 990 rval = dda_tape_op(dda, &local); 991 mutex_exit(&dda->dda_mutex); 992 993 if (ddi_copyout(&local, (void *)arg, sizeof (local), flag)) { 994 rval = EFAULT; 995 } 996 return (rval); 997 } 998 case MTIOCTOP: { 999 #ifdef _MULTI_DATAMODEL 1000 /* 1001 * For use when a 32 bit app makes a call into a 1002 * 64 bit ioctl 1003 */ 1004 struct mtop32 mtop_32_for_64; 1005 #endif /* _MULTI_DATAMODEL */ 1006 struct mtop passed; 1007 struct mtlop local; 1008 int rval = 0; 1009 1010 #ifdef _MULTI_DATAMODEL 1011 switch (ddi_model_convert_from(flag & FMODELS)) { 1012 case DDI_MODEL_ILP32: 1013 if (ddi_copyin((void *)arg, &mtop_32_for_64, 1014 sizeof (struct mtop32), flag)) { 1015 return (EFAULT); 1016 } 1017 local.mt_op = mtop_32_for_64.mt_op; 1018 local.mt_count = (int64_t)mtop_32_for_64.mt_count; 1019 break; 1020 1021 case DDI_MODEL_NONE: 1022 if (ddi_copyin((void *)arg, &passed, 1023 sizeof (passed), flag)) { 1024 return (EFAULT); 1025 } 1026 local.mt_op = passed.mt_op; 1027 /* prevent sign extension */ 1028 local.mt_count = (UINT32_MAX & passed.mt_count); 1029 break; 1030 } 1031 1032 #else /* ! _MULTI_DATAMODEL */ 1033 if (ddi_copyin((void *)arg, &passed, sizeof (passed), flag)) { 1034 return (EFAULT); 1035 } 1036 local.mt_op = passed.mt_op; 1037 /* prevent sign extension */ 1038 local.mt_count = (UINT32_MAX & passed.mt_count); 1039 #endif /* _MULTI_DATAMODEL */ 1040 1041 mutex_enter(&dda->dda_mutex); 1042 dda->dda_cred = credp; 1043 rval = dda_tape_op(dda, &local); 1044 mutex_exit(&dda->dda_mutex); 1045 1046 #ifdef _MULTI_DATAMODEL 1047 switch (ddi_model_convert_from(flag & FMODELS)) { 1048 case DDI_MODEL_ILP32: 1049 if (((uint64_t)local.mt_count) > UINT32_MAX) { 1050 rval = ERANGE; 1051 break; 1052 } 1053 /* 1054 * Convert 64 bit back to 32 bit before doing 1055 * copyout. This is what the ILP32 app expects. 1056 */ 1057 mtop_32_for_64.mt_op = local.mt_op; 1058 mtop_32_for_64.mt_count = (daddr32_t)local.mt_count; 1059 1060 if (ddi_copyout(&mtop_32_for_64, (void *)arg, 1061 sizeof (struct mtop32), flag)) { 1062 rval = EFAULT; 1063 } 1064 break; 1065 1066 case DDI_MODEL_NONE: 1067 passed.mt_count = local.mt_count; 1068 passed.mt_op = local.mt_op; 1069 if (ddi_copyout(&passed, (void *)arg, 1070 sizeof (passed), flag)) { 1071 rval = EFAULT; 1072 } 1073 break; 1074 } 1075 #else /* ! _MULTI_DATAMODE */ 1076 if (((uint64_t)local.mt_count) > UINT32_MAX) { 1077 rval = ERANGE; 1078 } else { 1079 passed.mt_op = local.mt_op; 1080 passed.mt_count = (daddr32_t)local.mt_count; 1081 if (ddi_copyout(&passed, (void *)arg, 1082 sizeof (passed), flag)) { 1083 rval = EFAULT; 1084 } 1085 } 1086 #endif /* _MULTI_DATAMODE */ 1087 return (rval); 1088 } 1089 case MTIOCGET: { 1090 #ifdef _MULTI_DATAMODEL 1091 struct mtget32 mtg_local32; 1092 struct mtget32 *mtget_32 = &mtg_local32; 1093 #endif /* _MULTI_DATAMODEL */ 1094 struct mtget mtg_local; 1095 struct mtget *mtget = &mtg_local; 1096 1097 bzero(mtget, sizeof (struct mtget)); 1098 mutex_enter(&dda->dda_mutex); 1099 dda->dda_cred = credp; 1100 if (!dda->dda_loaded) { 1101 mtget->mt_erreg = KEY_NOT_READY; 1102 mtget->mt_resid = 0; 1103 mtget->mt_fileno = -1; 1104 mtget->mt_blkno = 0; 1105 } else { 1106 mtget->mt_erreg = dda->dda_status; 1107 mtget->mt_resid = dda->dda_resid; 1108 mtget->mt_fileno = dda_get_fileno(dda); 1109 mtget->mt_blkno = dda->dda_blkno; 1110 } 1111 mtget->mt_type = MT_ISOTHER; 1112 mtget->mt_flags = MTF_SCSI /* | MTF_ASF */; 1113 mtget->mt_bf = 1; 1114 1115 dda->dda_status = 0; 1116 dda->dda_resid = 0; 1117 tmp = sizeof (struct mtget); 1118 1119 DDA_CLR_FM_NEEDED(dda); 1120 DDA_DEBUG3((dda_cmd_status, 1121 int, dda->dda_inst, 1122 short, mtget->mt_erreg, 1123 int32_t, mtget->mt_resid)); 1124 mutex_exit(&dda->dda_mutex); 1125 1126 #ifdef _MULTI_DATAMODEL 1127 switch (ddi_model_convert_from(flag & FMODELS)) { 1128 case DDI_MODEL_ILP32: 1129 mtget_32->mt_erreg = mtget->mt_erreg; 1130 mtget_32->mt_resid = mtget->mt_resid; 1131 mtget_32->mt_dsreg = mtget->mt_dsreg; 1132 mtget_32->mt_fileno = (daddr32_t)mtget->mt_fileno; 1133 mtget_32->mt_blkno = (daddr32_t)mtget->mt_blkno; 1134 mtget_32->mt_type = mtget->mt_type; 1135 mtget_32->mt_flags = mtget->mt_flags; 1136 mtget_32->mt_bf = mtget->mt_bf; 1137 1138 if (ddi_copyout(mtget_32, (void *)arg, 1139 sizeof (struct mtget32), flag)) { 1140 return (EFAULT); 1141 } 1142 break; 1143 case DDI_MODEL_NONE: 1144 if (ddi_copyout(mtget, (void *)arg, tmp, flag)) { 1145 return (EFAULT); 1146 } 1147 break; 1148 } 1149 #else /* ! _MULTI_DATAMODE */ 1150 if (ddi_copyout(mtget, (void *)arg, tmp, flag)) { 1151 return (EFAULT); 1152 } 1153 #endif /* _MULTI_DATAMODE */ 1154 1155 return (0); 1156 } 1157 case MTIOCGETDRIVETYPE: { 1158 #ifdef _MULTI_DATAMODEL 1159 struct mtdrivetype_request32 mtdtrq32; 1160 #endif /* _MULTI_DATAMODEL */ 1161 struct mtdrivetype_request mtdtrq; 1162 struct mtdrivetype mtdrtyp; 1163 struct mtdrivetype *mtdt = &mtdrtyp; 1164 1165 #ifdef _MULTI_DATAMODEL 1166 switch (ddi_model_convert_from(flag & FMODELS)) { 1167 case DDI_MODEL_ILP32: 1168 { 1169 if (ddi_copyin((void *)arg, &mtdtrq32, 1170 sizeof (struct mtdrivetype_request32), flag)) { 1171 return (EFAULT); 1172 } 1173 mtdtrq.size = mtdtrq32.size; 1174 mtdtrq.mtdtp = 1175 (struct mtdrivetype *)(uintptr_t)mtdtrq32.mtdtp; 1176 break; 1177 } 1178 case DDI_MODEL_NONE: 1179 if (ddi_copyin((void *)arg, &mtdtrq, 1180 sizeof (struct mtdrivetype_request), flag)) { 1181 return (EFAULT); 1182 } 1183 break; 1184 } 1185 #else /* ! _MULTI_DATAMODEL */ 1186 if (ddi_copyin((void *)arg, &mtdtrq, 1187 sizeof (struct mtdrivetype_request), flag)) { 1188 return (EFAULT); 1189 } 1190 #endif /* _MULTI_DATAMODEL */ 1191 1192 if (mtdtrq.size < 0) { 1193 return (EINVAL); 1194 } 1195 bzero(mtdt, sizeof (struct mtdrivetype)); 1196 (void) strncpy(mtdt->name, DDA_ST_NAME, ST_NAMESIZE); 1197 (void) strncpy(mtdt->vid, DDA_VID, VIDPIDLEN); 1198 mtdt->type = MT_ISOTHER; 1199 mtdt->bsize = 0; 1200 mtdt->options = ST_VARIABLE | 1201 ST_READ_IGNORE_ILI | 1202 ST_BSF | 1203 ST_BSR | 1204 ST_KNOWS_EOD | 1205 ST_UNLOADABLE | 1206 ST_NO_RESERVE_RELEASE; 1207 tmp = sizeof (struct mtdrivetype); 1208 if (mtdtrq.size < tmp) 1209 tmp = mtdtrq.size; 1210 if (ddi_copyout(mtdt, mtdtrq.mtdtp, tmp, flag)) { 1211 return (EFAULT); 1212 } 1213 mutex_enter(&dda->dda_mutex); 1214 DDA_CLR_FM_NEEDED(dda); 1215 mutex_exit(&dda->dda_mutex); 1216 return (0); 1217 } 1218 case MTIOCREADIGNOREILI: { 1219 int set_ili; 1220 1221 if (ddi_copyin((void *)arg, &set_ili, 1222 sizeof (set_ili), flag)) { 1223 return (EFAULT); 1224 } 1225 1226 mutex_enter(&dda->dda_mutex); 1227 if (!dda->dda_loaded) { 1228 mutex_exit(&dda->dda_mutex); 1229 return (EIO); 1230 } 1231 if (dda->dda_rec_size) { 1232 mutex_exit(&dda->dda_mutex); 1233 return (ENOTTY); 1234 } 1235 if (set_ili != 0 && set_ili != 1) { 1236 mutex_exit(&dda->dda_mutex); 1237 return (EINVAL); 1238 } 1239 dda->dda_ili = set_ili; 1240 DDA_DEBUG2((dda_cmd_ili, 1241 int, dda->dda_inst, 1242 int, dda->dda_ili)); 1243 DDA_CLR_FM_NEEDED(dda); 1244 mutex_exit(&dda->dda_mutex); 1245 return (0); 1246 } 1247 1248 } /* switch end */ 1249 1250 return (ENOTTY); 1251 } 1252 1253 /* tape operations */ 1254 1255 /* 1256 * dda_tape_op 1257 * 1258 * Parameters: 1259 * - dda: DDA tape drive. 1260 * - mtop: Magnetic tape operation structure. 1261 * 1262 * Perform the MTIO command by calling the appropriate DDA function. 1263 * 1264 * Return Values: 1265 * 0 : success 1266 * errno : failure 1267 * 1268 */ 1269 static int 1270 dda_tape_op(dda_t *dda, struct mtlop *mtop) 1271 { 1272 int err; 1273 1274 switch (mtop->mt_op) { 1275 case MTTELL: 1276 if (!dda->dda_loaded) { 1277 return (EIO); 1278 } 1279 mtop->mt_count = DDA_LBA(dda); 1280 return (0); 1281 case MTSEEK: { 1282 int64_t lba; 1283 1284 if (!dda->dda_loaded) { 1285 return (EIO); 1286 } 1287 if (err = dda_tape_locate(dda, mtop->mt_count)) { 1288 lba = DDA_LBA(dda); 1289 } 1290 if (err && mtop->mt_count != lba) { 1291 /* turn seek into tell command */ 1292 mtop->mt_op = MTTELL; 1293 mtop->mt_count = lba; 1294 } 1295 return (err); 1296 } 1297 case MTWEOF: 1298 if (mtop->mt_count < 0) { 1299 return (EINVAL); 1300 } 1301 err = dda_tape_wfm(dda, mtop->mt_count); 1302 return (err); 1303 case MTFSF: 1304 err = dda_tape_fsf(dda, mtop->mt_count); 1305 return (err); 1306 case MTBSF: 1307 err = dda_tape_bsf(dda, mtop->mt_count); 1308 return (err); 1309 case MTFSR: 1310 err = dda_tape_fsr(dda, mtop->mt_count); 1311 return (err); 1312 case MTBSR: 1313 err = dda_tape_bsr(dda, mtop->mt_count); 1314 return (err); 1315 case MTRETEN: 1316 case MTREW: 1317 err = dda_tape_rewind(dda); 1318 return (err); 1319 case MTNOP: 1320 DDA_DEBUG3((dda_cmd_nop, 1321 int, dda->dda_inst, 1322 int64_t, DDA_LBA(dda), 1323 int64_t, dda_get_fileno(dda))); 1324 return (0); 1325 case MTERASE: 1326 err = dda_tape_erase(dda); 1327 return (err); 1328 case MTEOM: 1329 err = dda_tape_eom(dda); 1330 return (err); 1331 case MTOFFL: 1332 err = dda_tape_unload(dda); 1333 return (err); 1334 case MTSRSZ: 1335 if (mtop->mt_count < 0) { 1336 return (EINVAL); 1337 } 1338 if (mtop->mt_count > DDA_MAX_REC_SIZE) { 1339 return (EINVAL); 1340 } 1341 if (!dda->dda_loaded) { 1342 return (EIO); 1343 } 1344 dda->dda_rec_size = mtop->mt_count; 1345 1346 if (dda->dda_rec_size) { 1347 dda->dda_ili = 0; 1348 } 1349 1350 DDA_DEBUG3((dda_cmd_srsz, 1351 int, dda->dda_inst, 1352 int32_t, dda->dda_rec_size, 1353 int, dda->dda_ili)); 1354 DDA_CLR_FM_NEEDED(dda); 1355 return (0); 1356 case MTGRSZ: 1357 if (!dda->dda_loaded) { 1358 return (EIO); 1359 } 1360 mtop->mt_count = dda->dda_rec_size; 1361 DDA_DEBUG3((dda_cmd_grsz, 1362 int, dda->dda_inst, 1363 int32_t, dda->dda_rec_size, 1364 int, dda->dda_ili)); 1365 return (0); 1366 } 1367 return (ENOTTY); 1368 } 1369 1370 /* 1371 * dda_tape_load 1372 * 1373 * Parameters: 1374 * - dda: DDA tape drive. 1375 * - path: DDA media directory. 1376 * 1377 * If the drive is already loaded and the path is different then 1378 * reject the load command and return. 1379 * If the drive is already loaded and the path is the same then 1380 * accept the load command and return. 1381 * If not loaded open the DDA media files. 1382 * If write protect tab is set read only. 1383 * Calculate data file offset to early warning. 1384 * Set unit attention status. 1385 * Set truncate need flag since the media is at BOT. 1386 * DDA media is now loaded and ready for access. 1387 * 1388 * Return Values: 1389 * 0 : success 1390 * errno : failure 1391 * 1392 */ 1393 static int 1394 dda_tape_load(dda_t *dda, char *path) 1395 { 1396 char *fname; 1397 int err; 1398 short status; 1399 1400 1401 dda->dda_status = 0; 1402 dda->dda_resid = 0; 1403 if (dda->dda_loaded) { 1404 if (strcmp(dda->dda_path, path) != 0) { 1405 cmn_err(CE_CONT, 1406 "%d loaded already %s", 1407 dda->dda_inst, dda->dda_path); 1408 1409 DDA_DEBUG2((dda_cmd_loaded_already, 1410 int, dda->dda_inst, 1411 char *, dda->dda_path)); 1412 1413 dda->dda_status = KEY_ILLEGAL_REQUEST; 1414 return (EIO); 1415 } 1416 cmn_err(CE_CONT, 1417 "%d load resume %s", 1418 dda->dda_inst, dda->dda_path); 1419 1420 DDA_DEBUG2((dda_cmd_load_resume, 1421 int, dda->dda_inst, 1422 char *, dda->dda_path)); 1423 1424 return (0); 1425 } 1426 1427 fname = kmem_alloc(PATH_MAX, KM_SLEEP); 1428 1429 /* reset media data, the drive data is not reset */ 1430 bzero(dda, offsetof(dda_t, dda_inst)); 1431 (void) snprintf(dda->dda_path, PATH_MAX, "%s", path); 1432 1433 (void) snprintf(fname, PATH_MAX, "%s/%s", dda->dda_path, 1434 DDA_METADATA_FNAME); 1435 if (err = dda_vn_open(dda, &dda->dda_metadata_vp, fname)) { 1436 goto load_error; 1437 } 1438 if (err = dda_vn_lock(dda, dda->dda_metadata_vp, F_WRLCK)) { 1439 goto load_error; 1440 } 1441 if (err = dda_vn_read(dda, dda->dda_metadata_vp, &dda->dda_metadata, 1442 sizeof (dda_metadata_t), 0)) { 1443 goto load_error; 1444 } 1445 DDA_BE_METADATA(dda->dda_metadata, dda->dda_metadata); 1446 1447 (void) snprintf(fname, PATH_MAX, "%s/%s", dda->dda_path, 1448 DDA_INDEX_FNAME); 1449 if (err = dda_vn_open(dda, &dda->dda_index_vp, fname)) { 1450 goto load_error; 1451 } 1452 if (err = dda_vn_size(dda, dda->dda_index_vp, &dda->dda_index_fsize)) { 1453 goto load_error; 1454 } 1455 if (err = dda_read_index(dda)) { 1456 goto load_error; 1457 } 1458 1459 (void) snprintf(fname, PATH_MAX, "%s/%s", dda->dda_path, 1460 DDA_DATA_FNAME); 1461 if (err = dda_vn_open(dda, &dda->dda_data_vp, fname)) { 1462 goto load_error; 1463 } 1464 if (err = dda_vn_size(dda, dda->dda_data_vp, &dda->dda_data_fsize)) { 1465 goto load_error; 1466 } 1467 1468 /* non-floating point early warning to eom percentage calculation */ 1469 dda->dda_early_warn = 1470 (dda->dda_metadata.dda_capacity / 100) * DDA_EARLY_WARN; 1471 if (dda->dda_early_warn < DDA_MAX_REC_SIZE) { 1472 dda->dda_early_warn = DDA_MAX_REC_SIZE; 1473 if (dda->dda_early_warn > dda->dda_metadata.dda_capacity) { 1474 dda->dda_early_warn = dda->dda_metadata.dda_capacity; 1475 } 1476 } 1477 1478 /* set media loaded */ 1479 dda->dda_status = KEY_UNIT_ATTENTION; 1480 dda->dda_loaded = 1; 1481 DDA_SET_TRUNC(dda); 1482 1483 cmn_err(CE_CONT, "%d loaded %s", 1484 dda->dda_inst, dda->dda_path); 1485 1486 DDA_DEBUG2((dda_cmd_load, 1487 int, dda->dda_inst, 1488 char *, path)); 1489 1490 kmem_free(fname, PATH_MAX); 1491 return (0); 1492 1493 load_error: 1494 cmn_err(CE_WARN, "%d load %s error %d", 1495 dda->dda_inst, dda->dda_path, err); 1496 1497 DDA_DEBUG3((dda_cmd_load_err, 1498 int, dda->dda_inst, 1499 char *, path, 1500 int, err)); 1501 1502 /* cleanup */ 1503 status = dda->dda_status; 1504 if (dda->dda_index_vp) { 1505 (void) dda_vn_close(dda, &dda->dda_index_vp); 1506 } 1507 if (dda->dda_data_vp) { 1508 (void) dda_vn_close(dda, &dda->dda_data_vp); 1509 } 1510 if (dda->dda_metadata_vp) { 1511 (void) dda_vn_lock(dda, dda->dda_metadata_vp, F_UNLCK); 1512 (void) dda_vn_close(dda, &dda->dda_metadata_vp); 1513 } 1514 dda_set_unloaded(dda); 1515 dda->dda_status = status; 1516 kmem_free(fname, PATH_MAX); 1517 return (err); 1518 } 1519 1520 /* 1521 * dda_tape_unload 1522 * 1523 * Parameters: 1524 * - dda: DDA tape drive. 1525 * 1526 * Write filemark if needed to emulate st bsd mode. 1527 * Unload media from the drive. 1528 * Report first error encounter. 1529 * 1530 * Return Values: 1531 * 0 : success 1532 * errno : failure 1533 * 1534 */ 1535 static int 1536 dda_tape_unload(dda_t *dda) 1537 { 1538 int rc; 1539 int err = 0; 1540 short status; 1541 1542 1543 /* 1544 * Close all files, report first error 1545 */ 1546 1547 if (!dda->dda_loaded) { 1548 return (EIO); 1549 } 1550 1551 dda->dda_status = 0; 1552 dda->dda_resid = 0; 1553 1554 if (err = dda_write_index(dda)) { 1555 status = dda->dda_status; 1556 } 1557 1558 if (DDA_GET_FM_NEEDED(dda)) { 1559 if (rc = dda_tape_wfm(dda, 1)) { 1560 if (err == 0) { 1561 err = rc; 1562 status = dda->dda_status; 1563 } 1564 } 1565 } 1566 1567 if (rc = dda_vn_close(dda, &dda->dda_index_vp)) { 1568 if (err == 0) { 1569 err = rc; 1570 status = dda->dda_status; 1571 } 1572 } 1573 1574 if (rc = dda_vn_close(dda, &dda->dda_data_vp)) { 1575 if (err == 0) { 1576 err = rc; 1577 status = dda->dda_status; 1578 } 1579 } 1580 1581 (void) dda_vn_lock(dda, dda->dda_metadata_vp, F_UNLCK); 1582 if (rc = dda_vn_close(dda, &dda->dda_metadata_vp)) { 1583 if (err == 0) { 1584 err = rc; 1585 status = dda->dda_status; 1586 } 1587 } 1588 1589 dda->dda_status = status; 1590 1591 if (err == 0) { 1592 cmn_err(CE_CONT, "%d unloaded %s", 1593 dda->dda_inst, dda->dda_path); 1594 1595 DDA_DEBUG2((dda_cmd_unload, 1596 int, dda->dda_inst, 1597 char *, dda->dda_path)); 1598 } else { 1599 cmn_err(CE_WARN, "%d unloaded %s with error %d", 1600 dda->dda_inst, dda->dda_path, err); 1601 1602 DDA_DEBUG3((dda_cmd_unload_err, 1603 int, dda->dda_inst, 1604 char *, dda->dda_path, 1605 int, err)); 1606 } 1607 1608 dda_set_unloaded(dda); 1609 return (err); 1610 } 1611 1612 /* support routines */ 1613 1614 /* 1615 * dda_set_unloaded 1616 * 1617 * Parameters: 1618 * - dda: DDA tape drive. 1619 * 1620 * Set DDA drive unloaded. 1621 * Zero DDA media structure members. 1622 * Set fileno to -1 for status. 1623 * 1624 * Return Values: 1625 * None 1626 * 1627 */ 1628 static void 1629 dda_set_unloaded(dda_t *dda) 1630 { 1631 bzero(dda, offsetof(dda_t, dda_inst)); 1632 dda->dda_index.dda_fileno = -1; 1633 dda->dda_loaded = 0; 1634 } 1635 1636 /* 1637 * dda_get_fileno 1638 * 1639 * Parameters: 1640 * - dda: DDA tape drive. 1641 * 1642 * Get DDA media fileno based on st bsd behavior. 1643 * 1644 * Return Values: 1645 * fileno : filemark number 1646 * 1647 */ 1648 static int64_t 1649 dda_get_fileno(dda_t *dda) 1650 { 1651 int64_t fileno; 1652 1653 fileno = dda->dda_index.dda_fileno; 1654 if (dda->dda_pos > dda->dda_index.dda_blkcount) { 1655 fileno += (dda->dda_pos - dda->dda_index.dda_blkcount); 1656 } 1657 1658 if (DDA_GET_FM_FWD_PEND(dda)) { 1659 if (DDA_GET_FM_NOSKIP(dda)) { 1660 fileno--; 1661 } 1662 } 1663 1664 return (fileno); 1665 } 1666 1667 /* 1668 * dda_get_blkno 1669 * 1670 * Parameters: 1671 * - dda: DDA tape drive. 1672 * 1673 * Get DDA media blkno. 1674 * If positioned at filemark then the blkno is 0. 1675 * Otherwise backup until bot or filemark is encountered. 1676 * 1677 * Return Values: 1678 * fileno : filemark number 1679 * 1680 */ 1681 static int 1682 dda_get_blkno(dda_t *dda, int64_t *blkno) 1683 { 1684 dda_istate_t istate; 1685 int err = 0; 1686 1687 if (dda->dda_pos > dda->dda_index.dda_blkcount) { 1688 *blkno = 0; 1689 return (0); 1690 } 1691 dda_save_istate(dda, &istate); 1692 *blkno = dda->dda_pos; 1693 dda->dda_index_offset -= sizeof (dda_index_t); 1694 while (dda->dda_index_offset >= 0) { 1695 if (err = dda_read_index(dda)) { 1696 break; 1697 } 1698 if (dda->dda_index.dda_fmcount) { 1699 break; 1700 } 1701 *blkno += dda->dda_index.dda_blkcount; 1702 dda->dda_index_offset -= sizeof (dda_index_t); 1703 } 1704 dda_restore_istate(dda, &istate); 1705 return (err); 1706 } 1707 1708 /* 1709 * dda_write_truncate 1710 * 1711 * Parameters: 1712 * - dda: DDA tape drive. 1713 * 1714 * Truncate DDA media at the current position. 1715 * If at bot then stripe align the data file offset. 1716 * 1717 * Return Values: 1718 * 0 : success 1719 * errno : failure 1720 * 1721 */ 1722 static int 1723 dda_write_truncate(dda_t *dda) 1724 { 1725 int err; 1726 1727 dda->dda_flags = 0; 1728 1729 if (DDA_IS_BOT(dda)) { 1730 bzero(&dda->dda_index, sizeof (dda_index_t)); 1731 DDA_SET_INDEX(dda); 1732 } 1733 1734 if (dda->dda_pos != DDA_INDEX_COUNT(dda)) { 1735 DDA_SET_INDEX(dda); 1736 if (dda->dda_pos <= dda->dda_index.dda_blkcount) { 1737 dda->dda_index.dda_fmcount = 0; 1738 dda->dda_index.dda_blkcount = dda->dda_pos; 1739 } else { 1740 dda->dda_index.dda_fmcount = 1741 dda->dda_pos - dda->dda_index.dda_blkcount; 1742 } 1743 1744 if (DDA_INDEX_COUNT(dda) == 0) { 1745 dda->dda_index_offset -= sizeof (dda_index_t); 1746 if (dda->dda_index_offset < 0) { 1747 bzero(&dda->dda_index, sizeof (dda_index_t)); 1748 dda->dda_index_offset = 0; 1749 dda->dda_pos = 0; 1750 } else { 1751 if (err = dda_read_index(dda)) { 1752 return (err); 1753 } 1754 dda->dda_pos = DDA_INDEX_COUNT(dda); 1755 } 1756 } 1757 } 1758 1759 if (err = dda_write_index(dda)) { 1760 dda->dda_status = KEY_MEDIUM_ERROR; 1761 return (err); 1762 } 1763 1764 dda->dda_index_fsize = dda->dda_index_offset + sizeof (dda_index_t); 1765 if (err = dda_vn_truncate(dda, dda->dda_index_vp, 1766 dda->dda_index_fsize)) { 1767 return (err); 1768 } 1769 1770 dda->dda_data_fsize = dda_data_offset(dda); 1771 if (err = dda_vn_truncate(dda, dda->dda_data_vp, 1772 dda->dda_data_fsize)) { 1773 return (err); 1774 } 1775 1776 if (DDA_IS_BOT(dda)) { 1777 dda->dda_index.dda_offset += dda_stripe_align(dda); 1778 } 1779 1780 return (0); 1781 } 1782 1783 /* 1784 * dda_tape_erase 1785 * 1786 * Parameters: 1787 * - dda: DDA tape drive. 1788 * 1789 * Erase DDA media from the current position. 1790 * 1791 * Return Values: 1792 * 0 : success 1793 * errno : failure 1794 * 1795 */ 1796 static int 1797 dda_tape_erase(dda_t *dda) 1798 { 1799 int err; 1800 1801 1802 if (!dda->dda_loaded) { 1803 return (EIO); 1804 } 1805 1806 dda->dda_status = 0; 1807 dda->dda_resid = 0; 1808 1809 if (DDA_GET_READ_ONLY(dda)) { 1810 dda->dda_status = KEY_WRITE_PROTECT; 1811 return (EACCES); 1812 } 1813 1814 /* 1815 * Erase from current logical position 1816 */ 1817 DDA_DEBUG2((dda_cmd_erase, 1818 int, dda->dda_inst, 1819 int64_t, DDA_LBA(dda))); 1820 1821 if (err = dda_write_truncate(dda)) { 1822 DDA_DEBUG2((dda_cmd_erase_err, 1823 int, dda->dda_inst, 1824 int, err)); 1825 } 1826 return (err); 1827 } 1828 1829 /* 1830 * dda_sync 1831 * 1832 * Parameters: 1833 * - dda: DDA tape drive. 1834 * 1835 * Flush DDA media files to disk. 1836 * 1837 * Return Values: 1838 * 0 : success 1839 * errno : failure 1840 * 1841 */ 1842 static int 1843 dda_sync(dda_t *dda) 1844 { 1845 int err; 1846 int rc; 1847 short status; 1848 1849 /* 1850 * Sync index and data files, report first error 1851 */ 1852 1853 err = dda_vn_sync(dda, dda->dda_index_vp); 1854 status = dda->dda_status; 1855 1856 if (rc = dda_vn_sync(dda, dda->dda_data_vp)) { 1857 if (err == 0) { 1858 status = dda->dda_status; 1859 err = rc; 1860 } 1861 } 1862 1863 dda->dda_status = status; 1864 return (err); 1865 } 1866 1867 /* 1868 * dda_tape_wfm 1869 * 1870 * Parameters: 1871 * - dda: DDA tape drive. 1872 * - count: Number of filemarks to write. 1873 * 1874 * If zero filemarks then flush media to disk and return. 1875 * Truncate DDA media if needed. 1876 * If at physical end of media and no filemarks can be 1877 * written then set status and return. 1878 * Write the number of filemarks requested. 1879 * Update position on media. 1880 * Set residual for the number of filemarks not written. 1881 * Flush DDA media to disk. 1882 * 1883 * Return Values: 1884 * 0 : success 1885 * errno : failure 1886 * 1887 * Note: 1888 * A filemark is counted as 1 byte of used tape space. 1889 */ 1890 static int 1891 dda_tape_wfm(dda_t *dda, int count) 1892 { 1893 int err; 1894 int64_t avail; 1895 int ew; 1896 1897 if (!dda->dda_loaded) { 1898 return (EIO); 1899 } 1900 dda->dda_status = 0; 1901 dda->dda_resid = count; 1902 1903 if (DDA_GET_READ_ONLY(dda)) { 1904 dda->dda_status = KEY_WRITE_PROTECT; 1905 return (EACCES); 1906 } 1907 1908 DDA_DEBUG3((dda_cmd_wfm, 1909 int, dda->dda_inst, 1910 int64_t, DDA_LBA(dda), 1911 int, count)); 1912 1913 if (count == 0) { 1914 if (err = dda_write_index(dda)) { 1915 return (err); 1916 } 1917 err = dda_sync(dda); 1918 return (err); 1919 } 1920 1921 if (DDA_GET_TRUNC(dda) && (err = dda_write_truncate(dda))) { 1922 return (err); 1923 } 1924 1925 if (err = dda_ew_eom(dda, count, &avail, &ew)) { 1926 return (err); 1927 } 1928 1929 if (avail == 0) { 1930 /* 1931 * Physical end of media. 1932 */ 1933 DDA_DEBUG2((dda_cmd_wfm_eom, 1934 int, dda->dda_inst, 1935 int64_t, DDA_LBA(dda))); 1936 dda->dda_status = SUN_KEY_EOT; 1937 return (EIO); 1938 } 1939 1940 DDA_SET_INDEX(dda); 1941 dda->dda_index.dda_fmcount += avail; 1942 if (err = dda_write_index(dda)) { 1943 dda->dda_index.dda_fmcount -= avail; 1944 return (err); 1945 } 1946 1947 dda->dda_resid -= avail; 1948 dda->dda_pos += avail; 1949 dda->dda_blkno = 0; 1950 1951 if (err = dda_sync(dda)) { 1952 return (err); 1953 } 1954 1955 DDA_CLR_FM_NEEDED(dda); 1956 1957 return (0); 1958 } 1959 1960 /* 1961 * dda_tape_write 1962 * 1963 * Parameters: 1964 * - dda: DDA tape drive. 1965 * - uio: Vector I/O operations. 1966 * 1967 * DDA write supports all write lengths allowed by the kernel. 1968 * 1969 * A variable length write may span two index records when the 1970 * length is not modulus max record size. 1971 * 1972 * A fixed length write requires the data length to be a multiple 1973 * the record size. 1974 * 1975 * If read only media then set write protect status and return. 1976 * If zero length write then return. 1977 * Calculate number of blocks to write based on the record size. 1978 * Truncate media if needed. 1979 * Get early warning and physical end of media. 1980 * Adjust length to write in blocks based on tape space remaining. 1981 * If positioned past early warning then alternating write failures 1982 * occur. 1983 * Get data file offset. 1984 * Write the data to the data file. 1985 * If write error then set status and return errno. 1986 * If write returns residual then adjust counts and truncate 1987 * incomplete blocks. 1988 * Update index record with new media position. 1989 * If write crosses into early warning then set status. 1990 * Write complete. 1991 * 1992 * 1993 * Return Values: 1994 * 0 : success 1995 * errno : failure 1996 * 1997 */ 1998 static int 1999 dda_tape_write(dda_t *dda, struct uio *uio) 2000 { 2001 int err; 2002 int32_t len; 2003 int32_t total; 2004 int32_t blksize; 2005 int32_t blkcount; 2006 int64_t avail; 2007 int ew; 2008 int rc; 2009 off64_t data_offset; 2010 int32_t blks; 2011 int64_t offset; 2012 dda_istate_t istate; 2013 int32_t partial = 0; 2014 2015 if (!dda->dda_loaded) { 2016 return (EIO); 2017 } 2018 dda->dda_status = 0; 2019 dda->dda_resid = 0; 2020 2021 if (DDA_GET_READ_ONLY(dda)) { 2022 dda->dda_status = KEY_WRITE_PROTECT; 2023 dda->dda_resid = uio->uio_resid; 2024 return (EACCES); 2025 } 2026 2027 if ((total = uio->uio_resid) == 0) { 2028 if (err = dda_write_index(dda)) { 2029 return (err); 2030 } 2031 return (0); 2032 } 2033 len = total; 2034 2035 dda_save_istate(dda, &istate); 2036 2037 if (dda->dda_rec_size == 0) { 2038 /* variable block(s) */ 2039 if (len > DDA_MAX_REC_SIZE) { 2040 /* write may span this index record and next */ 2041 blksize = DDA_MAX_REC_SIZE; 2042 blkcount = len / DDA_MAX_REC_SIZE; 2043 partial = len - (blksize * blkcount); 2044 } else { 2045 /* single block write */ 2046 blksize = len; 2047 blkcount = 1; 2048 } 2049 dda->dda_resid = len; 2050 } else { 2051 /* fixed block(s) */ 2052 if ((len % dda->dda_rec_size) != 0) { 2053 return (EINVAL); 2054 } 2055 blksize = dda->dda_rec_size; 2056 blkcount = (len / dda->dda_rec_size); 2057 dda->dda_resid = blkcount; 2058 } 2059 2060 DDA_DEBUG4((dda_cmd_write, 2061 int, dda->dda_inst, 2062 int64_t, DDA_LBA(dda), 2063 int32_t, uio->uio_resid, 2064 int32_t, blkcount)); 2065 2066 if (DDA_GET_TRUNC(dda) && (err = dda_write_truncate(dda))) { 2067 return (err); 2068 } 2069 2070 if (err = dda_ew_eom(dda, len, &avail, &ew)) { 2071 return (err); 2072 } 2073 2074 if (ew) { 2075 /* 2076 * Logical end of media, alternating 2077 * zero byte writes after early warning. 2078 */ 2079 DDA_DEBUG2((dda_cmd_write_ew, 2080 int, dda->dda_inst, 2081 int, DDA_GET_EW(dda))); 2082 if (DDA_GET_EW(dda)) { 2083 DDA_CLR_EW(dda); 2084 dda->dda_status = SUN_KEY_EOT; 2085 if (avail < blksize) { 2086 /* 2087 * Physical end of media hit. 2088 */ 2089 return (EIO); 2090 } 2091 return (0); 2092 } 2093 2094 /* 2095 * Next early warning write is zero bytes. 2096 */ 2097 DDA_SET_EW(dda); 2098 } 2099 2100 if (avail < len) { 2101 /* at least one block */ 2102 if (avail < blksize) { 2103 /* 2104 * Physical end of media hit. 2105 */ 2106 DDA_DEBUG2((dda_cmd_write_eom, 2107 int, dda->dda_inst, 2108 int64_t, DDA_LBA(dda))); 2109 dda->dda_status = SUN_KEY_EOT; 2110 return (EIO); 2111 } 2112 2113 /* adjust counts */ 2114 blkcount = avail / blksize; 2115 len = blkcount * blksize; 2116 if (dda->dda_rec_size == 0) { 2117 partial = 0; 2118 dda->dda_resid = (total - len); 2119 } else { 2120 dda->dda_resid = (total - len) / blksize; 2121 } 2122 } 2123 2124 if (dda->dda_pos > dda->dda_index.dda_blkcount && 2125 dda->dda_index.dda_fmcount) { 2126 dda_gen_next_index(dda, blksize); 2127 dda->dda_index.dda_offset += dda_stripe_align(dda); 2128 } 2129 2130 if (blksize != dda->dda_index.dda_blksize) { 2131 if (DDA_IS_BOT(dda)) { 2132 dda->dda_index.dda_blksize = blksize; 2133 } else { 2134 if (err = dda_write_index(dda)) { 2135 goto write_error; 2136 } 2137 dda_gen_next_index(dda, blksize); 2138 } 2139 } 2140 2141 /* write data */ 2142 data_offset = dda_data_offset(dda); 2143 uio->uio_loffset = data_offset; 2144 uio->uio_resid = len; 2145 (void) VOP_RWLOCK(dda->dda_data_vp, V_WRITELOCK_TRUE, NULL); 2146 err = VOP_WRITE(dda->dda_data_vp, uio, 0, dda->dda_cred, NULL); 2147 VOP_RWUNLOCK(dda->dda_data_vp, V_WRITELOCK_TRUE, NULL); 2148 2149 if (err) { 2150 DDA_DEBUG4((dda_cmd_write_vn_err, 2151 int, dda->dda_inst, 2152 int64_t, DDA_LBA(dda), 2153 off64_t, data_offset, 2154 int, err)); 2155 dda_vn_error_skey(dda, err); 2156 goto write_error; 2157 } 2158 2159 if (uio->uio_resid) { 2160 if (dda->dda_rec_size == 0) { 2161 partial = 0; 2162 } 2163 2164 /* remove blocks from data */ 2165 2166 blks = uio->uio_resid / blksize; 2167 if (uio->uio_resid - (blks * blksize)) { 2168 blks++; 2169 } 2170 blkcount -= blks; 2171 if (blkcount == 0) { 2172 goto write_error; 2173 } 2174 2175 len = blkcount * blksize; 2176 offset = data_offset + len; 2177 2178 if (err = dda_vn_truncate(dda, dda->dda_data_vp, offset)) { 2179 goto write_error; 2180 } 2181 } 2182 2183 /* update index record block count */ 2184 DDA_SET_INDEX(dda); 2185 dda->dda_index.dda_blkcount += blkcount; 2186 dda->dda_pos += blkcount; 2187 dda->dda_blkno += blkcount; 2188 2189 if (partial) { 2190 if (err = dda_write_index(dda)) { 2191 goto write_error; 2192 } 2193 dda_save_istate(dda, &istate); 2194 dda_gen_next_index(dda, partial); 2195 2196 /* update new index record with block */ 2197 DDA_SET_INDEX(dda); 2198 dda->dda_index.dda_blkcount = 1; 2199 dda->dda_pos++; 2200 dda->dda_blkno++; 2201 } 2202 2203 if (total == len) { 2204 dda->dda_resid = 0; 2205 } else { 2206 uio->uio_resid = total - len; 2207 if (dda->dda_rec_size == 0) { 2208 dda->dda_resid = (total - len); 2209 } else { 2210 dda->dda_resid = (total - len) / blksize; 2211 } 2212 2213 DDA_DEBUG4((dda_cmd_write_done, 2214 int, dda->dda_inst, 2215 int64_t, DDA_LBA(dda), 2216 int32_t, blkcount, 2217 int32_t, uio->uio_resid)); 2218 } 2219 2220 if (ew) { 2221 DDA_DEBUG2((dda_cmd_write_ew, 2222 int, dda->dda_inst, 2223 int64_t, DDA_LBA(dda))); 2224 dda->dda_status = SUN_KEY_EOT; 2225 } 2226 2227 DDA_SET_FM_NEEDED(dda); 2228 2229 dda->dda_data_fsize += total - uio->uio_resid; 2230 2231 return (err); 2232 2233 write_error: 2234 /* no blocks written */ 2235 uio->uio_resid = total; 2236 if (dda->dda_rec_size == 0) { 2237 dda->dda_resid = total; 2238 } else { 2239 dda->dda_resid = total / blksize; 2240 } 2241 dda_restore_istate(dda, &istate); 2242 if (DDA_IS_BOT(dda)) { 2243 dda->dda_index.dda_blksize = 0; 2244 } 2245 DDA_SET_TRUNC(dda); 2246 if (rc = dda_write_truncate(dda)) { 2247 if (err == 0) { 2248 err = rc; 2249 } 2250 } 2251 DDA_DEBUG3((dda_cmd_write_err, 2252 int, dda->dda_inst, 2253 int64_t, DDA_LBA(dda), 2254 int, err)); 2255 if (err) { 2256 /* original error */ 2257 return (err); 2258 } 2259 return (EIO); 2260 } 2261 2262 /* 2263 * dda_tape_read 2264 * 2265 * Parameters: 2266 * - dda: DDA tape drive. 2267 * - uio: Vector I/O operations. 2268 * 2269 * DDA read supports all read lengths allowed by the kernel. 2270 * 2271 * A variable length read may span two index records. 2272 * 2273 * The DDA variable length read supports the ILI (incorrect length 2274 * indicator). 2275 * 2276 * A fixed length read requires the data length to be a multiple of 2277 * the record size. 2278 * 2279 * If zero length read then return success. 2280 * Calculate the number of blocks to read based on the record size. 2281 * Get early warning and physical end of media. 2282 * Adjust length (blocks) to read based on tape space remaining. 2283 * Read the data from the data file. 2284 * If a read error occurred or residual from dda's adjusted read length 2285 * then set status and return. 2286 * Update the index record with new media position. 2287 * Read complete. 2288 * 2289 * 2290 * Return Values: 2291 * 0 : success 2292 * errno : failure 2293 * 2294 */ 2295 int 2296 dda_tape_read(dda_t *dda, struct uio *uio) 2297 { 2298 int32_t len; 2299 int32_t total; 2300 int32_t blksize; 2301 int32_t blkcount; 2302 int err; 2303 off64_t fsize; 2304 dda_istate_t istate; 2305 off64_t data_offset; 2306 int overflow = 0; 2307 int noskip; 2308 int partial = 0; 2309 off64_t offset; 2310 dda_index_t index; 2311 2312 if (!dda->dda_loaded) { 2313 return (EIO); 2314 } 2315 dda->dda_status = 0; 2316 dda->dda_resid = 0; 2317 DDA_SET_TRUNC(dda); 2318 DDA_CLR_FM_NEEDED(dda); 2319 DDA_CLR_EW(dda); 2320 2321 if ((total = uio->uio_resid) == 0) { 2322 if (err = dda_write_index(dda)) { 2323 return (err); 2324 } 2325 return (0); 2326 } 2327 len = total; 2328 2329 dda_save_istate(dda, &istate); 2330 2331 if (dda->dda_rec_size == 0) { 2332 /* variable */ 2333 if (len > DDA_MAX_REC_SIZE) { 2334 /* read may span this index record and next */ 2335 blksize = DDA_MAX_REC_SIZE; 2336 blkcount = len / DDA_MAX_REC_SIZE; 2337 if (len - (blksize * blkcount)) { 2338 /* actual partial blksize determined below */ 2339 partial = 1; 2340 } 2341 } else { 2342 /* single block read */ 2343 blksize = len; 2344 blkcount = 1; 2345 } 2346 dda->dda_resid = len; 2347 } else { 2348 /* fixed */ 2349 if (dda->dda_ili) { 2350 cmn_err(CE_WARN, "%d Incorrect Length Indicator Set", 2351 dda->dda_inst); 2352 return (EINVAL); 2353 } 2354 if ((len % dda->dda_rec_size) != 0) { 2355 cmn_err(CE_WARN, "%d read: not modulo %d block size", 2356 dda->dda_inst, dda->dda_rec_size); 2357 return (EINVAL); 2358 } 2359 blksize = dda->dda_rec_size; 2360 blkcount = (len / dda->dda_rec_size); 2361 dda->dda_resid = blkcount; 2362 } 2363 2364 if (err = dda_write_index(dda)) { 2365 return (err); 2366 } 2367 2368 DDA_DEBUG4((dda_cmd_read, 2369 int, dda->dda_inst, 2370 int64_t, DDA_LBA(dda), 2371 int32_t, uio->uio_resid, 2372 int32_t, blkcount)); 2373 2374 if (DDA_GET_FM_FWD_PEND(dda)) { 2375 noskip = DDA_GET_FM_NOSKIP(dda); 2376 DDA_CLR_FM_FWD_PEND(dda); 2377 if (noskip) { 2378 DDA_DEBUG1((dda_cmd_read_ffpns, 2379 int, dda->dda_inst)); 2380 2381 dda->dda_status = SUN_KEY_EOF; 2382 dda->dda_blkno = 0; 2383 return (0); 2384 } 2385 2386 DDA_DEBUG1((dda_cmd_read_ffpc, 2387 int, dda->dda_inst)); 2388 } 2389 2390 fsize = dda->dda_index_fsize - sizeof (dda_index_t); 2391 2392 if (dda->dda_pos >= DDA_INDEX_COUNT(dda)) { 2393 dda->dda_index_offset += sizeof (dda_index_t); 2394 if (dda->dda_index_offset > fsize) { 2395 2396 DDA_DEBUG3((dda_cmd_read_eot, 2397 int, dda->dda_inst, 2398 int64_t, DDA_LBA(dda), 2399 int, DDA_GET_EOT_EIO(dda))); 2400 2401 dda->dda_index_offset -= sizeof (dda_index_t); 2402 dda->dda_status = SUN_KEY_EOT; 2403 if (DDA_GET_EOT_EIO(dda) == 0) { 2404 DDA_SET_EOT_EIO(dda); 2405 dda->dda_resid = len; 2406 return (EIO); 2407 } 2408 return (0); 2409 } 2410 if (err = dda_read_index(dda)) { 2411 dda_restore_istate(dda, &istate); 2412 return (err); 2413 } 2414 } 2415 2416 DDA_CLR_EOT_EIO(dda); 2417 2418 if (DDA_IS_FM(dda)) { 2419 DDA_DEBUG2((dda_cmd_read_fm, 2420 int, dda->dda_inst, 2421 int64_t, DDA_LBA(dda))); 2422 2423 DDA_SET_FM_FWD_PEND(dda); 2424 dda->dda_pos++; 2425 dda->dda_status = SUN_KEY_EOF; 2426 dda->dda_blkno = 0; 2427 return (0); 2428 } 2429 2430 if (blksize != dda->dda_index.dda_blksize) { 2431 if (blksize < dda->dda_index.dda_blksize) { 2432 len = blksize; 2433 if (dda->dda_ili == 0) { 2434 overflow = 1; 2435 } 2436 } else { 2437 len = dda->dda_index.dda_blksize; 2438 } 2439 blkcount = 1; 2440 blksize = len; 2441 partial = 0; 2442 2443 DDA_DEBUG4((dda_cmd_read_blksz, 2444 int, dda->dda_inst, 2445 int64_t, blksize, 2446 int64_t, blkcount, 2447 int, overflow)); 2448 } 2449 2450 if (dda->dda_pos + blkcount + partial > dda->dda_index.dda_blkcount) { 2451 if (partial) { 2452 /* get partial from next index record */ 2453 offset = dda->dda_index_offset + sizeof (dda_index_t); 2454 if (offset > fsize) { 2455 partial = 0; 2456 } else if (dda_vn_read(dda, dda->dda_index_vp, 2457 &index, sizeof (dda_index_t), offset)) { 2458 partial = 0; 2459 } else { 2460 DDA_BE_INDEX(index, index); 2461 if (index.dda_blkcount == 0) { 2462 partial = 0; 2463 } 2464 } 2465 } 2466 2467 blkcount = dda->dda_index.dda_blkcount - dda->dda_pos; 2468 if (blkcount == 0) { 2469 if (dda->dda_rec_size == 0) { 2470 dda->dda_resid = total; 2471 } else { 2472 dda->dda_resid = total / blksize; 2473 } 2474 DDA_DEBUG1((dda_cmd_read_noblks, 2475 int, dda->dda_inst)); 2476 return (0); 2477 } 2478 2479 len = blkcount * blksize; 2480 2481 if (partial) { 2482 len += index.dda_blksize; 2483 } 2484 2485 DDA_DEBUG4((dda_cmd_read_numblks, 2486 int, dda->dda_inst, 2487 int32_t, len, 2488 int32_t, blksize, 2489 int32_t, blkcount)); 2490 2491 } else if (partial) { 2492 /* current index record contains partial */ 2493 len += dda->dda_index.dda_blksize; 2494 } 2495 2496 if (len > total) { 2497 len = total; 2498 if (dda->dda_ili == 0) { 2499 overflow = 1; 2500 } 2501 } 2502 2503 DDA_DEBUG2((dda_cmd_read_partial, 2504 int, dda->dda_inst, 2505 int32_t, partial)); 2506 2507 data_offset = dda_data_offset(dda); 2508 uio->uio_loffset = data_offset; 2509 uio->uio_resid = len; 2510 (void) VOP_RWLOCK(dda->dda_data_vp, V_WRITELOCK_FALSE, NULL); 2511 err = VOP_READ(dda->dda_data_vp, uio, 0, dda->dda_cred, NULL); 2512 VOP_RWUNLOCK(dda->dda_data_vp, V_WRITELOCK_FALSE, NULL); 2513 2514 /* 2515 * If a read error occurred or residual from dda adjusted length 2516 * then don't return any data. 2517 */ 2518 2519 if (err) { 2520 DDA_DEBUG4((dda_cmd_read_vn_err, 2521 int, dda->dda_inst, 2522 int64_t, DDA_LBA(dda), 2523 off64_t, data_offset, 2524 int, err)); 2525 2526 dda_restore_istate(dda, &istate); 2527 uio->uio_resid = total; 2528 dda_vn_error_skey(dda, err); 2529 if (dda->dda_rec_size == 0) { 2530 dda->dda_resid = total; 2531 } else { 2532 dda->dda_resid = total / blksize; 2533 } 2534 return (err); 2535 } 2536 2537 if (uio->uio_resid) { 2538 DDA_DEBUG2((dda_cmd_read_resid, 2539 int, dda->dda_inst, 2540 int32_t, uio->uio_resid)); 2541 2542 uio->uio_resid = total; 2543 if (dda->dda_rec_size == 0) { 2544 dda->dda_resid = total; 2545 } else { 2546 dda->dda_resid = total / blksize; 2547 } 2548 dda_restore_istate(dda, &istate); 2549 return (EIO); 2550 } 2551 2552 2553 /* 2554 * Successful read, adjust index record and counters. 2555 */ 2556 2557 dda->dda_pos += blkcount; 2558 2559 if (total == len) { 2560 dda->dda_blkno += blkcount; 2561 dda->dda_resid = 0; 2562 } else { 2563 uio->uio_resid = total - len; 2564 if (dda->dda_rec_size == 0) { 2565 dda->dda_resid = uio->uio_resid; 2566 } else { 2567 dda->dda_resid = uio->uio_resid / blksize; 2568 } 2569 dda->dda_blkno += uio->uio_resid / blksize; 2570 } 2571 2572 if (partial) { 2573 dda->dda_pos = 1; 2574 dda->dda_blkno++; 2575 dda->dda_index = index; 2576 dda->dda_index_offset += sizeof (dda_index_t); 2577 } 2578 2579 DDA_DEBUG3((dda_cmd_read_short, 2580 int, dda->dda_inst, 2581 int64_t, DDA_LBA(dda), 2582 int32_t, dda->dda_resid)); 2583 2584 if (overflow) { 2585 DDA_DEBUG2((dda_cmd_read_overflow, 2586 int, dda->dda_inst, 2587 int64_t, DDA_LBA(dda))); 2588 dda->dda_resid = 0; 2589 err = ENOMEM; 2590 } 2591 2592 return (err); 2593 } 2594 2595 /* 2596 * dda_tape_locate 2597 * 2598 * Parameters: 2599 * - dda: DDA tape drive. 2600 * - position: Locate to LBA. 2601 * 2602 * Locate to LBA requested. 2603 * 2604 * Return Values: 2605 * 0 : success 2606 * errno : failure, positioned at bot or eom 2607 * 2608 */ 2609 static int 2610 dda_tape_locate(dda_t *dda, off64_t position) 2611 { 2612 int err; 2613 int found; 2614 int64_t lba; 2615 dda_istate_t istate; 2616 int rc; 2617 2618 2619 if (!dda->dda_loaded) { 2620 return (EIO); 2621 } 2622 2623 dda->dda_status = 0; 2624 dda->dda_resid = 0; 2625 2626 if (err = dda_write_index(dda)) { 2627 return (err); 2628 } 2629 2630 dda->dda_blkno = 0; 2631 dda->dda_resid = 0; 2632 dda->dda_flags = 0; 2633 DDA_SET_TRUNC(dda); 2634 lba = DDA_LBA(dda); 2635 2636 DDA_DEBUG3((dda_cmd_locate, 2637 int, dda->dda_inst, 2638 int64_t, DDA_LBA(dda), 2639 off64_t, position)); 2640 2641 dda_save_istate(dda, &istate); 2642 if (err = dda_bsearch(dda, position, dda_locate_compare, &found)) { 2643 DDA_DEBUG2((dda_cmd_locate_err, 2644 int, dda->dda_inst, 2645 int, err)); 2646 dda_restore_istate(dda, &istate); 2647 return (err); 2648 } 2649 2650 if (!found) { 2651 /* 2652 * Locate unsuccessful, 2653 * position based on direction of search 2654 */ 2655 if (position < lba) { 2656 if (err = dda_tape_rewind(dda)) { 2657 return (err); 2658 } 2659 dda->dda_status = SUN_KEY_BOT; 2660 dda->dda_resid = 0; 2661 } else { 2662 if (err = dda_tape_eom(dda)) { 2663 return (err); 2664 } 2665 dda->dda_status = KEY_BLANK_CHECK; 2666 dda->dda_resid = 0; 2667 } 2668 err = EIO; 2669 } 2670 if (rc = dda_get_blkno(dda, &dda->dda_blkno)) { 2671 err = rc; 2672 } 2673 2674 DDA_DEBUG4((dda_cmd_locate_done, 2675 int, dda->dda_inst, 2676 int64_t, DDA_LBA(dda), 2677 int64_t, dda_get_fileno(dda), 2678 int64_t, dda->dda_blkno)); 2679 2680 return (err); 2681 } 2682 2683 /* 2684 * dda_tape_fsr 2685 * 2686 * Parameters: 2687 * - dda: DDA tape drive. 2688 * - count: Number of records to forward space. 2689 * 2690 * Forward space records the requested count. 2691 * Set truncate needed for write that may follow. 2692 * Clear filemark forward pending. 2693 * Clear alternating write success at early warning. 2694 * If filemark is hit during fsr then cross the filemark but report 2695 * logical position in front of the filemark to the user. 2696 * 2697 * Return Values: 2698 * 0 : success 2699 * errno : failure 2700 * 2701 */ 2702 static int 2703 dda_tape_fsr(dda_t *dda, int count) 2704 { 2705 int err; 2706 off64_t fsize; 2707 dda_istate_t istate; 2708 int fm; 2709 int64_t blks; 2710 2711 2712 if (!dda->dda_loaded) { 2713 return (EIO); 2714 } 2715 2716 dda->dda_status = 0; 2717 dda->dda_resid = count; 2718 2719 if (err = dda_write_index(dda)) { 2720 return (err); 2721 } 2722 2723 DDA_SET_TRUNC(dda); 2724 DDA_CLR_FM_NEEDED(dda); 2725 DDA_CLR_EW(dda); 2726 2727 DDA_DEBUG4((dda_cmd_fsr, 2728 int, dda->dda_inst, 2729 int64_t, DDA_LBA(dda), 2730 int64_t, dda_get_fileno(dda), 2731 int, count)); 2732 2733 fsize = dda->dda_index_fsize - sizeof (dda_index_t); 2734 2735 while (dda->dda_resid) { 2736 dda_save_istate(dda, &istate); 2737 2738 if (DDA_GET_FM_FWD_PEND(dda)) { 2739 dda->dda_status = SUN_KEY_EOF; 2740 return (EIO); 2741 } 2742 2743 if (dda->dda_pos >= DDA_INDEX_COUNT(dda)) { 2744 dda->dda_index_offset += sizeof (dda_index_t); 2745 if (dda->dda_index_offset > fsize) { 2746 dda_restore_istate(dda, &istate); 2747 dda->dda_status = KEY_BLANK_CHECK; 2748 err = EIO; 2749 break; 2750 } 2751 if (err = dda_read_index(dda)) { 2752 dda_restore_istate(dda, &istate); 2753 DDA_DEBUG2((dda_cmd_fsr_err, 2754 int, dda->dda_inst, 2755 int, err)); 2756 return (err); 2757 } 2758 } 2759 2760 DDA_DEBUG4((dda_cmd_fsr_where, 2761 int, dda->dda_inst, 2762 int64_t, dda->dda_pos, 2763 int64_t, dda->dda_index.dda_blkcount, 2764 int64_t, dda->dda_index.dda_fmcount)); 2765 2766 fm = DDA_IS_FM(dda); 2767 if (fm) { 2768 blks = 1; 2769 } else { 2770 blks = dda->dda_index.dda_blkcount - dda->dda_pos; 2771 if (dda->dda_resid <= blks) { 2772 blks = dda->dda_resid; 2773 } 2774 } 2775 2776 DDA_DEBUG2((dda_cmd_fsr_blks, 2777 int, dda->dda_inst, 2778 int64_t, blks)); 2779 2780 dda->dda_pos += blks; 2781 dda->dda_blkno += blks; 2782 2783 if (fm) { 2784 DDA_DEBUG1((dda_cmd_fsr_fm, 2785 int, dda->dda_inst)); 2786 DDA_SET_FM_FWD_PEND(dda); 2787 DDA_SET_FM_NOSKIP(dda); 2788 dda->dda_blkno--; 2789 dda->dda_status = SUN_KEY_EOF; 2790 err = EIO; 2791 break; 2792 } 2793 2794 dda->dda_resid -= blks; 2795 } 2796 2797 DDA_DEBUG4((dda_cmd_fsr_done, 2798 int, dda->dda_inst, 2799 int64_t, DDA_LBA(dda), 2800 int64_t, dda_get_fileno(dda), 2801 int32_t, dda->dda_resid)); 2802 2803 return (err); 2804 } 2805 2806 /* 2807 * dda_tape_bsr 2808 * 2809 * Parameters: 2810 * - dda: DDA tape drive. 2811 * - count: Number of records to backward space. 2812 * 2813 * Backspace records the requested count. 2814 * Set truncate needed for write that may follow. 2815 * Clear filemark forward pending. 2816 * Clear alternating write success at early warning. 2817 * If filemark is hit during bsr then do not cross the filemark. 2818 * 2819 * Return Values: 2820 * 0 : success 2821 * errno : failure 2822 * 2823 */ 2824 static int 2825 dda_tape_bsr(dda_t *dda, int count) 2826 { 2827 int err = 0; 2828 dda_istate_t istate; 2829 int64_t blks; 2830 2831 2832 if (!dda->dda_loaded) { 2833 return (EIO); 2834 } 2835 2836 dda->dda_status = 0; 2837 dda->dda_resid = count; 2838 2839 if (err = dda_write_index(dda)) { 2840 return (err); 2841 } 2842 2843 DDA_SET_TRUNC(dda); 2844 DDA_CLR_FM_NEEDED(dda); 2845 DDA_CLR_EW(dda); 2846 2847 DDA_DEBUG4((dda_cmd_bsr, 2848 int, dda->dda_inst, 2849 int64_t, DDA_LBA(dda), 2850 int64_t, dda_get_fileno(dda), 2851 int, count)); 2852 2853 while (dda->dda_resid) { 2854 dda_save_istate(dda, &istate); 2855 2856 if (DDA_GET_FM_FWD_PEND(dda)) { 2857 DDA_CLR_FM_FWD_PEND(dda); 2858 dda->dda_pos--; 2859 } 2860 2861 if (dda->dda_pos <= 0) { 2862 dda->dda_index_offset -= sizeof (dda_index_t); 2863 if (dda->dda_index_offset < 0) { 2864 dda_restore_istate(dda, &istate); 2865 dda->dda_status = SUN_KEY_BOT; 2866 err = EIO; 2867 break; 2868 } 2869 if (err = dda_read_index(dda)) { 2870 dda_restore_istate(dda, &istate); 2871 DDA_DEBUG2((dda_cmd_bsr_err, 2872 int, dda->dda_inst, 2873 int, err)); 2874 return (err); 2875 } 2876 dda->dda_pos = DDA_INDEX_COUNT(dda); 2877 } 2878 2879 DDA_DEBUG4((dda_cmd_bsr_where, 2880 int, dda->dda_inst, 2881 int64_t, dda->dda_pos, 2882 int64_t, dda->dda_index.dda_blkcount, 2883 int64_t, dda->dda_index.dda_fmcount)); 2884 2885 blks = 0; 2886 if (dda->dda_pos <= dda->dda_index.dda_blkcount) { 2887 blks = dda->dda_pos; 2888 if (dda->dda_resid <= blks) { 2889 blks = dda->dda_resid; 2890 } 2891 } 2892 2893 DDA_DEBUG2((dda_cmd_bsr_blks, 2894 int, dda->dda_inst, 2895 int64_t, blks)); 2896 2897 dda->dda_pos -= blks; 2898 dda->dda_blkno -= blks; 2899 2900 if (DDA_IS_FM(dda)) { 2901 DDA_DEBUG3((dda_cmd_bsr_fm, 2902 int, dda->dda_inst, 2903 int64_t, DDA_LBA(dda), 2904 int64_t, dda_get_fileno(dda))); 2905 2906 dda->dda_blkno = 0; 2907 dda->dda_status = SUN_KEY_EOF; 2908 err = EIO; 2909 break; 2910 } 2911 2912 dda->dda_resid -= blks; 2913 } 2914 2915 DDA_DEBUG4((dda_cmd_bsr_done, 2916 int, dda->dda_inst, 2917 int64_t, DDA_LBA(dda), 2918 int64_t, dda_get_fileno(dda), 2919 int32_t, dda->dda_resid)); 2920 2921 return (err); 2922 } 2923 2924 /* 2925 * dda_tape_fsf 2926 * 2927 * Parameters: 2928 * - dda: DDA tape drive. 2929 * - count: Number of filemarks to forward space. 2930 * 2931 * Forward space filemarks. 2932 * Set truncate needed for write that may follow. 2933 * Clear filemark forward pending. 2934 * Clear alternating write success at early warning. 2935 * If filemark forward pending then decrement the count. 2936 * Binary search to the filemark. 2937 * 2938 * Return Values: 2939 * 0 : success 2940 * errno : failure 2941 * 2942 */ 2943 static int 2944 dda_tape_fsf(dda_t *dda, int count) 2945 { 2946 int err; 2947 int found; 2948 dda_istate_t istate; 2949 int64_t fileno; 2950 2951 2952 if (!dda->dda_loaded) { 2953 return (EIO); 2954 } 2955 2956 dda->dda_status = 0; 2957 dda->dda_resid = count; 2958 2959 if (err = dda_write_index(dda)) { 2960 return (err); 2961 } 2962 2963 dda->dda_blkno = 0; 2964 DDA_SET_TRUNC(dda); 2965 DDA_CLR_FM_NEEDED(dda); 2966 DDA_CLR_EOT_EIO(dda); 2967 DDA_CLR_EW(dda); 2968 2969 DDA_DEBUG4((dda_cmd_fsf, 2970 int, dda->dda_inst, 2971 int64_t, DDA_LBA(dda), 2972 int64_t, dda_get_fileno(dda), 2973 int, count)); 2974 2975 if (DDA_GET_FM_FWD_PEND(dda)) { 2976 DDA_CLR_FM_FWD_PEND(dda); 2977 count--; 2978 2979 DDA_DEBUG4((dda_cmd_fsf_pend, 2980 int, dda->dda_inst, 2981 int64_t, DDA_LBA(dda), 2982 int64_t, dda_get_fileno(dda), 2983 int, count)); 2984 } 2985 2986 dda_save_istate(dda, &istate); 2987 fileno = dda_get_fileno(dda) + count; 2988 2989 if (fileno == 0) { 2990 err = dda_tape_rewind(dda); 2991 goto fsf_done; 2992 } 2993 2994 if (err = dda_bsearch(dda, fileno, dda_fsf_compare, &found)) { 2995 DDA_DEBUG2((dda_cmd_fsf_err, 2996 int, dda->dda_inst, 2997 int, err)); 2998 dda_restore_istate(dda, &istate); 2999 return (err); 3000 } 3001 3002 if (found) { 3003 /* 3004 * Forward space file successful 3005 */ 3006 dda->dda_resid = 0; 3007 } else { 3008 /* 3009 * Forward space file unsuccessful, 3010 * position based on direction of search 3011 */ 3012 if (count < 0) { 3013 if (err = dda_tape_rewind(dda)) { 3014 return (err); 3015 } 3016 dda->dda_status = SUN_KEY_BOT; 3017 dda->dda_resid = dda_get_fileno(dda) - fileno; 3018 } else { 3019 if (err = dda_tape_eom(dda)) { 3020 return (err); 3021 } 3022 if (err = dda_get_blkno(dda, &dda->dda_blkno)) { 3023 return (err); 3024 } 3025 dda->dda_status = KEY_BLANK_CHECK; 3026 dda->dda_resid = fileno - dda_get_fileno(dda); 3027 } 3028 err = EIO; 3029 } 3030 3031 fsf_done: 3032 DDA_DEBUG4((dda_cmd_fsf_done, 3033 int, dda->dda_inst, 3034 int64_t, DDA_LBA(dda), 3035 int64_t, dda_get_fileno(dda), 3036 int32_t, dda->dda_resid)); 3037 3038 return (err); 3039 } 3040 3041 /* 3042 * dda_tape_bsf 3043 * 3044 * Parameters: 3045 * - dda: DDA tape drive. 3046 * - count: Number of filemarks to backward space. 3047 * 3048 * Backward space filemarks. 3049 * Zero flags. 3050 * Set truncate needed for write that may follow. 3051 * Binary search to filemark. 3052 * 3053 * Return Values: 3054 * 0 : success 3055 * errno : failure 3056 * 3057 */ 3058 static int 3059 dda_tape_bsf(dda_t *dda, int count) 3060 { 3061 int err; 3062 int found; 3063 dda_istate_t istate; 3064 int64_t fileno; 3065 int rc; 3066 3067 3068 if (!dda->dda_loaded) { 3069 return (EIO); 3070 } 3071 3072 dda->dda_status = 0; 3073 dda->dda_resid = count; 3074 3075 if (err = dda_write_index(dda)) { 3076 return (err); 3077 } 3078 3079 dda->dda_flags = 0; 3080 dda->dda_blkno = DDA_BLKNO_UNKNOWN; 3081 DDA_SET_TRUNC(dda); 3082 fileno = dda_get_fileno(dda) - count; 3083 3084 DDA_DEBUG4((dda_cmd_bsf, 3085 int, dda->dda_inst, 3086 int64_t, DDA_LBA(dda), 3087 int64_t, dda_get_fileno(dda), 3088 int, count)); 3089 3090 dda_save_istate(dda, &istate); 3091 if (err = dda_bsearch(dda, fileno, dda_bsf_compare, &found)) { 3092 DDA_DEBUG2((dda_cmd_bsf_err, 3093 int, dda->dda_inst, 3094 int, err)); 3095 dda_restore_istate(dda, &istate); 3096 return (err); 3097 } 3098 3099 if (found) { 3100 /* 3101 * Backward space file successful 3102 */ 3103 dda->dda_resid = 0; 3104 } else { 3105 /* 3106 * Backward space file unsuccessful, 3107 * position based on direction of search 3108 */ 3109 if (count < 0) { 3110 if (err = dda_tape_eom(dda)) { 3111 return (err); 3112 } 3113 if (rc = dda_get_blkno(dda, &dda->dda_blkno)) { 3114 err = rc; 3115 } 3116 dda->dda_status = KEY_BLANK_CHECK; 3117 dda->dda_resid = fileno - dda_get_fileno(dda); 3118 } else { 3119 if (err = dda_tape_rewind(dda)) { 3120 return (err); 3121 } 3122 dda->dda_status = SUN_KEY_BOT; 3123 dda->dda_resid = dda_get_fileno(dda) - fileno; 3124 } 3125 err = EIO; 3126 } 3127 3128 DDA_DEBUG4((dda_cmd_bsf_done, 3129 int, dda->dda_inst, 3130 int64_t, DDA_LBA(dda), 3131 int64_t, dda_get_fileno(dda), 3132 int32_t, dda->dda_resid)); 3133 3134 return (err); 3135 } 3136 3137 /* 3138 * dda_tape_eom 3139 * 3140 * Parameters: 3141 * - dda: DDA tape drive. 3142 * 3143 * Position to end of media. 3144 * 3145 * Return Values: 3146 * 0 : success 3147 * errno : failure 3148 * 3149 */ 3150 static int 3151 dda_tape_eom(dda_t *dda) 3152 { 3153 off64_t fsize; 3154 int err; 3155 3156 3157 if (!dda->dda_loaded) { 3158 return (EIO); 3159 } 3160 3161 dda->dda_status = 0; 3162 dda->dda_resid = 0; 3163 3164 if (err = dda_write_index(dda)) { 3165 return (err); 3166 } 3167 3168 dda->dda_flags = 0; 3169 dda->dda_blkno = 0; 3170 3171 fsize = dda->dda_index_fsize - sizeof (dda_index_t); 3172 if (fsize < 0) { 3173 DDA_DEBUG2((dda_cmd_eom_err, 3174 int, dda->dda_inst, 3175 int, err)); 3176 dda->dda_status = KEY_MEDIUM_ERROR; 3177 return (EIO); 3178 } 3179 if (dda->dda_index_offset != fsize) { 3180 dda->dda_index_offset = fsize; 3181 if (err = dda_read_index(dda)) { 3182 DDA_DEBUG2((dda_cmd_eom_err, 3183 int, dda->dda_inst, 3184 int, err)); 3185 return (err); 3186 } 3187 } 3188 dda->dda_pos = DDA_INDEX_COUNT(dda); 3189 3190 DDA_DEBUG4((dda_cmd_eom, 3191 int, dda->dda_inst, 3192 int64_t, DDA_LBA(dda), 3193 int64_t, dda_get_fileno(dda), 3194 int64_t, dda->dda_blkno)); 3195 3196 return (0); 3197 } 3198 3199 /* 3200 * dda_tape_rewind 3201 * 3202 * Parameters: 3203 * - dda: DDA tape drive. 3204 * 3205 * Position to beginning of media. 3206 * 3207 * Return Values: 3208 * 0 : success 3209 * errno : failure 3210 * 3211 */ 3212 static int 3213 dda_tape_rewind(dda_t *dda) 3214 { 3215 int err = 0; 3216 3217 3218 if (!dda->dda_loaded) { 3219 return (EIO); 3220 } 3221 3222 dda->dda_status = 0; 3223 dda->dda_resid = 0; 3224 3225 if (err = dda_write_index(dda)) { 3226 return (err); 3227 } 3228 3229 if (DDA_GET_FM_NEEDED(dda)) { 3230 if (err = dda_tape_wfm(dda, 1)) { 3231 return (err); 3232 } 3233 } 3234 3235 dda->dda_flags = 0; 3236 dda->dda_blkno = 0; 3237 DDA_SET_TRUNC(dda); 3238 3239 dda->dda_index_offset = 0; 3240 if (err = dda_read_index(dda)) { 3241 DDA_DEBUG2((dda_cmd_rewind_err, 3242 int, dda->dda_inst, 3243 int, err)); 3244 return (err); 3245 } 3246 3247 DDA_DEBUG2((dda_cmd_rewind, 3248 int, dda->dda_inst, 3249 int64_t, DDA_LBA(dda))); 3250 3251 return (0); 3252 } 3253 3254 /* index operations */ 3255 3256 /* 3257 * dda_write_index 3258 * 3259 * Parameters: 3260 * - dda: DDA tape drive. 3261 * 3262 * Write an index record at the index file position. 3263 * 3264 * Return Values: 3265 * 0 : success 3266 * errno : failure 3267 * 3268 */ 3269 static int 3270 dda_write_index(dda_t *dda) 3271 { 3272 int err; 3273 dda_index_t index; 3274 3275 if (DDA_GET_INDEX(dda)) { 3276 DDA_CLR_INDEX(dda); 3277 DDA_BE_INDEX(dda->dda_index, index); 3278 if (err = dda_vn_write(dda, dda->dda_index_vp, &index, 3279 sizeof (dda_index_t), dda->dda_index_offset)) { 3280 return (err); 3281 } 3282 dda->dda_index_fsize = dda->dda_index_offset + 3283 sizeof (dda_index_t); 3284 3285 DDA_DEBUG4((dda_write_index, 3286 int, dda->dda_inst, 3287 int64_t, dda->dda_index.dda_lba, 3288 int64_t, dda->dda_index.dda_fileno, 3289 off64_t, dda->dda_index_offset)); 3290 } 3291 return (0); 3292 } 3293 3294 /* 3295 * dda_read_index 3296 * 3297 * Parameters: 3298 * - dda: DDA tape drive. 3299 * 3300 * Read an index record from the index file position. 3301 * 3302 * Return Values: 3303 * 0 : success 3304 * errno : failure 3305 * 3306 */ 3307 static int 3308 dda_read_index(dda_t *dda) 3309 { 3310 int err; 3311 dda_index_t index; 3312 3313 DDA_CLR_INDEX(dda); 3314 dda->dda_pos = 0; 3315 if (err = dda_vn_read(dda, dda->dda_index_vp, &index, 3316 sizeof (dda_index_t), dda->dda_index_offset)) { 3317 return (err); 3318 } 3319 DDA_BE_INDEX(index, dda->dda_index); 3320 3321 DDA_DEBUG4((dda_read_index, 3322 int, dda->dda_inst, 3323 int64_t, dda->dda_index.dda_lba, 3324 int64_t, dda->dda_index.dda_fileno, 3325 off64_t, dda->dda_index_offset)); 3326 3327 return (0); 3328 } 3329 3330 /* 3331 * dda_gen_next_index 3332 * 3333 * Parameters: 3334 * - dda: DDA tape drive. 3335 * - blksize: Record size for index record. 3336 * 3337 * Generate the next index record with starting positions from the 3338 * end of previous index record. 3339 * Function is called after a change in record size or when data 3340 * follows a filemark. 3341 * 3342 * Return Values: 3343 * None 3344 * 3345 */ 3346 static void 3347 dda_gen_next_index(dda_t *dda, int32_t blksize) 3348 { 3349 DDA_CLR_INDEX(dda); 3350 dda->dda_index.dda_offset = dda_data_offset(dda); 3351 dda->dda_index.dda_lba += DDA_INDEX_COUNT(dda); 3352 dda->dda_index.dda_fileno += dda->dda_index.dda_fmcount; 3353 dda->dda_index.dda_fmcount = 0; 3354 dda->dda_index.dda_blkcount = 0; 3355 dda->dda_index.dda_blksize = blksize; 3356 dda->dda_index_offset += sizeof (dda_index_t); 3357 dda->dda_pos = 0; 3358 3359 DDA_DEBUG3((dda_gen_next_index, 3360 int, dda->dda_inst, 3361 int64_t, dda->dda_index.dda_lba, 3362 int64_t, dda->dda_index.dda_fileno)); 3363 3364 } 3365 3366 /* 3367 * dda_save_istate 3368 * 3369 * Parameters: 3370 * - dda: DDA tape drive. 3371 * - istate: Index record and index file offset. 3372 * 3373 * Save current index record and position. 3374 * 3375 * Return Values: 3376 * None 3377 * 3378 */ 3379 static void 3380 dda_save_istate(dda_t *dda, dda_istate_t *istate) 3381 { 3382 istate->dda_index_offset = dda->dda_index_offset; 3383 istate->dda_index = dda->dda_index; 3384 istate->dda_pos = dda->dda_pos; 3385 istate->dda_flags = dda->dda_flags; 3386 } 3387 3388 /* 3389 * dda_restore_istate 3390 * 3391 * Parameters: 3392 * - dda: DDA tape drive. 3393 * - istate: Index record and index file offset. 3394 * 3395 * Restore saved index record and position. 3396 * 3397 * Return Values: 3398 * None 3399 * 3400 */ 3401 static void 3402 dda_restore_istate(dda_t *dda, dda_istate_t *istate) 3403 { 3404 dda->dda_index_offset = istate->dda_index_offset; 3405 dda->dda_index = istate->dda_index; 3406 dda->dda_pos = istate->dda_pos; 3407 if (istate->dda_flags & DDA_FLAG_INDEX) { 3408 DDA_SET_INDEX(dda); 3409 } 3410 } 3411 3412 /* alignment */ 3413 3414 /* 3415 * dda_stripe_align 3416 * 3417 * Parameters: 3418 * - dda: DDA tape drive. 3419 * 3420 * Align data file offset following after a filemark. 3421 * 3422 * Return Values: 3423 * Aligned data file offset. 3424 * 3425 */ 3426 static off64_t 3427 dda_stripe_align(dda_t *dda) 3428 { 3429 off64_t amount = 0; 3430 3431 DDA_DEBUG1((dda_stripe_align_enter, 3432 int, dda->dda_inst)); 3433 3434 /* 3435 * Called at bot write or when write data follows a file mark. 3436 */ 3437 if (dda->dda_metadata.dda_stripe > 0) { 3438 /* 3439 * Start tape file on stripe boundary 3440 */ 3441 amount = dda->dda_index.dda_offset % 3442 dda->dda_metadata.dda_stripe; 3443 3444 DDA_DEBUG3((dda_stripe_align_amount, 3445 int, dda->dda_inst, 3446 int32_t, dda->dda_metadata.dda_stripe, 3447 off64_t, amount)); 3448 3449 if (amount) { 3450 /* 3451 * Stripe adjustment needed. 3452 */ 3453 amount = dda->dda_metadata.dda_stripe - amount; 3454 3455 DDA_DEBUG3((dda_stripe_align, 3456 int, dda->dda_inst, 3457 int32_t, dda->dda_metadata.dda_stripe, 3458 off64_t, amount)); 3459 } 3460 } 3461 return (amount); 3462 } 3463 3464 /* 3465 * dda_data_offset 3466 * 3467 * Parameters: 3468 * - dda: DDA tape drive. 3469 * 3470 * Generate data file offset using the index record and 3471 * metadata direct I/O alignment. 3472 * 3473 * Return Values: 3474 * Data file offset. 3475 * 3476 */ 3477 static off64_t 3478 dda_data_offset(dda_t *dda) 3479 { 3480 off64_t offset; 3481 off64_t amount; 3482 int32_t sector = dda->dda_metadata.dda_sector; 3483 3484 offset = dda->dda_index.dda_offset; 3485 3486 DDA_DEBUG2((dda_data_offset_start, 3487 int, dda->dda_inst, 3488 off64_t, offset)); 3489 3490 if (dda->dda_pos <= dda->dda_index.dda_blkcount) { 3491 3492 offset += (dda->dda_pos * dda->dda_index.dda_blksize); 3493 3494 DDA_DEBUG2((dda_data_offset_le, 3495 int, dda->dda_inst, 3496 off64_t, offset)); 3497 3498 } else { 3499 3500 offset += (dda->dda_index.dda_blkcount * 3501 dda->dda_index.dda_blksize); 3502 3503 DDA_DEBUG2((dda_data_offset_gt, 3504 int, dda->dda_inst, 3505 off64_t, offset)); 3506 3507 } 3508 3509 if (dda->dda_metadata.dda_sector > 0 && 3510 DDA_LEN_ALIGNED(dda->dda_index.dda_blksize, sector) == 0) { 3511 3512 /* adjust for direct I/O */ 3513 3514 amount = DDA_OFF_ALIGNED(offset, sector); 3515 3516 if (amount) { 3517 3518 /* bytes needed for sector alignment */ 3519 3520 amount = sector - amount; 3521 } 3522 3523 offset += amount; 3524 3525 DDA_DEBUG3((dda_data_offset_align, 3526 int, dda->dda_inst, 3527 off64_t, offset, 3528 off64_t, amount)); 3529 } 3530 3531 DDA_DEBUG3((dda_data_offset, 3532 int, dda->dda_inst, 3533 int64_t, DDA_LBA(dda), 3534 off64_t, offset)); 3535 3536 return (offset); 3537 } 3538 3539 /* space */ 3540 3541 /* 3542 * dda_tape_capacity 3543 * 3544 * Parameters: 3545 * - dda: DDA tape drive. 3546 * - space: Amount of space remaining to eom. 3547 * 3548 * The amount of available space remaining to eom is from the last 3549 * data or fm on tape to phyical eom. The position on media does not 3550 * change the space remaining calculation. Filemarks count as 1 byte 3551 * of used capacity. The size of the three media files (metadata, 3552 * index, and data) are also subtracted from the capacity. 3553 * 3554 * Return Values: 3555 * 0 : success 3556 * errno : failure 3557 * 3558 */ 3559 static int 3560 dda_tape_capacity(dda_t *dda, int64_t *space) 3561 { 3562 int err; 3563 dda_index_t last_index; 3564 off64_t last_index_offset; 3565 off64_t last_index_fileno; 3566 off64_t last_index_fmcount; 3567 3568 3569 /* get offset of last index file record */ 3570 last_index_offset = dda->dda_index_fsize - sizeof (dda_index_t); 3571 if (last_index_offset < 0) { 3572 dda->dda_status = KEY_MEDIUM_ERROR; 3573 return (EIO); 3574 } 3575 3576 /* get total number of filemarks on tape */ 3577 if (dda->dda_index_offset >= last_index_offset) { 3578 /* current or next index record is the last index record */ 3579 last_index_fileno = dda->dda_index.dda_fileno; 3580 last_index_fmcount = dda->dda_index.dda_fmcount; 3581 } else { 3582 /* read last index record */ 3583 if (err = dda_vn_read(dda, dda->dda_index_vp, &last_index, 3584 sizeof (dda_index_t), last_index_offset)) { 3585 return (err); 3586 } 3587 DDA_BE_INDEX(last_index, last_index); 3588 last_index_fileno = last_index.dda_fileno; 3589 last_index_fmcount = last_index.dda_fmcount; 3590 } 3591 3592 *space = dda->dda_metadata.dda_capacity - /* max cart size minus */ 3593 dda->dda_data_fsize - /* data file size */ 3594 sizeof (dda_metadata_t) - /* metadata file size */ 3595 dda->dda_index_fsize - /* index file size */ 3596 last_index_fileno - /* total num of prev fms */ 3597 last_index_fmcount; /* remaining number of fms */ 3598 3599 if (*space < 0) { 3600 *space = 0; 3601 } 3602 3603 DDA_DEBUG3((dda_capacity, 3604 int, dda->dda_inst, 3605 int64_t, dda->dda_metadata.dda_capacity, 3606 int64_t, *space)); 3607 3608 return (0); 3609 } 3610 3611 /* 3612 * dda_ew_eom 3613 * 3614 * Parameters: 3615 * - dda: DDA tape drive. 3616 * - count: Bytes to write. 3617 * - avail: Bytes available on media. 3618 * - ew: Early warning. 3619 * 3620 * On return avail contains the number of bytes that can be written 3621 * to the media. The ew flag is set if the write is past early warning. 3622 * 3623 * Return Values: 3624 * 0 : success 3625 * errno : failure 3626 * 3627 */ 3628 static int 3629 dda_ew_eom(dda_t *dda, int32_t count, int64_t *avail, int *ew) 3630 { 3631 int64_t space; 3632 int err; 3633 int64_t used; 3634 3635 if (err = dda_tape_capacity(dda, &space)) { 3636 return (err); 3637 } 3638 3639 used = dda->dda_metadata.dda_capacity - space; 3640 3641 if (used + count >= dda->dda_early_warn) { 3642 *ew = 1; 3643 } else { 3644 *ew = 0; 3645 } 3646 if (used + count > dda->dda_metadata.dda_capacity) { 3647 *avail = space; 3648 } else { 3649 *avail = count; 3650 } 3651 3652 DDA_DEBUG4((dda_ew_eom, 3653 int, dda->dda_inst, 3654 int32_t, count, 3655 int64_t, *avail, 3656 int, *ew)); 3657 3658 return (0); 3659 } 3660 3661 /* search */ 3662 3663 /* 3664 * dda_locate_compare 3665 * 3666 * Parameters: 3667 * - dda: DDA tape drive. 3668 * - lba: Locate to LBA. 3669 * 3670 * Locate LBA binary search compare function. 3671 * 3672 * Return Values: 3673 * 0 : found 3674 * 1 : forward 3675 * -1 : backward 3676 * 3677 */ 3678 static int 3679 dda_locate_compare(dda_t *dda, int64_t lba) 3680 { 3681 int64_t last; 3682 3683 last = dda->dda_index.dda_lba + DDA_INDEX_COUNT(dda); 3684 3685 if (lba >= dda->dda_index.dda_lba && lba <= last) { 3686 3687 dda->dda_pos = lba - dda->dda_index.dda_lba; 3688 3689 return (0); 3690 } 3691 3692 if (lba < dda->dda_index.dda_lba) { 3693 return (-1); 3694 } 3695 3696 return (1); 3697 } 3698 3699 /* 3700 * dda_fsf_compare 3701 * 3702 * Parameters: 3703 * - dda: DDA tape drive. 3704 * - fileno: Locate file number. 3705 * 3706 * Forward space file binary search compare function. 3707 * 3708 * Return Values: 3709 * 0 : found 3710 * 1 : forward 3711 * -1 : backward 3712 * 3713 */ 3714 static int 3715 dda_fsf_compare(dda_t *dda, int64_t fileno) 3716 { 3717 int64_t last; 3718 3719 if (dda->dda_index.dda_fmcount) { 3720 3721 last = dda->dda_index.dda_fileno + dda->dda_index.dda_fmcount; 3722 3723 if (fileno > dda->dda_index.dda_fileno && fileno <= last) { 3724 3725 dda->dda_pos = dda->dda_index.dda_blkcount + 3726 fileno - dda->dda_index.dda_fileno; 3727 3728 return (0); 3729 } 3730 } 3731 3732 if (fileno <= dda->dda_index.dda_fileno) { 3733 return (-1); 3734 } 3735 3736 return (1); 3737 } 3738 3739 /* 3740 * dda_bsf_compare 3741 * 3742 * Parameters: 3743 * - dda: DDA tape drive. 3744 * - fileno: Locate file number. 3745 * 3746 * Backward space file binary search compare function. 3747 * 3748 * Return Values: 3749 * 0 : found 3750 * 1 : forward 3751 * -1 : backward 3752 * 3753 */ 3754 static int 3755 dda_bsf_compare(dda_t *dda, int64_t fileno) 3756 { 3757 int64_t last; 3758 3759 if (dda->dda_index.dda_fmcount) { 3760 3761 last = dda->dda_index.dda_fileno + dda->dda_index.dda_fmcount; 3762 3763 if (fileno >= dda->dda_index.dda_fileno && fileno < last) { 3764 3765 dda->dda_pos = dda->dda_index.dda_blkcount + 3766 fileno - dda->dda_index.dda_fileno; 3767 3768 return (0); 3769 } 3770 } 3771 3772 if (fileno < dda->dda_index.dda_fileno) { 3773 return (-1); 3774 } 3775 3776 return (1); 3777 } 3778 3779 /* 3780 * dda_bsearch 3781 * 3782 * Parameters: 3783 * - dda: DDA tape drive. 3784 * - key: LBA or file number. 3785 * - compare: Binary search comparison function. 3786 * - found: Search successful. 3787 * 3788 * Binary search index file records for LBA or fileno. 3789 * 3790 * Return Values: 3791 * 0 : success 3792 * errno : fs failure 3793 * 3794 */ 3795 static int 3796 dda_bsearch(dda_t *dda, 3797 int64_t key, 3798 int (*compare)(dda_t *, int64_t), 3799 int *found) 3800 { 3801 int err; 3802 int res; 3803 off64_t nel, width, base, two_width, last; 3804 3805 /* 3806 * Index file binary search for lba or fileno 3807 */ 3808 3809 DDA_DEBUG2((dda_bsearch, 3810 int, dda->dda_inst, 3811 int64_t, key)); 3812 3813 *found = 0; 3814 3815 /* bsearch(3C) */ 3816 width = sizeof (dda_index_t); 3817 two_width = width + width; 3818 3819 base = 0; 3820 nel = dda->dda_index_fsize / sizeof (dda_index_t); 3821 last = base + width * (nel - 1); 3822 3823 while (last >= base) { 3824 3825 dda->dda_index_offset = 3826 base + width * ((last - base) / two_width); 3827 3828 if (err = dda_read_index(dda)) { 3829 return (err); 3830 } 3831 3832 res = compare(dda, key); 3833 3834 if (res == 0) { 3835 *found = 1; 3836 return (0); 3837 } 3838 3839 if (res < 0) { 3840 last = dda->dda_index_offset - width; 3841 } else { 3842 base = dda->dda_index_offset + width; 3843 } 3844 } 3845 3846 return (0); 3847 } 3848 3849 /* vnode operations */ 3850 3851 /* 3852 * dda_vn_open 3853 * 3854 * Parameters: 3855 * - dda: DDA tape drive. 3856 * - vpp: Pointer to a vnode file pointer. 3857 * - fname: Filename to open. 3858 * 3859 * Open a dda media file from the kernel. 3860 * Ensure the dda user has permission to open the file. 3861 * On error convert the file open error into a sense key. 3862 * 3863 * Return Values: 3864 * 0 : success 3865 * errno : failure 3866 * 3867 */ 3868 static int 3869 dda_vn_open(dda_t *dda, struct vnode **vpp, char *fname) 3870 { 3871 int err; 3872 3873 if (err = vn_open(fname, UIO_SYSSPACE, DDA_VNODE_MODE, 0, vpp, 0, 0)) { 3874 DDA_DEBUG3((dda_vn_open_err, 3875 int, dda->dda_inst, 3876 char *, fname, 3877 int, err)); 3878 *vpp = NULL; 3879 dda_vn_error_skey(dda, err); 3880 return (err); 3881 } 3882 3883 err = VOP_ACCESS(*vpp, DDA_VNODE_MODE, 0, dda->dda_cred, NULL); 3884 if (err) { 3885 DDA_DEBUG3((dda_vn_open_access, 3886 int, dda->dda_inst, 3887 char *, fname, 3888 int, err)); 3889 (void) VOP_CLOSE(*vpp, DDA_VNODE_MODE, 1, (offset_t)0, 3890 dda->dda_cred, NULL); 3891 VN_RELE(*vpp); 3892 *vpp = NULL; 3893 dda_vn_error_skey(dda, err); 3894 } 3895 return (err); 3896 } 3897 3898 /* 3899 * dda_vn_close 3900 * 3901 * Parameters: 3902 * - dda: DDA tape drive. 3903 * - vpp: Pointer to a vnode file pointer. 3904 * 3905 * Close dda media file from the kernel. 3906 * On error convert the file close error into a sense key. 3907 * 3908 * Return Values: 3909 * 0 : success 3910 * errno : failure 3911 * 3912 */ 3913 static int 3914 dda_vn_close(dda_t *dda, struct vnode **vpp) 3915 { 3916 int err; 3917 3918 if (*vpp == NULL) { 3919 DDA_DEBUG1((dda_vn_close_null, 3920 int, dda->dda_inst)); 3921 dda->dda_status = KEY_MEDIUM_ERROR; 3922 return (EIO); 3923 } 3924 3925 err = VOP_CLOSE(*vpp, DDA_VNODE_MODE, 1, (offset_t)0, 3926 dda->dda_cred, NULL); 3927 if (err) { 3928 DDA_DEBUG3((dda_vn_close_err, 3929 int, dda->dda_inst, 3930 char *, dda_vn_get_fname(dda, *vpp), 3931 int, err)); 3932 dda_vn_error_skey(dda, err); 3933 } 3934 VN_RELE(*vpp); 3935 *vpp = NULL; 3936 return (err); 3937 } 3938 3939 /* 3940 * dda_vn_lock 3941 * 3942 * Parameters: 3943 * - dda: DDA tape drive. 3944 * - vp: Vnode pointer to open file. 3945 * - cmd: File lock or unlock command. 3946 * 3947 * Set or unset a file lock on the entire file. 3948 * The file lock is held by the driver while the media is loaded. 3949 * 3950 * Return Values: 3951 * 0 : success 3952 * errno : failure 3953 * 3954 */ 3955 static int 3956 dda_vn_lock(dda_t *dda, struct vnode *vp, short cmd) 3957 { 3958 flock64_t flk; 3959 int err; 3960 3961 if (vp == NULL) { 3962 DDA_DEBUG1((dda_vn_lock_null, 3963 int, dda->dda_inst)); 3964 dda->dda_status = KEY_MEDIUM_ERROR; 3965 return (EIO); 3966 } 3967 3968 /* lock or unlock entire file */ 3969 bzero(&flk, sizeof (flock64_t)); 3970 flk.l_type = cmd; 3971 3972 /* non-blocking file lock */ 3973 err = VOP_FRLOCK(vp, F_SETLK, &flk, FREAD | FWRITE, 3974 0, NULL, dda->dda_cred, NULL); 3975 3976 if (cmd == F_UNLCK && vn_has_flocks(vp)) { 3977 cleanlocks(vp, IGN_PID, 0); 3978 } 3979 3980 if (err) { 3981 DDA_DEBUG4((dda_vn_lock_err, 3982 int, dda->dda_inst, 3983 char *, dda_vn_get_fname(dda, vp), 3984 int, cmd, 3985 int, err)); 3986 dda_vn_error_skey(dda, err); 3987 } 3988 3989 return (err); 3990 } 3991 3992 /* 3993 * dda_vn_read 3994 * 3995 * Parameters: 3996 * - dda: DDA tape drive. 3997 * - vp: Vnode file pointer. 3998 * - buf: File read buffer. 3999 * - len: Length of read buffer. 4000 * - offset: File offset to begin reading from. 4001 * 4002 * From the kernel read the requested buffer length from the file. 4003 * On error convert the file read error into a sense key. 4004 * 4005 * Return Values: 4006 * 0 : success 4007 * errno : failure 4008 * 4009 */ 4010 static int 4011 dda_vn_read(dda_t *dda, struct vnode *vp, void *buf, int len, off64_t offset) 4012 { 4013 int err; 4014 struct iovec iov; 4015 struct uio uio; 4016 4017 if (vp == NULL) { 4018 DDA_DEBUG1((dda_vn_read_null, 4019 int, dda->dda_inst)); 4020 dda->dda_status = KEY_MEDIUM_ERROR; 4021 return (EIO); 4022 } 4023 4024 iov.iov_base = (caddr_t)buf; 4025 iov.iov_len = len; 4026 4027 uio.uio_iov = &iov; 4028 uio.uio_iovcnt = 1; 4029 uio.uio_segflg = UIO_SYSSPACE; 4030 uio.uio_loffset = offset; 4031 uio.uio_resid = len; 4032 uio.uio_fmode = FREAD; 4033 uio.uio_llimit = MAXOFFSET_T; 4034 4035 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 4036 err = VOP_READ(vp, &uio, 0, dda->dda_cred, NULL); 4037 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 4038 4039 if (err) { 4040 DDA_DEBUG4((dda_vn_read_err, 4041 int, dda->dda_inst, 4042 char *, dda_vn_get_fname(dda, vp), 4043 off64_t, offset, 4044 int, err)); 4045 dda_vn_error_skey(dda, err); 4046 return (err); 4047 } 4048 4049 if (uio.uio_resid != 0) { 4050 DDA_DEBUG4((dda_vn_read_resid, 4051 int, dda->dda_inst, 4052 char *, dda_vn_get_fname(dda, vp), 4053 off64_t, offset, 4054 int32_t, uio.uio_resid)); 4055 dda->dda_status = KEY_MEDIUM_ERROR; 4056 return (EIO); 4057 } 4058 return (0); 4059 } 4060 4061 /* 4062 * dda_vn_write 4063 * 4064 * Parameters: 4065 * - dda: DDA tape drive. 4066 * - vp: Vnode file pointer. 4067 * - buf: File write buffer. 4068 * - len: Length of write buffer. 4069 * - offset: File offset to begin writing. 4070 * 4071 * From the kernel write the requested buffer length to the file. 4072 * On error convert the file write error into a sense key. 4073 * 4074 * Return Values: 4075 * 0 : success 4076 * errno : failure 4077 * 4078 */ 4079 static int 4080 dda_vn_write(dda_t *dda, struct vnode *vp, void *buf, int len, off64_t offset) 4081 { 4082 int err; 4083 struct iovec iov; 4084 struct uio uio; 4085 4086 if (vp == NULL) { 4087 DDA_DEBUG1((dda_vn_write_null, 4088 int, dda->dda_inst)); 4089 dda->dda_status = KEY_MEDIUM_ERROR; 4090 return (EIO); 4091 } 4092 4093 iov.iov_base = (caddr_t)buf; 4094 iov.iov_len = len; 4095 4096 uio.uio_iov = &iov; 4097 uio.uio_iovcnt = 1; 4098 uio.uio_segflg = UIO_SYSSPACE; 4099 uio.uio_loffset = offset; 4100 uio.uio_resid = len; 4101 uio.uio_fmode = FWRITE; 4102 uio.uio_llimit = MAXOFFSET_T; 4103 4104 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 4105 err = VOP_WRITE(vp, &uio, FWRITE|FTRUNC, dda->dda_cred, NULL); 4106 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 4107 4108 if (err) { 4109 DDA_DEBUG4((dda_vn_write_err, 4110 int, dda->dda_inst, 4111 char *, dda_vn_get_fname(dda, vp), 4112 off64_t, offset, 4113 int, err)); 4114 dda_vn_error_skey(dda, err); 4115 return (err); 4116 } 4117 4118 if (uio.uio_resid != 0) { 4119 DDA_DEBUG4((dda_vn_write_resid, 4120 int, dda->dda_inst, 4121 char *, dda_vn_get_fname(dda, vp), 4122 off64_t, offset, 4123 int32_t, uio.uio_resid)); 4124 dda->dda_status = KEY_MEDIUM_ERROR; 4125 return (EIO); 4126 } 4127 return (0); 4128 } 4129 4130 /* 4131 * dda_vn_truncate 4132 * 4133 * Parameters: 4134 * - dda: DDA tape drive. 4135 * - vp: Vnode file pointer. 4136 * - offset: Truncate file at offset. 4137 * 4138 * Truncate the file. 4139 * On error convert the file truncate error into a sense key. 4140 * 4141 * Return Values: 4142 * 0 : success 4143 * errno : failure 4144 * 4145 */ 4146 static int 4147 dda_vn_truncate(dda_t *dda, struct vnode *vp, off64_t offset) 4148 { 4149 int err; 4150 struct vattr vattr; 4151 4152 if (vp == NULL) { 4153 DDA_DEBUG1((dda_vn_truncate_null, 4154 int, dda->dda_inst)); 4155 dda->dda_status = KEY_MEDIUM_ERROR; 4156 return (EIO); 4157 } 4158 4159 vattr.va_size = offset; 4160 vattr.va_mask = AT_SIZE; 4161 err = VOP_SETATTR(vp, &vattr, 0, dda->dda_cred, NULL); 4162 if (err) { 4163 DDA_DEBUG4((dda_vn_truncate_err, 4164 int, dda->dda_inst, 4165 char *, dda_vn_get_fname(dda, vp), 4166 off64_t, offset, 4167 int, err)); 4168 dda_vn_error_skey(dda, err); 4169 } 4170 return (err); 4171 } 4172 4173 /* 4174 * dda_vn_sync 4175 * 4176 * Parameters: 4177 * - dda: DDA tape drive. 4178 * - vp: Vnode file pointer. 4179 * 4180 * Flush file to disk. 4181 * On error convert the file flush error into a sense key. 4182 * 4183 * Return Values: 4184 * 0 : success 4185 * errno : failure 4186 * 4187 */ 4188 static int 4189 dda_vn_sync(dda_t *dda, struct vnode *vp) 4190 { 4191 int err; 4192 4193 if (vp == NULL) { 4194 DDA_DEBUG1((dda_vn_sync_null, 4195 int, dda->dda_inst)); 4196 dda->dda_status = KEY_MEDIUM_ERROR; 4197 return (EIO); 4198 } 4199 4200 err = VOP_FSYNC(vp, FSYNC, dda->dda_cred, NULL); 4201 if (err) { 4202 DDA_DEBUG3((dda_vn_sync_err, 4203 int, dda->dda_inst, 4204 char *, dda_vn_get_fname(dda, vp), 4205 int, err)); 4206 dda_vn_error_skey(dda, err); 4207 } 4208 return (err); 4209 } 4210 4211 /* 4212 * dda_vn_size 4213 * 4214 * Parameters: 4215 * - dda: DDA tape drive. 4216 * - vp: Vnode file pointer. 4217 * - fsize: File size. 4218 * 4219 * Get dda media file size. 4220 * On error convert the file size error into a sense key. 4221 * 4222 * Return Values: 4223 * 0 : success 4224 * errno : failure 4225 * 4226 */ 4227 static int 4228 dda_vn_size(dda_t *dda, struct vnode *vp, off64_t *fsize) 4229 { 4230 int err; 4231 struct vattr vattr; 4232 4233 if (vp == NULL) { 4234 DDA_DEBUG1((dda_vn_size_null, 4235 int, dda->dda_inst)); 4236 dda->dda_status = KEY_MEDIUM_ERROR; 4237 return (EIO); 4238 } 4239 4240 vattr.va_mask = AT_SIZE; 4241 err = VOP_GETATTR(vp, &vattr, 0, dda->dda_cred, NULL); 4242 if (err) { 4243 DDA_DEBUG3((dda_vn_size_err, 4244 int, dda->dda_inst, 4245 char *, dda_vn_get_fname(dda, vp), 4246 int, err)); 4247 dda_vn_error_skey(dda, err); 4248 } else { 4249 *fsize = (off64_t)vattr.va_size; 4250 } 4251 return (err); 4252 } 4253 4254 /* 4255 * dda_vn_get_fname 4256 * 4257 * Parameters: 4258 * - dda: DDA tape drive. 4259 * - vp: Vnode file pointer. 4260 * 4261 * Get dda media filename from the vnode pointer for tracing. 4262 * 4263 * Return Values: 4264 * filename 4265 * 4266 */ 4267 static char * 4268 dda_vn_get_fname(dda_t *dda, struct vnode *vp) 4269 { 4270 char *fname; 4271 4272 if (vp == dda->dda_metadata_vp) { 4273 fname = DDA_METADATA_FNAME; 4274 } else if (vp == dda->dda_index_vp) { 4275 fname = DDA_INDEX_FNAME; 4276 } else if (vp == dda->dda_data_vp) { 4277 fname = DDA_DATA_FNAME; 4278 } else { 4279 fname = DDA_UNKNOWN_FNAME; 4280 } 4281 return (fname); 4282 } 4283 4284 /* 4285 * dda_vn_error_skey 4286 * 4287 * Parameters: 4288 * - dda: DDA tape drive. 4289 * - int: errno 4290 * 4291 * Convert filesystem or kernel errno into tape drive sense key. 4292 * 4293 * Return Values: 4294 * None 4295 * 4296 */ 4297 static void 4298 dda_vn_error_skey(dda_t *dda, int err) 4299 { 4300 switch (err) { 4301 case 0: /* no error */ 4302 dda->dda_status = KEY_NO_SENSE; 4303 break; 4304 case EINVAL: /* invalid arg */ 4305 dda->dda_status = KEY_ILLEGAL_REQUEST; 4306 break; 4307 case EFBIG: /* file too large */ 4308 case ENOSPC: /* no space */ 4309 dda->dda_status = SUN_KEY_EOT; 4310 break; 4311 case EACCES: /* permission denied */ 4312 case EROFS: /* read only fs */ 4313 dda->dda_status = KEY_WRITE_PROTECT; 4314 break; 4315 case EISDIR: /* is directory */ 4316 case ENOENT: /* no such file or directory */ 4317 dda->dda_status = KEY_MEDIUM_ERROR; 4318 break; 4319 /* ESTALE: stale nfs file handle */ 4320 /* EMFILE: too many open files */ 4321 /* EMLINK: too many links */ 4322 /* EAGAIN: resource temporarily unavailable */ 4323 /* ENOMEM: not enough core */ 4324 /* ENOLCK: no record locks available */ 4325 default: 4326 dda->dda_status = KEY_RECOVERABLE_ERROR; 4327 break; 4328 } 4329 } 4330