|
|
1.1 ! root 1: /* @(#)st.c 1.1 86/02/03 SMI */ ! 2: ! 3: /* ! 4: * Copyright (c) 1985 by Sun Microsystems, Inc. ! 5: */ ! 6: ! 7: #include "st.h" ! 8: #if NST > 0 ! 9: ! 10: /* ! 11: * Driver for Sysgen SC400 and Emulex MT02 SCSI tape controller. ! 12: */ ! 13: ! 14: #include "../h/param.h" ! 15: #include "../h/systm.h" ! 16: #include "../h/buf.h" ! 17: #include "../h/dir.h" ! 18: #include "../h/conf.h" ! 19: #include "../h/user.h" ! 20: #include "../h/file.h" ! 21: #include "../h/map.h" ! 22: #include "../h/vm.h" ! 23: #include "../h/mtio.h" ! 24: #include "../h/cmap.h" ! 25: ! 26: #include "../sun/dklabel.h" ! 27: #include "../sun/dkio.h" ! 28: #include "../machine/psl.h" ! 29: #include "../machine/mmu.h" ! 30: #include "../machine/cpu.h" ! 31: #include "../sundev/mbvar.h" ! 32: #include "../sundev/screg.h" ! 33: #include "../sundev/sireg.h" ! 34: #include "../sundev/scsi.h" ! 35: #include "../sundev/streg.h" ! 36: ! 37: #define INF 1000000000 ! 38: /* ! 39: * Max # of buffers outstanding per unit. ! 40: */ ! 41: #define MAXSTBUF 3 ! 42: ! 43: /* ! 44: * Bits in minor device. ! 45: */ ! 46: #define STUNIT(dev) (minor(dev) & 03) ! 47: #define T_NOREWIND 04 ! 48: #define QIC_24 8 ! 49: ! 50: extern struct scsi_unit stunits[]; ! 51: extern struct scsi_unit_subr scsi_unit_subr[]; ! 52: extern struct scsi_tape stape[]; ! 53: extern int nstape; ! 54: ! 55: /* ! 56: * Return a pointer to this unit's unit structure. ! 57: */ ! 58: stunitptr(md) ! 59: register struct mb_device *md; ! 60: { ! 61: return ((int)&stunits[md->md_unit]); ! 62: } ! 63: ! 64: /* ! 65: * Attach device (boot time). ! 66: */ ! 67: stattach(md) ! 68: register struct mb_device *md; ! 69: { ! 70: register struct scsi_unit *un; ! 71: register struct scsi_tape *dsi; ! 72: ! 73: un = &stunits[md->md_unit]; ! 74: dsi = &stape[md->md_unit]; ! 75: un->un_md = md; ! 76: un->un_mc = md->md_mc; ! 77: un->un_unit = md->md_unit; ! 78: un->un_target = TARGET(md->md_slave); ! 79: un->un_lun = LUN(md->md_slave); ! 80: un->un_ss = &scsi_unit_subr[TYPE(md->md_flags)]; ! 81: dsi->un_ctype = ST_TYPE_INVALID; ! 82: dsi->un_openf = CLOSED; ! 83: } ! 84: ! 85: stinit(dev) ! 86: dev_t dev; ! 87: { ! 88: register int unit; ! 89: register struct scsi_tape *dsi; ! 90: ! 91: unit = STUNIT(dev); ! 92: dsi = &stape[unit]; ! 93: ! 94: dsi->un_ctype = 1; ! 95: dsi->un_openf = OPENING; ! 96: stcmd(dev, SC_TEST_UNIT_READY, 0); ! 97: if (stcmd(dev, SC_REQUEST_SENSE, 0) == 0 || dsi->un_openf != OPEN) { ! 98: dsi->un_openf = OPENING; ! 99: if (stcmd(dev, SC_REQUEST_SENSE, 0) == 0 || ! 100: dsi->un_openf != OPEN) { ! 101: if (stcmd(dev, SC_REQUEST_SENSE, 0) == 0 || ! 102: dsi->un_openf != OPEN) { ! 103: if (dsi->un_openf == OPEN_FAILED) { ! 104: uprintf("st%d: no cartridge loaded\n", ! 105: unit); ! 106: } else { ! 107: uprintf("st%d: tape not online \n", ! 108: unit); ! 109: } ! 110: dsi->un_openf = CLOSED; ! 111: dsi->un_ctype = ST_TYPE_INVALID; ! 112: return (0); ! 113: } ! 114: } ! 115: } ! 116: dsi->un_openf = CLOSED; ! 117: return (1); ! 118: } ! 119: ! 120: sctopen(dev, flag) ! 121: dev_t dev; ! 122: int flag; ! 123: { ! 124: register struct scsi_unit *un; ! 125: register int unit, s; ! 126: register struct scsi_tape *dsi; ! 127: register int i; ! 128: ! 129: unit = STUNIT(dev); ! 130: if (unit > nstape) { ! 131: u.u_error = ENXIO; ! 132: return; ! 133: } ! 134: un = &stunits[unit]; ! 135: dsi = &stape[unit]; ! 136: if (un->un_mc == 0) { /* never attached */ ! 137: u.u_error = ENXIO; ! 138: return; ! 139: } ! 140: ! 141: /* determine type of tape controller */ ! 142: if (dsi->un_ctype == ST_TYPE_INVALID) { ! 143: if (stinit(dev) == 0) { ! 144: u.u_error = EIO; ! 145: return; ! 146: } ! 147: } ! 148: ! 149: s = spl6(); ! 150: if (dsi->un_openf != CLOSED) { /* already open */ ! 151: (void) splx(s); ! 152: u.u_error = EBUSY; ! 153: return; ! 154: } ! 155: dsi->un_openf = OPEN; ! 156: (void) splx(s); ! 157: dsi->un_read_only = 0; ! 158: ! 159: /* must be qic 24 format */ ! 160: if (!(minor(dev) & QIC_24)) { ! 161: dsi->un_openf = CLOSED; ! 162: u.u_error = EIO; ! 163: return; ! 164: } ! 165: if ((flag & FWRITE) && dsi->un_read_only) { ! 166: uprintf("st%d: cartridge is write protected \n", unit); ! 167: dsi->un_openf = CLOSED; ! 168: u.u_error = EIO; ! 169: return; ! 170: } ! 171: dsi->un_lastiow = 0; ! 172: dsi->un_lastior = 0; ! 173: dsi->un_next_block = 0; ! 174: dsi->un_last_block = INF; ! 175: /* if we reset these here they will never be preserved for "mt status" ! 176: dsi->un_retry_ct = 0; ! 177: dsi->un_underruns = 0; ! 178: */ ! 179: u.u_error = 0; ! 180: return; ! 181: } ! 182: ! 183: /*ARGSUSED*/ ! 184: sctclose(dev, flag) ! 185: register dev_t dev; ! 186: int flag; ! 187: { ! 188: register struct scsi_unit *un; ! 189: register struct scsi_tape *dsi; ! 190: ! 191: un = &stunits[STUNIT(dev)]; ! 192: dsi = &stape[STUNIT(dev)]; ! 193: dsi->un_openf = CLOSING; ! 194: if (dsi->un_lastiow) { ! 195: if (stcmd(dev, SC_WRITE_FILE_MARK, 0) == 0) { ! 196: printf("st%d: stclose failed to write file mark\n", ! 197: un - stunits); ! 198: } ! 199: } ! 200: if ((minor(dev) & T_NOREWIND) == 0) { ! 201: (void) stcmd(dev, SC_REWIND, -1); ! 202: } ! 203: dsi->un_openf = CLOSED; ! 204: } ! 205: ! 206: stcmd(dev, cmd, count) ! 207: dev_t dev; ! 208: int cmd, count; ! 209: { ! 210: register struct buf *bp; ! 211: register int s, error; ! 212: register struct scsi_unit *un; ! 213: ! 214: un = &stunits[STUNIT(dev)]; ! 215: bp = &un->un_sbuf; ! 216: s = splx(pritospl(un->un_mc->mc_intpri)); ! 217: while (bp->b_flags & B_BUSY) { ! 218: /* ! 219: * special test because B_BUSY never gets cleared in ! 220: * the non-waiting rewind case. ! 221: */ ! 222: if (bp->b_bcount == -1 && (bp->b_flags & B_DONE)) { ! 223: break; ! 224: } ! 225: bp->b_flags |= B_WANTED; ! 226: sleep((caddr_t) bp, PRIBIO); ! 227: } ! 228: bp->b_flags = B_BUSY | B_READ; ! 229: (void) splx(s); ! 230: bp->b_dev = dev; ! 231: bp->b_bcount = count; ! 232: un->un_scmd = cmd; ! 233: ststrategy(bp); ! 234: /* ! 235: * In case of rewind on close, don't wait. ! 236: */ ! 237: if (cmd == SC_REWIND && count == -1) { ! 238: return (1); ! 239: } ! 240: s = splx(pritospl(un->un_mc->mc_intpri)); ! 241: while ((bp->b_flags & B_DONE) == 0) { ! 242: sleep((caddr_t) bp, PRIBIO); ! 243: } ! 244: (void) splx(s); ! 245: error = geterror(bp); ! 246: if (bp->b_flags & B_WANTED) { ! 247: wakeup((caddr_t) bp); ! 248: } ! 249: bp->b_flags &= B_ERROR; /* clears B_BUSY */ ! 250: return (error == 0); ! 251: } ! 252: ! 253: ststrategy(bp) ! 254: register struct buf *bp; ! 255: { ! 256: register struct scsi_unit *un; ! 257: register int unit, s; ! 258: register struct buf *ap; ! 259: register struct scsi_tape *dsi; ! 260: ! 261: unit = STUNIT(bp->b_dev); ! 262: if (unit > nstape) { ! 263: printf("st%d: ststrategy: invalid unit %x\n", unit, unit); ! 264: bp->b_flags |= B_ERROR; ! 265: iodone(bp); ! 266: return; ! 267: } ! 268: un = &stunits[unit]; ! 269: dsi = &stape[unit]; ! 270: if (dsi->un_openf != OPEN && bp != &un->un_sbuf) { ! 271: bp->b_flags |= B_ERROR; ! 272: iodone(bp); ! 273: return; ! 274: } ! 275: s = splx(pritospl(un->un_mc->mc_intpri)); ! 276: while (dsi->un_bufcnt >= MAXSTBUF) { ! 277: sleep((caddr_t) &dsi->un_bufcnt, PRIBIO); ! 278: } ! 279: dsi->un_bufcnt++; ! 280: ! 281: /* ! 282: * Put the block at the end of the queue. ! 283: * Should probably have a pointer to the end of ! 284: * the queue, but the queue can't get too long, ! 285: * so the added code complexity probably isn't ! 286: * worth it. ! 287: */ ! 288: ap = &un->un_utab; ! 289: while (ap->b_actf != NULL) { ! 290: ap = ap->b_actf; ! 291: } ! 292: ap->b_actf = bp; ! 293: bp->b_actf = NULL; ! 294: if (un->un_utab.b_active == 0) { ! 295: (*un->un_c->c_ss->scs_ustart)(un); ! 296: bp = &un->un_mc->mc_tab; ! 297: if (bp->b_actf && bp->b_active == 0) { ! 298: (*un->un_c->c_ss->scs_start)(un); ! 299: } ! 300: } ! 301: (void) splx(s); ! 302: } ! 303: ! 304: /* ! 305: * Start the operation. ! 306: */ ! 307: /*ARGSUSED*/ ! 308: ststart(bp, un) ! 309: register struct buf *bp; ! 310: register struct scsi_unit *un; ! 311: { ! 312: register int bno; ! 313: register struct scsi_tape *dsi; ! 314: ! 315: dsi = &stape[STUNIT(bp->b_dev)]; ! 316: /* ! 317: * Default is that last command was NOT a read/write command; ! 318: * if we issue a read/write command we will notice this in stintr(). ! 319: */ ! 320: dsi->un_lastiow = 0; ! 321: dsi->un_lastior = 0; ! 322: if (bp == &un->un_sbuf) { ! 323: un->un_cmd = un->un_scmd; ! 324: un->un_count = bp->b_bcount; ! 325: } else if (bp == &un->un_rbuf) { ! 326: if (bp->b_flags & B_READ) { ! 327: if (dsi->un_eof) { ! 328: bp->b_resid = bp->b_bcount; ! 329: iodone(bp); ! 330: if (dsi->un_bufcnt-- >= MAXSTBUF) { ! 331: wakeup((caddr_t) &dsi->un_bufcnt); ! 332: } ! 333: return (0); ! 334: } ! 335: un->un_cmd = SC_READ; ! 336: } else { ! 337: un->un_cmd = SC_WRITE; ! 338: } ! 339: un->un_count = howmany(bp->b_bcount, DEV_BSIZE); ! 340: un->un_flags |= SC_UNF_DVMA; ! 341: } else { ! 342: bno = bp->b_blkno; ! 343: if (bno > dsi->un_last_block && bp->b_flags & B_READ) { ! 344: /* ! 345: * Can't read past EOF. ! 346: */ ! 347: bp->b_flags |= B_ERROR; ! 348: bp->b_error = EIO; ! 349: iodone(bp); ! 350: if (dsi->un_bufcnt-- >= MAXSTBUF) { ! 351: wakeup((caddr_t) &dsi->un_bufcnt); ! 352: } ! 353: return (0); ! 354: } ! 355: if (bno == dsi->un_last_block && bp->b_flags & B_READ) { ! 356: /* ! 357: * Reading at EOF returns 0 bytes. ! 358: */ ! 359: bp->b_resid = bp->b_bcount; ! 360: iodone(bp); ! 361: if (dsi->un_bufcnt-- >= MAXSTBUF) { ! 362: wakeup((caddr_t) &dsi->un_bufcnt); ! 363: } ! 364: return (0); ! 365: } ! 366: if ((bp->b_flags & B_READ) == 0) { ! 367: /* ! 368: * Writing sets EOF. ! 369: */ ! 370: dsi->un_last_block = bno + 1; ! 371: } ! 372: if (bno != dsi->un_next_block) { ! 373: /* ! 374: * Not the next record. ! 375: * In theory we could space forward, or even rewind ! 376: * and space forward, and maybe someday we will. ! 377: * For now, no one really needs this capability. ! 378: */ ! 379: bp->b_flags |= B_ERROR; ! 380: bp->b_error = ENXIO; ! 381: iodone(bp); ! 382: if (dsi->un_bufcnt-- >= MAXSTBUF) { ! 383: wakeup((caddr_t) &dsi->un_bufcnt); ! 384: } ! 385: return (0); ! 386: } ! 387: /* ! 388: * Position OK, we can do the read or write. ! 389: */ ! 390: if (bp->b_flags & B_READ) { ! 391: un->un_cmd = SC_READ; ! 392: } else { ! 393: un->un_cmd = SC_WRITE; ! 394: } ! 395: un->un_count = howmany(bp->b_bcount, DEV_BSIZE); ! 396: un->un_flags |= SC_UNF_DVMA; ! 397: } ! 398: bp->b_resid = 0; ! 399: return (1); ! 400: } ! 401: ! 402: /* ! 403: * Make a command description block. ! 404: */ ! 405: stmkcdb(c, un) ! 406: register struct scsi_ctlr *c; ! 407: register struct scsi_unit *un; ! 408: { ! 409: register struct scsi_cdb *cdb; ! 410: register struct scsi_tape *dsi; ! 411: int density = 0; ! 412: ! 413: cdb = &c->c_cdb; ! 414: bzero((caddr_t)cdb, sizeof (*cdb)); ! 415: cdb->cmd = un->un_cmd; ! 416: cdb->lun = un->un_lun; ! 417: un->un_dma_addr = un->un_dma_count = 0; ! 418: dsi = &stape[un->un_unit]; ! 419: ! 420: switch (un->un_cmd) { ! 421: ! 422: case SC_WRITE_FILE_MARK: ! 423: case SC_LOAD: ! 424: cdb->count = 1; ! 425: break; ! 426: ! 427: case SC_TEST_UNIT_READY: ! 428: break; ! 429: ! 430: case SC_REWIND: ! 431: break; ! 432: ! 433: case SC_ERASE_CARTRIDGE: ! 434: cdb->t_code = 1; ! 435: break; ! 436: ! 437: case SC_REQUEST_SENSE: ! 438: un->un_dma_addr = (int)c->c_sense - (int)DVMA; ! 439: un->un_dma_count = cdb->count = sizeof (struct st_archive_sense); ! 440: break; ! 441: ! 442: case SC_READ: ! 443: case SC_WRITE: ! 444: cdb->t_code = 1; ! 445: cdb->high_count = un->un_count >> 16; ! 446: cdb->mid_count = (un->un_count >> 8) & 0xFF; ! 447: cdb->low_count = un->un_count & 0xFF; ! 448: un->un_dma_addr = un->un_baddr; ! 449: un->un_dma_count = un->un_count * DEV_BSIZE; ! 450: break; ! 451: ! 452: case SC_SPACE_FILE: ! 453: if (un->un_count == 0) ! 454: cdb->t_code = 3; /* space to end */ ! 455: else ! 456: cdb->t_code = 1; /* space files, not records */ ! 457: /* fall through ... */ ! 458: ! 459: case SC_SPACE_REC: ! 460: cdb->cmd = SC_SPACE; ! 461: cdb->high_count = un->un_count >> 16; ! 462: cdb->mid_count = (un->un_count >> 8) & 0xFF; ! 463: cdb->low_count = un->un_count & 0xFF; ! 464: un->un_dma_addr = un->un_dma_count = 0; ! 465: break; ! 466: ! 467: default: ! 468: printf("st%d: stmkcdb: invalid command %x\n", un - stunits, ! 469: un->un_cmd); ! 470: break; ! 471: } ! 472: } ! 473: ! 474: stintr(c, resid, error) ! 475: register struct scsi_ctlr *c; ! 476: register int resid, error; ! 477: { ! 478: register struct scsi_unit *un; ! 479: register struct buf *bp; ! 480: register struct scsi_tape *dsi; ! 481: struct st_archive_sense *ars; ! 482: ! 483: un = c->c_un; ! 484: bp = un->un_mc->mc_tab.b_actf->b_actf; ! 485: dsi = &stape[STUNIT(bp->b_dev)]; ! 486: ars = (struct st_archive_sense *)c->c_sense; ! 487: ! 488: /* ! 489: * We determine which tape controller we have by the number of ! 490: * sense bytes we get back. ! 491: */ ! 492: if (dsi->un_openf == OPENING && un->un_cmd == SC_REQUEST_SENSE) { ! 493: if (resid || ST_NO_CART(dsi, c->c_sense)) { ! 494: dsi->un_openf = OPEN_FAILED; ! 495: } else { ! 496: dsi->un_openf = OPEN; ! 497: if (ST_WRITE_PROT(dsi, c->c_sense)) ! 498: dsi->un_read_only = 1; ! 499: } ! 500: } ! 501: ! 502: if (c->c_scb.busy) ! 503: bp->b_flags |= B_ERROR; ! 504: else if (error || c->c_scb.chk || resid > 0) { ! 505: if (c->c_scb.chk && ST_RESET(dsi, c->c_sense)) { ! 506: /* ! 507: * Power on or reset occurred ! 508: */ ! 509: dsi->un_reset_occurred = 1; ! 510: bp->b_flags |= B_ERROR; ! 511: } else if (c->c_scb.chk && ST_NO_CART(dsi, c->c_sense)) { ! 512: printf("st%d: no cartridge loaded \n", ! 513: un - stunits); ! 514: bp->b_flags |= B_ERROR; ! 515: } else if (c->c_scb.chk && ST_FILE_MARK(dsi, c->c_sense)) { ! 516: /* ! 517: * File mark detected. ! 518: */ ! 519: dsi->un_eof = 1; ! 520: switch (un->un_cmd) { ! 521: case SC_READ: ! 522: dsi->un_next_block += un->un_count - ! 523: resid / DEV_BSIZE; ! 524: dsi->un_last_block = dsi->un_next_block; ! 525: break; ! 526: case SC_SPACE_REC: ! 527: dsi->un_last_block = dsi->un_next_block += ! 528: un->un_count; /* a little high */ ! 529: break; ! 530: default: ! 531: printf("st%d: scsi tape hit eof on cmd %x\n", ! 532: un - stunits, un->un_cmd); ! 533: break; ! 534: } ! 535: bp->b_resid = resid; ! 536: } else if ((un->un_cmd == SC_WRITE || ! 537: un->un_cmd == SC_WRITE_FILE_MARK) && ! 538: c->c_scb.chk && ST_WRITE_PROT(dsi, c->c_sense)) { ! 539: /* ! 540: * Write protected tape. ! 541: */ ! 542: printf("st%d: tape is write protected \n, ", ! 543: un - stunits); ! 544: dsi->un_read_only = 1; ! 545: bp->b_flags |= B_ERROR; ! 546: } else if (c->c_scb.chk && ST_EOT(dsi, c->c_sense)) { ! 547: /* ! 548: * End of tape. ! 549: */ ! 550: bp->b_resid = bp->b_bcount; ! 551: if (un->un_cmd == SC_WRITE) { ! 552: /* ! 553: * Setting this flag makes stclose() ! 554: * write a file mark before closing. ! 555: * Until a file mark is written, the ! 556: * tape will return invalid command ! 557: * indications and not respond to ! 558: * rewinds. ! 559: */ ! 560: dsi->un_lastiow = 1; ! 561: } ! 562: } else if (c->c_scb.chk && ST_ILLEGAL(dsi, c->c_sense)) { ! 563: printf("st%d: illegal command 0x%x\n", un-stunits, un->un_cmd); ! 564: bp->b_flags |= B_ERROR; ! 565: } else if (ST_CORRECTABLE(dsi, c->c_sense)) ! 566: goto success; ! 567: else if (ST_EOD(dsi, c->c_sense)) ! 568: bp->b_flags |= B_ERROR; ! 569: else { ! 570: /* ! 571: * Some other error which we can't handle. ! 572: */ ! 573: if ((c->c_scb.chk && dsi->un_openf == OPEN)) ! 574: st_pr_sense(c, dsi); ! 575: bp->b_flags |= B_ERROR; ! 576: } ! 577: } else { ! 578: success: ! 579: switch (un->un_cmd) { ! 580: ! 581: case SC_REWIND: ! 582: case SC_ERASE_CARTRIDGE: ! 583: case SC_MODE_SELECT: ! 584: case SC_LOAD: ! 585: dsi->un_next_block = 0; ! 586: dsi->un_eof = 0; ! 587: break; ! 588: ! 589: case SC_WRITE: ! 590: dsi->un_lastiow = 1; ! 591: dsi->un_next_block += un->un_count; ! 592: break; ! 593: ! 594: case SC_READ: ! 595: dsi->un_lastior = 1; ! 596: dsi->un_next_block += un->un_count; ! 597: break; ! 598: ! 599: case SC_SPACE_FILE: ! 600: dsi->un_next_block = 0; ! 601: dsi->un_last_block = INF; ! 602: dsi->un_eof = 0; ! 603: break; ! 604: ! 605: case SC_SPACE_REC: ! 606: dsi->un_next_block += un->un_count; ! 607: break; ! 608: ! 609: case SC_REQUEST_SENSE: ! 610: dsi->un_status = ((char *)ars)[2]; ! 611: /* ! 612: if (ars->ext_sense.add_len >= AR_ES_ADD_LEN) { ! 613: dsi->un_retry_ct += ! 614: (ars->retries_msb << 8) + ! 615: ars->retries_lsb; ! 616: } ! 617: */ ! 618: break; ! 619: ! 620: case SC_TEST_UNIT_READY: ! 621: break; ! 622: ! 623: case SC_WRITE_FILE_MARK: ! 624: dsi->un_next_block = 0; ! 625: dsi->un_last_block = 0; /* i.e. no reads allowed */ ! 626: break; ! 627: ! 628: default: ! 629: printf("st%d: stintr: invalid command %x\n", ! 630: un - stunits, un->un_cmd); ! 631: break; ! 632: } ! 633: } ! 634: if (bp == &un->un_sbuf && ! 635: ((un->un_flags & SC_UNF_DVMA) == 0)) { ! 636: (*c->c_ss->scs_done)(un->un_mc); ! 637: } else { ! 638: mbdone(un->un_mc); ! 639: un->un_flags &= ~SC_UNF_DVMA; ! 640: } ! 641: if (dsi->un_bufcnt-- >= MAXSTBUF) { ! 642: wakeup((caddr_t) &dsi->un_bufcnt); ! 643: } ! 644: } ! 645: ! 646: st_pr_sense(c, dsi) ! 647: register struct scsi_ctlr *c; ! 648: register struct scsi_tape *dsi; ! 649: { ! 650: register struct scsi_unit *un; ! 651: register u_char *cp; ! 652: register int i; ! 653: ! 654: un = c->c_un; ! 655: cp = (u_char *)c->c_sense; ! 656: printf("st%d: stintr: sense ", un - stunits); ! 657: for (i=0; i < sizeof (struct st_archive_sense); i++) ! 658: printf("%x ", *cp++); ! 659: printf("\n"); ! 660: } ! 661: ! 662: sctread(dev) ! 663: register dev_t dev; ! 664: { ! 665: register struct scsi_unit *un; ! 666: register int unit, r, resid; ! 667: register struct scsi_tape *dsi; ! 668: ! 669: unit = STUNIT(dev); ! 670: if (unit > nstape) { ! 671: u.u_error = ENXIO; ! 672: return; ! 673: } ! 674: un = &stunits[unit]; ! 675: dsi = &stape[unit]; ! 676: if (u.u_count % DEV_BSIZE) { ! 677: u.u_error = ENXIO; ! 678: return; /* drive can't do it */ ! 679: } ! 680: resid = u.u_count; ! 681: dsi->un_next_block = u.u_offset / DEV_BSIZE; ! 682: dsi->un_last_block = INF; ! 683: physio(ststrategy, &un->un_rbuf, dev, B_READ, minphys); ! 684: if (dsi->un_eof && u.u_count == resid) { ! 685: dsi->un_eof = 0; /* the user is really getting it */ ! 686: } ! 687: } ! 688: ! 689: sctwrite(dev) ! 690: register dev_t dev; ! 691: { ! 692: register struct scsi_unit *un; ! 693: register int unit; ! 694: register struct scsi_tape *dsi; ! 695: ! 696: unit = STUNIT(dev); ! 697: if (unit > nstape) { ! 698: u.u_error = ENXIO; ! 699: return; ! 700: } ! 701: un = &stunits[unit]; ! 702: dsi = &stape[unit]; ! 703: dsi->un_next_block = u.u_offset / DEV_BSIZE; ! 704: dsi->un_last_block = INF; ! 705: physio(ststrategy, &un->un_rbuf, dev, B_WRITE, minphys); ! 706: } ! 707: ! 708: /*ARGSUSED*/ ! 709: sctioctl(dev, cmd, data, flag) ! 710: register dev_t dev; ! 711: register int cmd; ! 712: register caddr_t data; ! 713: int flag; ! 714: { ! 715: register int fcount; ! 716: struct mtop mtop; ! 717: struct mtget mtget; ! 718: register int unit; ! 719: register struct scsi_tape *dsi; ! 720: static int ops[] = { ! 721: SC_WRITE_FILE_MARK, /* write tape mark */ ! 722: SC_SPACE_FILE, /* forward space file */ ! 723: SC_SPACE_FILE, /* backspace file */ ! 724: SC_SPACE_REC, /* forward space record */ ! 725: SC_SPACE_REC, /* backspace record */ ! 726: SC_REWIND, /* rewind tape */ ! 727: SC_REWIND, /* unload - we just rewind */ ! 728: SC_REQUEST_SENSE, /* get status */ ! 729: SC_REWIND, /* retension - rewind + vu_57 */ ! 730: SC_ERASE_CARTRIDGE, /* erase entire tape */ ! 731: }; ! 732: ! 733: unit = STUNIT(dev); ! 734: if (unit > nstape) { ! 735: u.u_error = ENXIO; ! 736: return; ! 737: } ! 738: dsi = &stape[unit]; ! 739: switch (cmd) { ! 740: case MTIOCTOP: /* tape operation */ ! 741: if (copyin((caddr_t)data, (caddr_t)&mtop, sizeof(mtop))) { ! 742: u.u_error = EFAULT; ! 743: return; ! 744: } ! 745: switch (mtop.mt_op) { ! 746: case MTWEOF: ! 747: case MTERASE: ! 748: if (dsi->un_read_only) { ! 749: u.u_error = ENXIO; ! 750: return; ! 751: } ! 752: } ! 753: ! 754: switch (mtop.mt_op) { ! 755: case MTBSF: ! 756: case MTBSR: ! 757: fcount = -mtop.mt_count; ! 758: break; ! 759: case MTRETEN: ! 760: dsi->un_reten_rewind = 1; ! 761: /* FALL THRU */ ! 762: case MTFSF: ! 763: fcount = mtop.mt_count; ! 764: if (fcount == -1) ! 765: fcount = 0; ! 766: case MTWEOF: ! 767: case MTREW: ! 768: case MTOFFL: ! 769: case MTNOP: ! 770: case MTERASE: ! 771: fcount = mtop.mt_count; ! 772: break; ! 773: default: ! 774: u.u_error = ENXIO; ! 775: return; ! 776: } ! 777: /* ! 778: * If eof_flag then we hit eof but didn't tell the user yet. ! 779: */ ! 780: if (ops[mtop.mt_op] == SC_SPACE_FILE && dsi->un_eof) { ! 781: dsi->un_eof = 0; ! 782: if (mtop.mt_op == MTFSF) ! 783: fcount--; ! 784: } ! 785: if (stcmd(dev, ops[mtop.mt_op], fcount) == 0) ! 786: u.u_error = EIO; ! 787: return; ! 788: ! 789: case MTIOCGET: ! 790: if (stcmd(dev, SC_REQUEST_SENSE, 0) == 0) { ! 791: u.u_error = EIO; ! 792: return; ! 793: } ! 794: mtget.mt_type = MT_ISSC; ! 795: mtget.mt_erreg = dsi->un_status; ! 796: mtget.mt_fileno = dsi->un_retry_ct; ! 797: mtget.mt_blkno = dsi->un_underruns; ! 798: dsi->un_retry_ct = dsi->un_underruns = 0; ! 799: if (copyout((caddr_t)&mtget, data, sizeof(mtget))) ! 800: u.u_error = EFAULT; ! 801: return; ! 802: ! 803: default: ! 804: u.u_error = ENXIO; ! 805: return; ! 806: } ! 807: } ! 808: #endif NST > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.