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