|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1990 University of Utah. ! 3: * Copyright (c) 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Systems Programming Group of the University of Utah Computer ! 8: * Science Department. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by the University of ! 21: * California, Berkeley and its contributors. ! 22: * 4. Neither the name of the University nor the names of its contributors ! 23: * may be used to endorse or promote products derived from this software ! 24: * without specific prior written permission. ! 25: * ! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 36: * SUCH DAMAGE. ! 37: * ! 38: * from: Utah $Hdr: st.c 1.8 90/10/14$ ! 39: * ! 40: * @(#)st.c 7.3 (Berkeley) 5/4/91 ! 41: */ ! 42: ! 43: /* ! 44: * SCSI CCS (Command Command Set) tape driver. ! 45: * ! 46: * Specific to Exabyte: ! 47: * mt status: residual="Mbytes to LEOM" ! 48: * minor bit 4 [b1bbbb] (aka /dev/rst16) selects short filemarks ! 49: * minor bit 5 [1bbbbb] (aka /dev/rst32) selects fix block mode, 1k blocks. ! 50: * ! 51: * Archive drive: ! 52: * can read both QIC-24 and QIC-II. But only writes ! 53: * QIC-24. ! 54: * ! 55: * Supports Archive Viper QIC-150 tape drive, but scsi.c reports selection ! 56: * errors. ! 57: * ! 58: * Supports Archive Python DAT drive, but will sometimes hang machine. ! 59: * ! 60: * Supports HP 35450A DAT drive, but will sometimes hang machine. ! 61: * Partitioning of tape not supported. ! 62: * Vendor unique support has not been added. ! 63: * ! 64: * ! 65: * Supports Archive VIPER (QIC-150). ! 66: * Mostly Supports Archive PYTHON (DAT). ! 67: * Hangs if write after spin down. ! 68: * Need scsi.c that does connect/disconnect. ! 69: */ ! 70: ! 71: /* ! 72: * support for the block device not implemented ! 73: */ ! 74: ! 75: #include "st.h" ! 76: #if NST > 0 ! 77: ! 78: #include "param.h" ! 79: #include "systm.h" ! 80: #include "buf.h" ! 81: #include "scsireg.h" ! 82: #include "file.h" ! 83: #include "tty.h" ! 84: #include "proc.h" ! 85: #include "mtio.h" ! 86: #include "ioctl.h" ! 87: #include "kernel.h" ! 88: #include "tprintf.h" ! 89: ! 90: #include "device.h" ! 91: #include "stvar.h" ! 92: ! 93: #define ADD_DELAY ! 94: ! 95: extern int scsi_test_unit_rdy(); ! 96: extern int scsi_request_sense(); ! 97: extern int scsiustart(); ! 98: extern int scsigo(); ! 99: extern void scsifree(); ! 100: extern void scsireset(); ! 101: extern void scsi_delay(); ! 102: extern int scsi_tt_oddio(); ! 103: ! 104: extern int scsi_immed_command(); ! 105: ! 106: int stinit(), ststart(), stgo(), stintr(); ! 107: struct driver stdriver = { ! 108: stinit, "st", ststart, stgo, stintr, ! 109: }; ! 110: ! 111: struct st_softc { ! 112: struct hp_device *sc_hd; ! 113: struct devqueue sc_dq; ! 114: long sc_blkno; /* (possible block device support?) */ ! 115: long sc_resid; /* (possible block device support?) */ ! 116: int sc_flags; ! 117: int sc_blklen; /* 0 = variable len records */ ! 118: int sc_filepos; /* file position on tape */ ! 119: long sc_numblks; /* number of blocks on tape */ ! 120: short sc_type; /* ansi scsi type */ ! 121: short sc_punit; /* physical unit (scsi lun) */ ! 122: short sc_tapeid; /* tape drive id */ ! 123: char sc_datalen[32]; /* additional data length on some commands */ ! 124: short sc_tticntdwn; /* interrupts between TTi display updates */ ! 125: tpr_t sc_ctty; ! 126: struct buf *sc_bp; ! 127: u_char sc_cmd; ! 128: } st_softc[NST]; ! 129: ! 130: /* softc flags */ ! 131: #define STF_ALIVE 0x0001 ! 132: #define STF_OPEN 0x0002 ! 133: #define STF_WMODE 0x0004 ! 134: #define STF_WRTTN 0x0008 ! 135: #define STF_CMD 0x0010 ! 136: #define STF_LEOT 0x0020 ! 137: #define STF_MOVED 0x0040 ! 138: ! 139: struct st_mode st_mode[NST]; ! 140: ! 141: /* ! 142: * Maybe this should not be global, but gives chance to get ! 143: * tape remaining, Rewrites/ECC, etc outside the driver ! 144: */ ! 145: static struct st_xsense { ! 146: struct scsi_xsense sc_xsense; /* data from sense */ ! 147: struct exb_xsense exb_xsense; /* additional info from exabyte */ ! 148: } st_xsense[NST]; ! 149: ! 150: static struct scsi_fmt_cdb stcmd[NST]; ! 151: ! 152: static struct scsi_fmt_cdb st_read_cmd = { 6, CMD_READ }; ! 153: static struct scsi_fmt_cdb st_write_cmd = { 6, CMD_WRITE }; ! 154: ! 155: struct buf sttab[NST]; ! 156: struct buf stbuf[NST]; ! 157: ! 158: #define UNIT(x) (minor(x) & 3) ! 159: #define stpunit(x) ((x) & 7) ! 160: ! 161: #define STDEV_NOREWIND 0x04 ! 162: #define STDEV_HIDENSITY 0x08 ! 163: #define STDEV_EXSFMK 0x10 ! 164: #define STDEV_FIXEDBLK 0x20 ! 165: ! 166: #ifdef DEBUG ! 167: int st_debug = 0x0000; ! 168: #define ST_OPEN 0x0001 ! 169: #define ST_GO 0x0002 ! 170: #define ST_FMKS 0x0004 ! 171: #define ST_OPENSTAT 0x0008 ! 172: #define ST_BRESID 0x0010 ! 173: #define ST_ODDIO 0x0020 ! 174: #endif ! 175: ! 176: /* ! 177: * Patchable variable. If an even length read is requested a dma transfer is ! 178: * used. Only after the read will we find out if the read had an odd number ! 179: * of bytes. The HP98658 hardware cannot do odd length transfers, the last ! 180: * byte of the data will always be 0x00. Normally, the driver will complain ! 181: * about such transfers and return EIO. However, if st_dmaoddretry is non- ! 182: * zero, the driver will try and issue a BSR and then re-read the data using ! 183: * 'programmed transfer mode'. In most cases this works, however for unknown ! 184: * reasons it will hang the machine in certain cases. ! 185: * ! 186: * Note: ! 187: * Odd length read requests are always done using programmed transfer mode. ! 188: */ ! 189: int st_dmaoddretry = 0; ! 190: ! 191: /* ! 192: * Exabyte only: ! 193: * From adb can have access to fixed vs. variable length modes. ! 194: * Use 0x400 for 1k (best capacity) fixed length records. ! 195: * In st_open, if minor bit 4 set then 1k records are used. ! 196: * If st_exblken is set to anything other then 0 we are in fixed length mode. ! 197: * Minor bit 4 overrides any setting of st_exblklen. ! 198: * ! 199: */ ! 200: int st_exblklen = 0; ! 201: ! 202: /* exabyte here for adb access, set at open time */ ! 203: #define EX_CT 0x80 /* international cart - more space W/P6 */ ! 204: #define EX_ND 0x20 /* no disconnect */ ! 205: #define EX_NBE 0x08 /* no busy enable */ ! 206: #define EX_EBD 0x04 /* even byte disconnect */ ! 207: #define EX_PE 0x02 /* parity enable */ ! 208: #define EX_NAL 0x01 /* no auto load */ ! 209: int st_exvup = (EX_CT|EX_ND|EX_NBE); /* vendor unique parameters */ ! 210: ! 211: /* ! 212: * motion and reconnect thresholds guidelines: ! 213: * write operation; lower motion threshold for faster transfer ! 214: * raise reconnect threshold for slower transfer ! 215: * read operation; lower motion threshold for slower transfer ! 216: * raise reconnect threshold for faster transfer ! 217: */ ! 218: int st_exmotthr = 0x80; /* motion threshold, 0x80 default */ ! 219: int st_exreconthr = 0xa0; /* reconnect threshold, 0xa0 default */ ! 220: int st_exgapthr = 7; /* gap threshold, 7 default */ ! 221: #ifdef TTI ! 222: int st_extti = 0x01; /* bitmask of unit numbers, do extra */ ! 223: /* sensing so TTi display gets updated */ ! 224: #endif ! 225: ! 226: stinit(hd) ! 227: register struct hp_device *hd; ! 228: { ! 229: register struct st_softc *sc = &st_softc[hd->hp_unit]; ! 230: ! 231: sc->sc_hd = hd; ! 232: sc->sc_punit = stpunit(hd->hp_flags); ! 233: sc->sc_type = stident(sc, hd); ! 234: if (sc->sc_type < 0) ! 235: return(0); ! 236: sc->sc_dq.dq_ctlr = hd->hp_ctlr; ! 237: sc->sc_dq.dq_unit = hd->hp_unit; ! 238: sc->sc_dq.dq_slave = hd->hp_slave; ! 239: sc->sc_dq.dq_driver = &stdriver; ! 240: sc->sc_blkno = 0; ! 241: sc->sc_flags = STF_ALIVE; ! 242: return(1); ! 243: } ! 244: ! 245: stident(sc, hd) ! 246: register struct st_softc *sc; ! 247: register struct hp_device *hd; ! 248: { ! 249: int unit; ! 250: int ctlr, slave; ! 251: int i, stat, inqlen; ! 252: char idstr[32]; ! 253: #ifdef ADD_DELAY ! 254: static int havest = 0; ! 255: #endif ! 256: struct st_inquiry { ! 257: struct scsi_inquiry inqbuf; ! 258: struct exb_inquiry exb_inquiry; ! 259: } st_inqbuf; ! 260: static struct scsi_fmt_cdb st_inq = { ! 261: 6, ! 262: CMD_INQUIRY, 0, 0, 0, sizeof(st_inqbuf), 0 ! 263: }; ! 264: ! 265: ctlr = hd->hp_ctlr; ! 266: slave = hd->hp_slave; ! 267: unit = sc->sc_punit; ! 268: scsi_delay(-1); ! 269: ! 270: inqlen = 0x05; /* min */ ! 271: st_inq.cdb[4] = 0x05; ! 272: stat = scsi_immed_command(ctlr, slave, unit, &st_inq, ! 273: (u_char *)&st_inqbuf, inqlen, B_READ); ! 274: /* do twice as first command on some scsi tapes always fails */ ! 275: stat = scsi_immed_command(ctlr, slave, unit, &st_inq, ! 276: (u_char *)&st_inqbuf, inqlen, B_READ); ! 277: if (stat == -1) ! 278: goto failed; ! 279: ! 280: if (st_inqbuf.inqbuf.type != 0x01 || /* sequential access device */ ! 281: st_inqbuf.inqbuf.qual != 0x80 || /* removable media */ ! 282: (st_inqbuf.inqbuf.version != 0x01 && /* current ANSI SCSI spec */ ! 283: st_inqbuf.inqbuf.version != 0x02)) /* 0x02 is for HP DAT */ ! 284: goto failed; ! 285: ! 286: /* now get additonal info */ ! 287: inqlen = 0x05 + st_inqbuf.inqbuf.len; ! 288: st_inq.cdb[4] = inqlen; ! 289: bzero(&st_inqbuf, sizeof(st_inqbuf)); ! 290: stat = scsi_immed_command(ctlr, slave, unit, &st_inq, ! 291: (u_char *)&st_inqbuf, inqlen, B_READ); ! 292: ! 293: if (st_inqbuf.inqbuf.len >= 28) { ! 294: bcopy((caddr_t)&st_inqbuf.inqbuf.vendor_id, (caddr_t)idstr, 28); ! 295: for (i = 27; i > 23; --i) ! 296: if (idstr[i] != ' ') ! 297: break; ! 298: idstr[i+1] = 0; ! 299: for (i = 23; i > 7; --i) ! 300: if (idstr[i] != ' ') ! 301: break; ! 302: idstr[i+1] = 0; ! 303: for (i = 7; i >= 0; --i) ! 304: if (idstr[i] != ' ') ! 305: break; ! 306: idstr[i+1] = 0; ! 307: printf("st%d: %s %s rev %s\n", hd->hp_unit, idstr, &idstr[8], ! 308: &idstr[24]); ! 309: } else if (inqlen == 5) ! 310: /* great it's a stupid device, doesn't know it's know name */ ! 311: idstr[0] = idstr[8] = '\0'; ! 312: else ! 313: idstr[8] = '\0'; ! 314: ! 315: if (stat == 0xff) { ! 316: printf("st%d: Cant handle this tape drive\n", hd->hp_unit); ! 317: goto failed; ! 318: } ! 319: ! 320: if (bcmp("EXB-8200", &idstr[8], 8) == 0) { ! 321: sc->sc_tapeid = MT_ISEXABYTE; ! 322: sc->sc_datalen[CMD_REQUEST_SENSE] = 26; ! 323: sc->sc_datalen[CMD_INQUIRY] = 52; ! 324: sc->sc_datalen[CMD_MODE_SELECT] = 17; ! 325: sc->sc_datalen[CMD_MODE_SENSE] = 17; ! 326: } else if (bcmp("VIPER 150", &idstr[8], 9) == 0) { ! 327: sc->sc_tapeid = MT_ISVIPER1; ! 328: sc->sc_datalen[CMD_REQUEST_SENSE] = 14; ! 329: sc->sc_datalen[CMD_INQUIRY] = 36; ! 330: sc->sc_datalen[CMD_MODE_SELECT] = 12; ! 331: sc->sc_datalen[CMD_MODE_SENSE] = 12; ! 332: } else if (bcmp("Python 25501", &idstr[8], 12) == 0) { ! 333: sc->sc_tapeid = MT_ISPYTHON; ! 334: sc->sc_datalen[CMD_REQUEST_SENSE] = 14; ! 335: sc->sc_datalen[CMD_INQUIRY] = 36; ! 336: sc->sc_datalen[CMD_MODE_SELECT] = 12; ! 337: sc->sc_datalen[CMD_MODE_SENSE] = 12; ! 338: } else if (bcmp("HP35450A", &idstr[8], 8) == 0) { ! 339: /* XXX "extra" stat makes the HP drive happy at boot time */ ! 340: stat = scsi_test_unit_rdy(ctlr, slave, unit); ! 341: sc->sc_tapeid = MT_ISHPDAT; ! 342: sc->sc_datalen[CMD_REQUEST_SENSE] = 14; ! 343: sc->sc_datalen[CMD_INQUIRY] = 36; ! 344: sc->sc_datalen[CMD_MODE_SELECT] = 12; ! 345: sc->sc_datalen[CMD_MODE_SENSE] = 12; ! 346: } else { ! 347: if (idstr[8] == '\0') ! 348: printf("st%d: No ID, assuming Archive\n", hd->hp_unit); ! 349: else ! 350: printf("st%d: Unsupported tape device\n", hd->hp_unit); ! 351: sc->sc_tapeid = MT_ISAR; ! 352: sc->sc_datalen[CMD_REQUEST_SENSE] = 8; ! 353: sc->sc_datalen[CMD_INQUIRY] = 5; ! 354: sc->sc_datalen[CMD_MODE_SELECT] = 12; ! 355: sc->sc_datalen[CMD_MODE_SENSE] = 12; ! 356: } ! 357: ! 358: sc->sc_filepos = 0; ! 359: ! 360: /* load xsense */ ! 361: stxsense(ctlr, slave, unit, sc); ! 362: ! 363: scsi_delay(0); ! 364: #ifdef ADD_DELAY ! 365: /* XXX if we have a tape, we must up the delays in the HA driver */ ! 366: if (!havest) { ! 367: havest = 1; ! 368: scsi_delay(20000); ! 369: } ! 370: #endif ! 371: return(st_inqbuf.inqbuf.type); ! 372: failed: ! 373: scsi_delay(0); ! 374: return(-1); ! 375: } ! 376: ! 377: stopen(dev, flag, type, p) ! 378: dev_t dev; ! 379: int flag, type; ! 380: struct proc *p; ! 381: { ! 382: register struct st_softc *sc = &st_softc[UNIT(dev)]; ! 383: register struct st_xsense *xsense; ! 384: register int count; ! 385: register int stat; ! 386: int ctlr, slave, unit; ! 387: struct mode_select_data msd; ! 388: struct mode_sense mode; ! 389: int modlen; ! 390: static struct scsi_fmt_cdb modsel = { ! 391: 6, ! 392: CMD_MODE_SELECT, 0, 0, 0, sizeof(msd), 0 ! 393: }; ! 394: static struct scsi_fmt_cdb unitready = { ! 395: 6, ! 396: CMD_TEST_UNIT_READY, 0, 0, 0, 0, 0 ! 397: }; ! 398: static struct scsi_fmt_cdb modsense = { ! 399: 6, ! 400: CMD_MODE_SENSE, 0, 0, 0, sizeof(mode), 0 ! 401: }; ! 402: ! 403: ctlr = sc->sc_dq.dq_ctlr; ! 404: slave = sc->sc_dq.dq_slave; ! 405: unit = sc->sc_punit; ! 406: xsense = &st_xsense[UNIT(dev)]; ! 407: ! 408: if (UNIT(dev) > NST || (sc->sc_flags & STF_ALIVE) == 0) ! 409: return(ENXIO); ! 410: if (sc->sc_flags & STF_OPEN) ! 411: return(EBUSY); ! 412: ! 413: /* do a mode sense to get current */ ! 414: modlen = sc->sc_datalen[CMD_MODE_SENSE]; ! 415: modsense.cdb[4] = modlen; ! 416: stat = scsi_immed_command(ctlr, slave, unit, &modsense, ! 417: (u_char *)&mode, modlen, B_READ); ! 418: ! 419: /* do a mode sense to get current */ ! 420: modlen = sc->sc_datalen[CMD_MODE_SENSE]; ! 421: modsense.cdb[4] = modlen; ! 422: stat = scsi_immed_command(ctlr, slave, unit, &modsense, ! 423: (u_char *)&mode, modlen, B_READ); ! 424: ! 425: /* set record length */ ! 426: switch (sc->sc_tapeid) { ! 427: case MT_ISAR: ! 428: sc->sc_blklen = 512; ! 429: break; ! 430: case MT_ISEXABYTE: ! 431: if (minor(dev) & STDEV_FIXEDBLK) ! 432: sc->sc_blklen = 0x400; ! 433: else ! 434: sc->sc_blklen = st_exblklen; ! 435: break; ! 436: case MT_ISHPDAT: ! 437: sc->sc_blklen = 512; ! 438: break; ! 439: case MT_ISVIPER1: ! 440: sc->sc_blklen = 512; ! 441: break; ! 442: case MT_ISPYTHON: ! 443: sc->sc_blklen = 512; ! 444: break; ! 445: default: ! 446: if ((mode.md.blklen2 << 16 | ! 447: mode.md.blklen1 << 8 | ! 448: mode.md.blklen0) != 0) ! 449: sc->sc_blklen = mode.md.blklen2 << 16 | ! 450: mode.md.blklen1 << 8 | ! 451: mode.md.blklen0; ! 452: else ! 453: sc->sc_blklen = 512; ! 454: } ! 455: ! 456: /* setup for mode select */ ! 457: msd.rsvd1 = 0; ! 458: msd.rsvd2 = 0; ! 459: msd.rsvd3 = 0; ! 460: msd.buff = 1; ! 461: msd.speed = 0; ! 462: msd.blkdeslen = 0x08; ! 463: msd.density = 0; ! 464: msd.blks2 = 0; ! 465: msd.blks1 = 0; ! 466: msd.blks0 = 0; ! 467: msd.rsvd4 = 0; ! 468: msd.blklen2 = (sc->sc_blklen >> 16) & 0xff; ! 469: msd.blklen1 = (sc->sc_blklen >> 8) & 0xff; ! 470: msd.blklen0 = sc->sc_blklen & 0xff; ! 471: ! 472: switch (sc->sc_tapeid) { ! 473: case MT_ISAR: ! 474: if (minor(dev) & STDEV_HIDENSITY) ! 475: msd.density = 0x5; ! 476: else { ! 477: if (flag & FWRITE) { ! 478: uprintf("Can only write QIC-24\n"); ! 479: return(EIO); ! 480: } ! 481: msd.density = 0x4; ! 482: } ! 483: break; ! 484: case MT_ISEXABYTE: ! 485: if (minor(dev) & STDEV_HIDENSITY) ! 486: uprintf("EXB-8200 density support only\n"); ! 487: msd.vupb = (u_char)st_exvup; ! 488: msd.rsvd5 = 0; ! 489: msd.p5 = 0; ! 490: msd.motionthres = (u_char)st_exmotthr; ! 491: msd.reconthres = (u_char)st_exreconthr; ! 492: msd.gapthres = (u_char)st_exgapthr; ! 493: break; ! 494: case MT_ISHPDAT: ! 495: case MT_ISVIPER1: ! 496: case MT_ISPYTHON: ! 497: if (minor(dev) & STDEV_HIDENSITY) ! 498: uprintf("Only one density supported\n"); ! 499: break; ! 500: default: ! 501: uprintf("Unsupported drive\n"); ! 502: return(EIO); ! 503: } ! 504: ! 505: modlen = sc->sc_datalen[CMD_MODE_SELECT]; ! 506: modsel.cdb[4] = modlen; ! 507: ! 508: /* mode select */ ! 509: count = 0; ! 510: retryselect: ! 511: stat = scsi_immed_command(ctlr, slave, unit, &modsel, ! 512: (u_char *)&msd, modlen, B_WRITE); ! 513: /* ! 514: * First command after power cycle, bus reset or tape change ! 515: * will error. Try command again ! 516: */ ! 517: if (stat == STS_CHECKCOND) { ! 518: sc->sc_filepos = 0; ! 519: stxsense(ctlr, slave, unit, sc); ! 520: stat = scsi_immed_command(ctlr, slave, unit, &modsel, ! 521: (u_char *)&msd, modlen, B_WRITE); ! 522: #ifdef DEBUG ! 523: if (stat && (st_debug & ST_OPEN)) ! 524: printf("stopen: stat on mode select 0x%x second try\n", stat); ! 525: #endif ! 526: if (stat == STS_CHECKCOND) { ! 527: stxsense(ctlr, slave, unit, sc); ! 528: prtkey(UNIT(dev), sc); ! 529: } ! 530: if (stat) ! 531: return(EIO); ! 532: } ! 533: if (stat == -1 || stat == STS_BUSY) { ! 534: /* ! 535: * XXX it might just be that the bus is busy because ! 536: * another tape is doing a command. This would change ! 537: * with connect/disconnect, ie. the other drive would ! 538: * not hold onto the bus. ! 539: * ! 540: * Sleep on lbolt for up to 20 minutes (max time to FSF ! 541: * an exabyte to EOT: 16:xx minutes) ! 542: */ ! 543: if (++count > 60*20) { ! 544: uprintf("SCSI bus timeout\n"); ! 545: return(EBUSY); ! 546: } ! 547: sleep((caddr_t)&lbolt, PZERO+1); ! 548: goto retryselect; ! 549: } ! 550: ! 551: /* drive ready ? */ ! 552: stat = scsi_test_unit_rdy(ctlr, slave, unit); ! 553: ! 554: if (stat == STS_CHECKCOND) { ! 555: stxsense(ctlr, slave, unit, sc); ! 556: switch (sc->sc_tapeid) { ! 557: case MT_ISEXABYTE: ! 558: if ((xsense->sc_xsense.key & XSK_NOTRDY) && ! 559: xsense->exb_xsense.tnp) ! 560: uprintf("no cartridge\n"); ! 561: else if (xsense->sc_xsense.key & XSK_NOTRDY) ! 562: uprintf("cartridge not loaded\n"); ! 563: else if (xsense->sc_xsense.key & XSK_UNTATTEN) { ! 564: uprintf("new cart/power interrupt\n"); ! 565: stat = 0; ! 566: } else if ((xsense->sc_xsense.key & XSK_UNTATTEN) && ! 567: xsense->exb_xsense.tnp) ! 568: uprintf("cartridge unloading\n"); ! 569: else ! 570: prtkey(UNIT(dev), sc); ! 571: break; ! 572: case MT_ISAR: ! 573: if (xsense->sc_xsense.key & XSK_UNTATTEN) ! 574: stat = scsi_test_unit_rdy(ctlr, slave, unit); ! 575: if (stat == STS_CHECKCOND) { ! 576: stxsense(ctlr, slave, unit, sc); ! 577: if (xsense->sc_xsense.key) ! 578: prtkey(UNIT(dev), sc); ! 579: } else { ! 580: sc->sc_filepos = 0; /* new tape */ ! 581: stat = 0; ! 582: } ! 583: break; ! 584: case MT_ISHPDAT: ! 585: case MT_ISVIPER1: ! 586: case MT_ISPYTHON: ! 587: if (xsense->sc_xsense.key & XSK_UNTATTEN) ! 588: stat = scsi_test_unit_rdy(ctlr, slave, unit); ! 589: if (stat == STS_CHECKCOND) { ! 590: stxsense(ctlr, slave, unit, sc); ! 591: if (xsense->sc_xsense.key) ! 592: prtkey(UNIT(dev), sc); ! 593: } ! 594: break; ! 595: default: ! 596: uprintf("st%d: not ready\n", UNIT(dev)); ! 597: prtkey(UNIT(dev), sc); ! 598: break; ! 599: } ! 600: } ! 601: if (stat) ! 602: return(EIO); ! 603: ! 604: /* mode sense */ ! 605: modlen = sc->sc_datalen[CMD_MODE_SENSE]; ! 606: modsense.cdb[4] = modlen; ! 607: stat = scsi_immed_command(ctlr, slave, unit, &modsense, ! 608: (u_char *)&mode, modlen, B_READ); ! 609: #ifdef DEBUG ! 610: if (st_debug & ST_OPENSTAT) ! 611: prtmodstat(&mode); ! 612: #endif ! 613: ! 614: if (stat == STS_CHECKCOND) { ! 615: stxsense(ctlr, slave, unit, sc); ! 616: #ifdef DEBUG ! 617: if (st_debug & ST_OPEN) ! 618: dumpxsense(xsense); ! 619: #endif ! 620: } ! 621: if (stat) ! 622: return(EIO); ! 623: ! 624: if ((flag & FWRITE) && mode.md.wp) { ! 625: uprintf("st:%d write protected\n", UNIT(dev)); ! 626: return(EACCES); ! 627: } ! 628: ! 629: sc->sc_ctty = tprintf_open(p); ! 630: /* save total number of blocks on tape */ ! 631: sc->sc_numblks = mode.md.numblk2 << 16 | ! 632: mode.md.numblk1 << 8 | ! 633: mode.md.numblk0; ! 634: ! 635: if (xsense->sc_xsense.eom && !(sc->sc_flags & STF_LEOT)) ! 636: sc->sc_filepos = 0; ! 637: #ifdef DEBUG ! 638: if (st_debug & ST_FMKS) ! 639: printf("st%d: open filepos = %d\n", UNIT(dev), sc->sc_filepos); ! 640: #endif ! 641: ! 642: sc->sc_flags |= (STF_OPEN); ! 643: if (flag & FWRITE) ! 644: sc->sc_flags |= STF_WMODE; ! 645: sc->sc_flags &= ~STF_MOVED; ! 646: ! 647: #ifdef TTI ! 648: /* make stats available, also lit up TTi display */ ! 649: sc->sc_tticntdwn = 100; ! 650: #endif ! 651: stxsense(ctlr, slave, unit, sc); ! 652: ! 653: return(0); ! 654: } ! 655: ! 656: /*ARGSUSED*/ ! 657: stclose(dev, flag) ! 658: dev_t dev; ! 659: int flag; ! 660: { ! 661: register struct st_softc *sc = &st_softc[UNIT(dev)]; ! 662: register int hit = 0; ! 663: ! 664: if ((sc->sc_flags & (STF_WMODE|STF_WRTTN)) == (STF_WMODE|STF_WRTTN)) { ! 665: /* ! 666: * XXX driver only supports cartridge tapes. ! 667: * Cartridge tapes don't do double EOFs on EOT. ! 668: */ ! 669: stcommand(dev, MTWEOF, 1); ! 670: hit++; ! 671: } ! 672: if ((minor(dev) & STDEV_NOREWIND) == 0) { ! 673: stcommand(dev, MTREW, 1); ! 674: hit++; ! 675: } ! 676: #ifdef NOTDEF ! 677: /* wait until more stable before trying [XXX Needed ?] */ ! 678: if (!hit && (sc->sc_flags & SFT_WMODE)) ! 679: /* force out any any bufferd write data */ ! 680: stcommand(dev, MTFSR, 0); ! 681: #endif ! 682: /* make stats available */ ! 683: stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, sc->sc_punit, sc); ! 684: ! 685: sc->sc_flags &= ~(STF_OPEN|STF_WMODE|STF_WRTTN); ! 686: tprintf_close(sc->sc_ctty); ! 687: return(0); /* XXX */ ! 688: } ! 689: ! 690: ststrategy(bp) ! 691: register struct buf *bp; ! 692: { ! 693: struct buf *dp; ! 694: int unit, s; ! 695: ! 696: unit = UNIT(bp->b_dev); ! 697: dp = &sttab[unit]; ! 698: bp->av_forw = NULL; ! 699: s = splbio(); ! 700: if (dp->b_actf == NULL) ! 701: dp->b_actf = bp; ! 702: else ! 703: dp->b_actl->av_forw = bp; ! 704: dp->b_actl = bp; ! 705: if (dp->b_active == 0) { ! 706: dp->b_active = 1; ! 707: stustart(unit); ! 708: } ! 709: splx(s); ! 710: } ! 711: ! 712: stustart(unit) ! 713: int unit; ! 714: { ! 715: if (scsireq(&st_softc[unit].sc_dq)) ! 716: ststart(unit); ! 717: } ! 718: ! 719: ststart(unit) ! 720: int unit; ! 721: { ! 722: struct hp_device *hp = st_softc[unit].sc_hd; ! 723: ! 724: if (scsiustart(hp->hp_ctlr)) ! 725: stgo(unit); ! 726: } ! 727: ! 728: stgo(unit) ! 729: int unit; ! 730: { ! 731: register struct st_softc *sc = &st_softc[unit]; ! 732: register struct scsi_fmt_cdb *cmd; ! 733: register struct buf *bp = sttab[unit].b_actf; ! 734: struct hp_device *hp = sc->sc_hd; ! 735: int pad, stat; ! 736: long nblks; ! 737: ! 738: if (sc->sc_flags & STF_CMD) { ! 739: cmd = &stcmd[unit]; ! 740: pad = 0; ! 741: } else { ! 742: cmd = bp->b_flags & B_READ ? &st_read_cmd : &st_write_cmd; ! 743: if (sc->sc_blklen) ! 744: cmd->cdb[1] |= 0x01; /* fixed mode */ ! 745: else ! 746: cmd->cdb[1] &= 0xfe; ! 747: if (bp->b_flags & B_READ) ! 748: sc->sc_flags &= ~STF_WRTTN; ! 749: else ! 750: sc->sc_flags |= STF_WRTTN; ! 751: ! 752: if (sc->sc_blklen) { /* fixed mode */ ! 753: nblks = bp->b_bcount / sc->sc_blklen; ! 754: if (bp->b_bcount % sc->sc_blklen) { ! 755: tprintf(sc->sc_ctty, ! 756: "st%d: I/O not block aligned %d/%ld\n", ! 757: unit, sc->sc_blklen, bp->b_bcount); ! 758: cmd->cdb[1] &= 0xfe; /* force error */ ! 759: } ! 760: } else /* variable len */ ! 761: nblks = bp->b_bcount; ! 762: ! 763: *(u_char *)(&cmd->cdb[2]) = (u_char) (nblks >> 16); ! 764: *(u_char *)(&cmd->cdb[3]) = (u_char) (nblks >> 8); ! 765: *(u_char *)(&cmd->cdb[4]) = (u_char) nblks; ! 766: /* ! 767: * Always Zero. We are either writing in variable ! 768: * length mode we are writing in fixed block mode, ! 769: * or we are going to do odd length IO and are not ! 770: * going to use DMA. ! 771: */ ! 772: pad = 0; ! 773: } ! 774: ! 775: #ifdef DEBUG ! 776: if (st_debug & ST_GO) ! 777: printf("stgo: cmd len %d [0]0x%x [1]0x%x [2]0x%x [3]0x%x [4]0x%x [5]0x%x\n", ! 778: cmd->len, cmd->cdb[0], cmd->cdb[1], cmd->cdb[2], ! 779: cmd->cdb[3], cmd->cdb[4], cmd->cdb[5]); ! 780: #endif ! 781: ! 782: sc->sc_flags |= STF_MOVED; ! 783: if (bp->b_bcount & 1) { ! 784: #ifdef DEBUG ! 785: if (st_debug & ST_ODDIO) ! 786: printf("stgo%d: odd count %d using manual transfer\n", ! 787: unit, bp->b_bcount); ! 788: #endif ! 789: stat = scsi_tt_oddio(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, ! 790: bp->b_un.b_addr, bp->b_bcount, ! 791: bp->b_flags, 1); ! 792: if (stat == 0) { ! 793: bp->b_resid = 0; ! 794: stfinish(unit, sc, bp); ! 795: } ! 796: } else ! 797: stat = scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, ! 798: bp, cmd, pad); ! 799: if (stat) { ! 800: bp->b_error = EIO; ! 801: bp->b_flags |= B_ERROR; ! 802: stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, ! 803: sc->sc_punit, sc); ! 804: sterror(unit, sc, stat); ! 805: stfinish(unit, sc, bp); ! 806: } ! 807: } ! 808: ! 809: stfinish(unit, sc, bp) ! 810: int unit; ! 811: struct st_softc *sc; ! 812: struct buf *bp; ! 813: { ! 814: sttab[unit].b_errcnt = 0; ! 815: sttab[unit].b_actf = bp->b_actf; ! 816: iodone(bp); ! 817: scsifree(&sc->sc_dq); ! 818: if (sttab[unit].b_actf) ! 819: stustart(unit); ! 820: else ! 821: sttab[unit].b_active = 0; ! 822: } ! 823: ! 824: stread(dev, uio) ! 825: dev_t dev; ! 826: struct uio *uio; ! 827: { ! 828: int unit = UNIT(dev); ! 829: ! 830: return(physio(ststrategy, &stbuf[unit], dev, B_READ, minphys, uio)); ! 831: } ! 832: ! 833: stwrite(dev, uio) ! 834: dev_t dev; ! 835: struct uio *uio; ! 836: { ! 837: int unit = UNIT(dev); ! 838: ! 839: return(physio(ststrategy, &stbuf[unit], dev, B_WRITE, minphys, uio)); ! 840: } ! 841: ! 842: /*ARGSUSED*/ ! 843: stdump(dev) ! 844: dev_t dev; ! 845: { ! 846: return(ENXIO); ! 847: } ! 848: ! 849: /*ARGSUSED*/ ! 850: stioctl(dev, cmd, data, flag) ! 851: dev_t dev; ! 852: int cmd; ! 853: caddr_t data; ! 854: int flag; ! 855: { ! 856: register struct st_softc *sc = &st_softc[UNIT(dev)]; ! 857: register int cnt; ! 858: register struct mtget *mtget; ! 859: register struct st_xsense *xp = &st_xsense[UNIT(dev)]; ! 860: register struct mtop *op; ! 861: long resid; ! 862: ! 863: switch (cmd) { ! 864: ! 865: /* tape operation */ ! 866: case MTIOCTOP: ! 867: op = (struct mtop *)data; ! 868: switch (op->mt_op) { ! 869: ! 870: case MTBSR: ! 871: case MTFSR: ! 872: if (sc->sc_tapeid == MT_ISAR) ! 873: return(ENXIO); ! 874: case MTWEOF: ! 875: case MTFSF: ! 876: case MTBSF: ! 877: cnt = (int)op->mt_count; ! 878: break; ! 879: ! 880: case MTREW: ! 881: case MTOFFL: ! 882: cnt = 1; ! 883: break; ! 884: ! 885: case MTNOP: ! 886: return(0); ! 887: default: ! 888: return(EINVAL); ! 889: } ! 890: if (cnt <= 0) ! 891: return(EINVAL); ! 892: stcommand(dev, (u_int)op->mt_op, cnt); ! 893: break; ! 894: ! 895: /* drive status */ ! 896: case MTIOCGET: ! 897: mtget = (struct mtget *)data; ! 898: stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, ! 899: sc->sc_punit, sc); ! 900: mtget->mt_type = sc->sc_tapeid; ! 901: mtget->mt_dsreg = 0; ! 902: mtget->mt_erreg = ((xp->sc_xsense.valid << 15) | ! 903: (xp->sc_xsense.filemark << 14) | ! 904: (xp->sc_xsense.eom << 13) | ! 905: (xp->sc_xsense.ili << 12) | ! 906: (xp->sc_xsense.key << 8)); ! 907: ! 908: if (sc->sc_tapeid == MT_ISEXABYTE) { ! 909: mtget->mt_dsreg = sc->sc_flags; ! 910: resid = (xp->exb_xsense.tplft2 << 16 | ! 911: xp->exb_xsense.tplft1 << 8 | ! 912: xp->exb_xsense.tplft0); ! 913: mtget->mt_resid = resid / 1000; ! 914: mtget->mt_erreg |= (((xp->exb_xsense.rwerrcnt2 << 16 | ! 915: xp->exb_xsense.rwerrcnt1 << 8 | ! 916: xp->exb_xsense.rwerrcnt0) * 100) / ! 917: (sc->sc_numblks - resid)) & 0xff; ! 918: } else if (xp->sc_xsense.valid) { ! 919: resid = ((xp->sc_xsense.info1 << 24) | ! 920: (xp->sc_xsense.info2 << 16) | ! 921: (xp->sc_xsense.info3 << 8) | ! 922: (xp->sc_xsense.info4)); ! 923: if (sc->sc_blklen) /* if fixed mode */ ! 924: resid *= sc->sc_blklen; ! 925: mtget->mt_resid = resid; ! 926: } else ! 927: mtget->mt_resid = 0; ! 928: break; ! 929: ! 930: default: ! 931: return(ENXIO); ! 932: } ! 933: return(0); ! 934: } ! 935: ! 936: stintr(unit, stat) ! 937: int unit, stat; ! 938: { ! 939: register struct st_softc *sc = &st_softc[unit]; ! 940: register struct st_xsense *xp = &st_xsense[unit]; ! 941: register struct buf *bp = sttab[unit].b_actf; ! 942: struct hp_device *hp = sc->sc_hd; ! 943: ! 944: #ifdef DEBUG ! 945: if (bp == NULL) { ! 946: printf("st%d: bp == NULL\n", unit); ! 947: return; ! 948: } ! 949: #endif ! 950: switch (stat) { ! 951: /* scsi command completed ok */ ! 952: case 0: ! 953: bp->b_resid = 0; ! 954: break; ! 955: ! 956: /* more status */ ! 957: case STS_CHECKCOND: ! 958: stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, ! 959: sc->sc_punit, sc); ! 960: if (xp->sc_xsense.valid) { ! 961: bp->b_resid = (u_long)((xp->sc_xsense.info1 << 24) | ! 962: (xp->sc_xsense.info2 << 16) | ! 963: (xp->sc_xsense.info3 << 8) | ! 964: (xp->sc_xsense.info4)); ! 965: if (sc->sc_blklen) /* fixed mode */ ! 966: bp->b_resid *= sc->sc_blklen; ! 967: } ! 968: if (xp->sc_xsense.filemark) { ! 969: sc->sc_filepos++; ! 970: break; ! 971: } ! 972: if (xp->sc_xsense.key) { ! 973: sterror(unit, sc, stat); ! 974: bp->b_flags |= B_ERROR; ! 975: bp->b_error = EIO; ! 976: break; ! 977: } ! 978: if (xp->sc_xsense.ili) { ! 979: /* ! 980: * Fixed length blocks, an error. ! 981: */ ! 982: if (sc->sc_blklen) { ! 983: tprintf(sc->sc_ctty, ! 984: "st%d: Incorrect Length Indicator, blkcnt diff %d\n", ! 985: unit, sc->sc_blklen - bp->b_resid); ! 986: bp->b_flags |= B_ERROR; ! 987: bp->b_error = EIO; ! 988: break; ! 989: } ! 990: /* ! 991: * Variable length but read more than requested, ! 992: * an error. ! 993: */ ! 994: if (bp->b_resid < 0) { ! 995: bp->b_resid = 0; ! 996: bp->b_flags |= B_ERROR; ! 997: bp->b_error = ENOMEM; ! 998: break; ! 999: } ! 1000: /* ! 1001: * Variable length and odd, may require special ! 1002: * handling. ! 1003: */ ! 1004: if (bp->b_resid & 1 && sc->sc_tapeid != MT_ISAR) { ! 1005: /* ! 1006: * Normal behavior, treat as an error. ! 1007: */ ! 1008: if (!st_dmaoddretry) { ! 1009: tprintf(sc->sc_ctty, ! 1010: "st%d: Odd length read %d\n", ! 1011: UNIT(bp->b_dev), ! 1012: bp->b_bcount - bp->b_resid); ! 1013: bp->b_error = EIO; ! 1014: bp->b_flags |= B_ERROR; ! 1015: break; ! 1016: } ! 1017: /* ! 1018: * Attempt to back up and re-read using oddio. ! 1019: */ ! 1020: #ifdef DEBUG ! 1021: if (st_debug & ST_ODDIO) ! 1022: printf("st%d: stintr odd count %d, do BSR then oddio\n", ! 1023: UNIT(bp->b_dev), ! 1024: bp->b_bcount - bp->b_resid); ! 1025: #endif ! 1026: stat = scsi_tt_oddio(hp->hp_ctlr, hp->hp_slave, ! 1027: sc->sc_punit, 0, -1, 0, 0); ! 1028: if (stat == 0) ! 1029: stat = scsi_tt_oddio(hp->hp_ctlr, ! 1030: hp->hp_slave, ! 1031: sc->sc_punit, ! 1032: bp->b_un.b_addr, ! 1033: bp->b_bcount - bp->b_resid, ! 1034: bp->b_flags, 0); ! 1035: if (stat) { ! 1036: bp->b_error = EIO; ! 1037: bp->b_flags |= B_ERROR; ! 1038: stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, ! 1039: sc->sc_punit, sc); ! 1040: sterror(unit, sc, stat); ! 1041: } ! 1042: } ! 1043: break; ! 1044: } ! 1045: if (xp->sc_xsense.eom) { ! 1046: bp->b_flags |= B_ERROR; ! 1047: bp->b_error = ENOSPC; ! 1048: break; ! 1049: } ! 1050: tprintf(sc->sc_ctty, "st%d: unknown scsi error\n", unit); ! 1051: bp->b_flags |= B_ERROR; ! 1052: bp->b_error = EIO; ! 1053: break; ! 1054: ! 1055: default: ! 1056: printf("st%d: stintr unknown stat 0x%x\n", unit, stat); ! 1057: break; ! 1058: } ! 1059: #ifdef DEBUG ! 1060: if ((st_debug & ST_BRESID) && bp->b_resid != 0) ! 1061: printf("b_resid %d b_flags 0x%x b_error 0x%x\n", ! 1062: bp->b_resid, bp->b_flags, bp->b_error); ! 1063: #endif ! 1064: /* asked for more filemarks then on tape */ ! 1065: if (bp->b_resid != 0 && ! 1066: (sc->sc_flags & STF_CMD) && sc->sc_cmd == CMD_SPACE) { ! 1067: sc->sc_filepos -= bp->b_resid; ! 1068: if (sc->sc_filepos < 0) ! 1069: sc->sc_filepos = 0; ! 1070: } ! 1071: ! 1072: #ifdef TTI ! 1073: if (st_extti & (1<<unit) && ! 1074: sc->sc_type == MT_ISEXABYTE) /* to make display lit up */ ! 1075: /* ! 1076: * XXX severe performance penality for this. ! 1077: * Try and throttle by not calling stxsense on every intr. ! 1078: * Mostly for TTi we, get a stxsense call in open and close. ! 1079: */ ! 1080: if (sc->sc_tticntdwn-- == 0) { ! 1081: stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, ! 1082: sc->sc_punit, sc); ! 1083: sc->sc_tticntdwn = 100; ! 1084: } ! 1085: #endif ! 1086: ! 1087: stfinish(unit, sc, bp); ! 1088: } ! 1089: ! 1090: stcommand(dev, command, cnt) ! 1091: dev_t dev; ! 1092: u_int command; ! 1093: int cnt; ! 1094: { ! 1095: register struct st_softc *sc = &st_softc[UNIT(dev)]; ! 1096: register struct buf *bp = &stbuf[UNIT(dev)]; ! 1097: register struct scsi_fmt_cdb *cmd = &stcmd[UNIT(dev)]; ! 1098: register cmdcnt; ! 1099: int s; ! 1100: ! 1101: cmd->len = 6; /* all tape commands are cdb6 */ ! 1102: cmd->cdb[1] = sc->sc_punit; ! 1103: cmd->cdb[2] = cmd->cdb[3] = cmd->cdb[4] = cmd->cdb[5] = 0; ! 1104: cmdcnt = 0; ! 1105: ! 1106: /* ! 1107: * XXX Assumption is that everything except Archive can take ! 1108: * repeat count in cdb block. ! 1109: */ ! 1110: switch (command) { ! 1111: case MTWEOF: ! 1112: cmd->cdb[0] = CMD_WRITE_FILEMARK; ! 1113: if (sc->sc_tapeid != MT_ISAR) { ! 1114: cmdcnt = cnt; ! 1115: cnt = 1; ! 1116: } else ! 1117: cmdcnt = 1; ! 1118: *(u_char *)(&cmd->cdb[2]) = (u_char) (cmdcnt >> 16); ! 1119: *(u_char *)(&cmd->cdb[3]) = (u_char) (cmdcnt >> 8); ! 1120: *(u_char *)(&cmd->cdb[4]) = (u_char) cmdcnt; ! 1121: ! 1122: if (sc->sc_tapeid == MT_ISEXABYTE && ! 1123: (minor(dev) & STDEV_EXSFMK)) /* short filemarks */ ! 1124: cmd->cdb[5] |= 0x80; ! 1125: else ! 1126: cmd->cdb[5] &= 0x7f; ! 1127: break; ! 1128: case MTBSF: ! 1129: /* Archive can't back up, will not get to BSR case */ ! 1130: if (sc->sc_tapeid == MT_ISAR) { ! 1131: if ((sc->sc_filepos - cnt) < 0) { ! 1132: stcommand(dev, MTREW, 1); ! 1133: return; ! 1134: } ! 1135: cmdcnt = sc->sc_filepos - cnt + 1; ! 1136: stcommand(dev, MTREW, 1); ! 1137: stcommand(dev, MTFSF, cmdcnt); ! 1138: return; ! 1139: } ! 1140: case MTBSR: ! 1141: case MTFSR: ! 1142: case MTFSF: ! 1143: if (command == MTBSF || command == MTBSR) ! 1144: cnt = cnt * (-1); /* backward move */ ! 1145: if (command == MTFSF || command == MTBSF) ! 1146: cmd->cdb[1] |= 0x01; /* filemarks */ ! 1147: else ! 1148: cmd->cdb[1] |= 0x00; /* logical blocks */ ! 1149: if (sc->sc_tapeid != MT_ISAR) { ! 1150: cmdcnt = cnt; ! 1151: cnt = 1; ! 1152: } else ! 1153: cmdcnt = 1; ! 1154: *(u_char *)(&cmd->cdb[2]) = (u_char) (cmdcnt >> 16); ! 1155: *(u_char *)(&cmd->cdb[3]) = (u_char) (cmdcnt >> 8); ! 1156: *(u_char *)(&cmd->cdb[4]) = (u_char) cmdcnt; ! 1157: cmd->cdb[0] = CMD_SPACE; ! 1158: break; ! 1159: case MTREW: ! 1160: cmd->cdb[0] = CMD_REWIND; ! 1161: sc->sc_filepos = 0; ! 1162: break; ! 1163: case MTOFFL: ! 1164: cmd->cdb[0] = CMD_LOADUNLOAD; ! 1165: sc->sc_filepos = 0; ! 1166: break; ! 1167: default: ! 1168: printf("st%d: stcommand bad command 0x%x\n", ! 1169: UNIT(dev), command); ! 1170: } ! 1171: ! 1172: sc->sc_flags |= STF_CMD; ! 1173: sc->sc_cmd = cmd->cdb[0]; ! 1174: ! 1175: sc->sc_bp = bp; ! 1176: again: ! 1177: #ifdef DEBUG ! 1178: if (st_debug & ST_FMKS) ! 1179: printf("st%d: stcommand filepos %d cmdcnt %d cnt %d\n", ! 1180: UNIT(dev), sc->sc_filepos, cmdcnt, cnt); ! 1181: #endif ! 1182: s = splbio(); ! 1183: while (bp->b_flags & B_BUSY) { ! 1184: if (bp->b_flags & B_DONE) ! 1185: break; ! 1186: bp->b_flags |= B_WANTED; ! 1187: sleep((caddr_t)bp, PRIBIO); ! 1188: } ! 1189: bp->b_flags = B_BUSY|B_READ; ! 1190: splx(s); ! 1191: bp->b_dev = dev; ! 1192: bp->b_bcount = 0; ! 1193: bp->b_resid = 0; ! 1194: bp->b_blkno = 0; ! 1195: bp->b_error = 0; ! 1196: ststrategy(bp); ! 1197: iowait(bp); ! 1198: if (bp->b_flags & B_WANTED) ! 1199: wakeup((caddr_t)bp); ! 1200: bp->b_flags &= B_ERROR; ! 1201: ! 1202: if (command == MTWEOF || command == MTFSF || command == MTBSF) ! 1203: sc->sc_filepos += cmdcnt; ! 1204: ! 1205: if (--cnt > 0) ! 1206: goto again; ! 1207: ! 1208: sc->sc_flags |= STF_MOVED; ! 1209: sc->sc_flags &= ~(STF_CMD|STF_WRTTN); ! 1210: } ! 1211: ! 1212: sterror(unit, sc, stat) ! 1213: int unit, stat; ! 1214: struct st_softc *sc; ! 1215: { ! 1216: /* stxsense must have been called before sterror() */ ! 1217: if (stat & STS_CHECKCOND) ! 1218: prtkey(unit, sc); ! 1219: else if (stat) ! 1220: tprintf(sc->sc_ctty, ! 1221: "st%d: bad scsi status 0x%x\n", unit, stat); ! 1222: ! 1223: if ((sc->sc_flags & STF_CMD) && sc->sc_cmd == CMD_SPACE) /* fsf */ ! 1224: sc->sc_filepos--; ! 1225: } ! 1226: ! 1227: stxsense(ctlr, slave, unit, sc) ! 1228: int ctlr, slave, unit; ! 1229: struct st_softc *sc; ! 1230: { ! 1231: u_char *sensebuf; ! 1232: unsigned len; ! 1233: ! 1234: sensebuf = (u_char *)&st_xsense[sc->sc_dq.dq_unit]; ! 1235: len = sc->sc_datalen[CMD_REQUEST_SENSE]; ! 1236: scsi_request_sense(ctlr, slave, unit, sensebuf, len); ! 1237: } ! 1238: ! 1239: prtkey(unit, sc) ! 1240: int unit; ! 1241: struct st_softc *sc; ! 1242: { ! 1243: register struct st_xsense *xp = &st_xsense[unit]; ! 1244: ! 1245: switch (xp->sc_xsense.key) { ! 1246: case XSK_NOSENCE: ! 1247: break; ! 1248: case XSK_NOTUSED1: ! 1249: case XSK_NOTUSEDC: ! 1250: case XSK_NOTUSEDE: ! 1251: break; ! 1252: case XSK_REVERVED: ! 1253: tprintf(sc->sc_ctty, "st%d: Reserved sense key 0x%x\n", ! 1254: unit, xp->sc_xsense.key); ! 1255: break; ! 1256: case XSK_NOTRDY: ! 1257: tprintf(sc->sc_ctty, "st%d: NOT READY\n", unit); ! 1258: break; ! 1259: case XSK_MEDERR: ! 1260: tprintf(sc->sc_ctty, "st%d: MEDIUM ERROR\n", unit); ! 1261: break; ! 1262: case XSK_HRDWERR: ! 1263: tprintf(sc->sc_ctty, "st%d: HARDWARE ERROR\n", unit); ! 1264: break; ! 1265: case XSK_ILLREQ: ! 1266: tprintf(sc->sc_ctty, "st%d: ILLEGAL REQUEST\n", unit); ! 1267: break; ! 1268: case XSK_UNTATTEN: ! 1269: tprintf(sc->sc_ctty, "st%d: UNIT ATTENTION\n", unit); ! 1270: break; ! 1271: case XSK_DATAPROT: ! 1272: tprintf(sc->sc_ctty, "st%d: DATA PROTECT\n", unit); ! 1273: break; ! 1274: case XSK_BLNKCHK: ! 1275: tprintf(sc->sc_ctty, "st%d: BLANK CHECK\n", unit); ! 1276: break; ! 1277: case XSK_VENDOR: ! 1278: tprintf(sc->sc_ctty, "st%d: VENDER UNIQUE SENSE KEY ", unit); ! 1279: switch (sc->sc_tapeid) { ! 1280: case MT_ISEXABYTE: ! 1281: tprintf(sc->sc_ctty, "Exabyte: "); ! 1282: if (xp->exb_xsense.xfr) ! 1283: tprintf(sc->sc_ctty, ! 1284: "Transfer Abort Error\n"); ! 1285: if (xp->exb_xsense.tmd) ! 1286: tprintf(sc->sc_ctty, ! 1287: "Tape Mark Detect Error\n"); ! 1288: break; ! 1289: default: ! 1290: tprintf(sc->sc_ctty, "\n"); ! 1291: } ! 1292: break; ! 1293: case XSK_CPYABORT: ! 1294: tprintf(sc->sc_ctty, "st%d: COPY ABORTED\n", unit); ! 1295: break; ! 1296: case XSK_ABORTCMD: ! 1297: tprintf(sc->sc_ctty, "st%d: ABORTED COMMAND\n", unit); ! 1298: break; ! 1299: case XSK_VOLOVER: ! 1300: tprintf(sc->sc_ctty, "st%d: VOLUME OVERFLOW\n", unit); ! 1301: break; ! 1302: default: ! 1303: tprintf(sc->sc_ctty, "st%d: unknown sense key 0x%x\n", ! 1304: unit, xp->sc_xsense.key); ! 1305: } ! 1306: if (sc->sc_tapeid == MT_ISEXABYTE) { ! 1307: if (xp->exb_xsense.bpe) ! 1308: tprintf(sc->sc_ctty, "st%d: Bus Parity Errorn", unit); ! 1309: if (xp->exb_xsense.fpe) ! 1310: tprintf(sc->sc_ctty, ! 1311: "st%d: Formatted Buffer Parity Errorn", unit); ! 1312: if (xp->exb_xsense.eco) ! 1313: tprintf(sc->sc_ctty, "st%d: Error Counter Overflown", ! 1314: unit); ! 1315: if (xp->exb_xsense.tme) ! 1316: tprintf(sc->sc_ctty, "st%d: Tape Motion Errorn", unit); ! 1317: if (xp->exb_xsense.xfr) ! 1318: tprintf(sc->sc_ctty, "st%d: Transfer About Errorn", ! 1319: unit); ! 1320: if (xp->exb_xsense.tmd) ! 1321: tprintf(sc->sc_ctty, "st%d: Tape Mark Detect Errorn", ! 1322: unit); ! 1323: if (xp->exb_xsense.fmke) ! 1324: tprintf(sc->sc_ctty, "st%d: Filemark Errorn", unit); ! 1325: if (xp->exb_xsense.ure) ! 1326: tprintf(sc->sc_ctty, "st%d: Under Run Errorn", unit); ! 1327: if (xp->exb_xsense.sse) ! 1328: tprintf(sc->sc_ctty, "st%d: Servo System Errorn", ! 1329: unit); ! 1330: if (xp->exb_xsense.fe) ! 1331: tprintf(sc->sc_ctty, "st%d: Formatter Errorn", unit); ! 1332: if (xp->exb_xsense.wseb) ! 1333: tprintf(sc->sc_ctty, "st%d: WSEB Errorn", unit); ! 1334: if (xp->exb_xsense.wseo) ! 1335: tprintf(sc->sc_ctty, "st%d: WSEO Errorn", unit); ! 1336: } ! 1337: } ! 1338: ! 1339: #ifdef DEBUG ! 1340: ! 1341: dumpxsense(sensebuf) ! 1342: struct st_xsense *sensebuf; ! 1343: { ! 1344: struct st_xsense *xp = sensebuf; ! 1345: ! 1346: printf("valid 0x%x errorclass 0x%x errorcode 0x%x\n", ! 1347: xp->sc_xsense.valid, ! 1348: xp->sc_xsense.class, xp->sc_xsense.code); ! 1349: printf("seg number 0x%x\n", xp->sc_xsense.segment); ! 1350: printf("FMK 0x%x EOM 0x%x ILI 0x%x RSVD 0x%x sensekey 0x%x\n", ! 1351: xp->sc_xsense.filemark, xp->sc_xsense.eom, xp->sc_xsense.ili, ! 1352: xp->sc_xsense.rsvd, xp->sc_xsense.key); ! 1353: printf("info 0x%lx\n", ! 1354: (u_long)((xp->sc_xsense.info1<<24)|(xp->sc_xsense.info2<<16)| ! 1355: (xp->sc_xsense.info3<<8)|(xp->sc_xsense.info4)) ); ! 1356: printf("ASenseL 0x%x\n", xp->sc_xsense.len); ! 1357: ! 1358: if (xp->sc_xsense.len != 0x12) /* MT_ISEXB Exabyte only ?? */ ! 1359: return; /* What about others */ ! 1360: ! 1361: printf("ASenseC 0x%x\n", xp->exb_xsense.addsens); ! 1362: printf("AsenseQ 0x%x\n", xp->exb_xsense.addsensq); ! 1363: printf("R/W Errors 0x%lx\n", ! 1364: (u_long)((xp->exb_xsense.rwerrcnt2<<16)| ! 1365: (xp->exb_xsense.rwerrcnt1<<8)| ! 1366: (xp->exb_xsense.rwerrcnt1)) ); ! 1367: printf("PF 0x%x BPE 0x%x FPE 0x%x ME 0x%x ECO 0x%x TME 0x%x TNP 0x%x BOT 0x%x\n", ! 1368: xp->exb_xsense.pf, xp->exb_xsense.bpe, xp->exb_xsense.fpe, ! 1369: xp->exb_xsense.me, xp->exb_xsense.eco, xp->exb_xsense.tme, ! 1370: xp->exb_xsense.tnp, xp->exb_xsense.bot); ! 1371: printf("XFR 0x%x TMD 0x%x WP 0x%x FMKE 0x%x URE 0x%x WE1 0x%x SSE 0x%x FE 0x%x\n", ! 1372: xp->exb_xsense.xfr, xp->exb_xsense.tmd, xp->exb_xsense.wp, ! 1373: xp->exb_xsense.fmke, xp->exb_xsense.ure, xp->exb_xsense.we1, ! 1374: xp->exb_xsense.sse, xp->exb_xsense.fe); ! 1375: printf("WSEB 0x%x WSEO 0x%x\n", ! 1376: xp->exb_xsense.wseb, xp->exb_xsense.wseo); ! 1377: printf("Remaining Tape 0x%lx\n", ! 1378: (u_long)((xp->exb_xsense.tplft2<<16)| ! 1379: (xp->exb_xsense.tplft1<<8)| ! 1380: (xp->exb_xsense.tplft0)) ); ! 1381: } ! 1382: ! 1383: prtmodsel(msd, modlen) ! 1384: struct mode_select_data *msd; ! 1385: int modlen; ! 1386: { ! 1387: printf("Modsel command. len is 0x%x.\n", modlen); ! 1388: printf("rsvd1 0x%x rsvd2 0x%x rsvd3 0x%x bufferd 0x%x speed 0x%x bckdeslen 0x%x\n", ! 1389: msd->rsvd1,msd->rsvd2,msd->rsvd3,msd->buff,msd->speed,msd->blkdeslen); ! 1390: printf("density 0x%x blks2 0x%x blks1 0x%x blks0 0x%x rsvd 0x%x blklen2 0x%x blklen1 0x%x blklen0 0x%x\n", ! 1391: msd->density,msd->blks2,msd->blks1,msd->blks0,msd->rsvd4,msd->blklen2,msd->blklen1,msd->blklen0); ! 1392: printf("vupb 0x%x rsvd 0x%x p5 0x%x motionthres 0x%x reconthres 0x%x gapthres 0x%x \n", ! 1393: msd->vupb,msd->rsvd5,msd->p5,msd->motionthres,msd->reconthres,msd->gapthres); ! 1394: } ! 1395: ! 1396: prtmodstat(mode) ! 1397: struct mode_sense *mode; ! 1398: { ! 1399: printf("Mode Status\n"); ! 1400: printf("sdl 0x%x medtype 0x%x wp 0x%x bfmd 0x%x speed 0x%x bdl 0x%x\n", ! 1401: mode->md.sdl, mode->md.medtype, mode->md.wp, mode->md.bfmd, ! 1402: mode->md.speed, mode->md.bdl); ! 1403: printf("dencod 0x%x numblk 0x%x blklen 0x%x\n", ! 1404: mode->md.dencod, ! 1405: (mode->md.numblk2<<16)|(mode->md.numblk1<<8)|(mode->md.numblk0), ! 1406: (mode->md.blklen2<<16)|(mode->md.blklen1<<8)|(mode->md.blklen0) ); ! 1407: printf("ct 0x%x nd 0x%x nbe 0x%x edb 0x%x pe 0x%x nal 0x%x p5 0x%x\n", ! 1408: mode->ex.ct, mode->ex.nd, mode->ex.nbe, ! 1409: mode->ex.ebd, mode->ex.pe, mode->ex.nal, mode->ex.p5); ! 1410: printf("motionthres 0x%x reconthres 0x%x gapthres 0x%x\n", ! 1411: mode->ex.motionthres, mode->ex.reconthres, mode->ex.gapthres); ! 1412: } ! 1413: #endif /* DEBUG */ ! 1414: ! 1415: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.