|
|
1.1 ! root 1: /* ! 2: * @(#)st.c 1.1 86/02/03 Copyright (c) 1985 by Sun Microsystems, Inc. ! 3: */ ! 4: ! 5: #include <sys/types.h> ! 6: #include <sys/inode.h> ! 7: #include <sun/dklabel.h> ! 8: #include <sun/dkio.h> ! 9: #include <sys/buf.h> ! 10: #include <sundev/screg.h> ! 11: #include <sundev/sireg.h> ! 12: #include <sundev/scsi.h> ! 13: #include <sundev/streg.h> ! 14: #include <machine/idprom.h> ! 15: #include "saio.h" ! 16: #include "param.h" ! 17: ! 18: /* ! 19: * Driver for Sysgen SC4000 and EMULEX MT-02 SCSI tape controllers. ! 20: * Supports qic11 format only. ! 21: */ ! 22: extern int scdoit(); ! 23: #ifdef SUN3 ! 24: extern int sidoit(); ! 25: #endif ! 26: ! 27: #define min(a,b) ((a)<(b)? (a): (b)) ! 28: ! 29: #define NSD 1 ! 30: unsigned long staddrs[NSD] = { 0x0, }; ! 31: ! 32: extern int xxprobe(), xxboot(); ! 33: int stopen(), stclose(), ststrategy(); ! 34: ! 35: ! 36: struct stparam { ! 37: int st_target; ! 38: int st_unit; ! 39: int st_eof; ! 40: int st_lastcmd; ! 41: int st_ctype; ! 42: #ifdef SUN3 ! 43: int st_ha_type; ! 44: #endif ! 45: struct saioreq subsip[1]; /* sip for host adapter */ ! 46: }; ! 47: ! 48: /* ! 49: * DMA-able buffers ! 50: */ ! 51: #ifdef SUN2 ! 52: /* virtual addresses are precious on Sun-2 */ ! 53: #define MAXSTBSIZE (20*1024) ! 54: #endif ! 55: #ifdef SUN3 ! 56: #define MAXSTBSIZE (127*512) ! 57: #endif ! 58: struct stdma { ! 59: char sbuffer[SENSE_LENGTH]; ! 60: char databuffer[MAXSTBSIZE]; ! 61: }; ! 62: ! 63: #define STSBUF (((struct stdma *)sip->si_dmaaddr)->sbuffer) ! 64: #define STBUF (((struct stdma *)sip->si_dmaaddr)->databuffer) ! 65: ! 66: #define ISAEMULEX(stp) (stp->st_ctype == ST_TYPE_EMULEX ? 1 : 0) ! 67: ! 68: /* ! 69: * What resources we need to run ! 70: */ ! 71: struct devinfo stinfo = { ! 72: 0, /* No device to map in */ ! 73: sizeof (struct stdma), ! 74: sizeof (struct stparam), ! 75: NSD, /* Dummy devices */ ! 76: staddrs, /* Dummy devices */ ! 77: MAP_MAINMEM, ! 78: MAXSTBSIZE, /* transfer size */ ! 79: }; ! 80: ! 81: struct boottab stdriver = { ! 82: "st", xxprobe, xxboot, ! 83: stopen, stclose, ststrategy, ! 84: "st: SCSI tape", &stinfo ! 85: }; ! 86: ! 87: #define TAPE_TARGET 4 /* default SCSI target # for tape */ ! 88: ! 89: #define SENSE_BITS \ ! 90: "\020\17NoCart\16NoDrive\15WriteProt\14EndMedium\13HardErr\12WrongBlock\ ! 91: \11FileMark\7InvCmd\6NoData\5Flaking\4BOT\0034\0022\1GotReset" ! 92: ! 93: #define SENSELOC 4 /* sysgen returns sense at this offset */ ! 94: ! 95: #define ROUNDUP(x) ((x + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1)) ! 96: ! 97: #ifdef SUN3 ! 98: /* ! 99: * Determine type of host adaptor interface, si or sc. ! 100: * Returns 1 if si host adaptor and 0 if sc host adaptor. ! 101: */ ! 102: st_probe(sip) ! 103: struct saioreq *sip; ! 104: { ! 105: if (siprobe(sip)) { ! 106: return (1); ! 107: } else { ! 108: return (0); ! 109: } ! 110: } ! 111: #endif ! 112: ! 113: /* ! 114: * Open the SCSI Tape controller ! 115: */ ! 116: int ! 117: stopen(sip) ! 118: register struct saioreq *sip; ! 119: { ! 120: register struct stparam *stp; ! 121: register int r; ! 122: register int skip; ! 123: register int i; ! 124: struct scsi_cdb cdb; ! 125: struct scsi_scb scb; ! 126: ! 127: stp = (struct stparam *) sip->si_devdata; ! 128: bzero( (char *)stp, (sizeof (struct stparam))); ! 129: ! 130: *stp->subsip = *sip; /* initialize subsip */ ! 131: ! 132: #ifdef SUN3 ! 133: { ! 134: extern struct boottab scdriver; ! 135: extern struct boottab sidriver; ! 136: ! 137: /* FIXME, find out which scsi interface to use */ ! 138: if (st_probe(sip)) { ! 139: stp->st_ha_type = 1; ! 140: ! 141: /* FIXME, must vector thru table */ ! 142: stp->subsip->si_boottab = &sidriver; ! 143: } else { ! 144: stp->st_ha_type = 0; ! 145: ! 146: /* FIXME, must vector thru table */ ! 147: stp->subsip->si_boottab = &scdriver; ! 148: } ! 149: } ! 150: #endif ! 151: #ifdef SUN2 ! 152: { ! 153: extern struct boottab scdriver; ! 154: ! 155: stp->subsip->si_boottab = &scdriver; ! 156: } ! 157: #endif ! 158: ! 159: stp->subsip->si_unit = sip->si_unit >> 3; /* Target number */ ! 160: if (stp->subsip->si_unit == 0) { ! 161: stp->subsip->si_unit = TAPE_TARGET; ! 162: } ! 163: ! 164: r = devopen(stp->subsip); ! 165: if (r < 0) return r; ! 166: ! 167: /* Logical unit number */ ! 168: stp->st_unit = sip->si_unit & 0x07; ! 169: ! 170: /* ! 171: * Must wait for tape controller to become ready. ! 172: * This takes about 10 seconds for the Emulex. ! 173: */ ! 174: /* ! 175: * Test for the controller being ready. First test will fail if ! 176: * the SCSI bus is permanently busy or if a previous op was ! 177: * interrupted in mid-transfer. Second one should work. ! 178: */ ! 179: for (i = 0; i < 2; i++) { ! 180: bzero((char *) &cdb, sizeof cdb); ! 181: cdb.cmd = SC_TEST_UNIT_READY; ! 182: cdb.count = 0; ! 183: stp->subsip->si_cc = 0; ! 184: stp->subsip->si_ma = 0; ! 185: #ifdef SUN3 ! 186: if (stp->st_ha_type) ! 187: r = sidoit(&cdb, &scb, stp->subsip); ! 188: else ! 189: #endif ! 190: r = scdoit(&cdb, &scb, stp->subsip); ! 191: } ! 192: ! 193: /* ! 194: * To figure out what type of tape controller is out there we send ! 195: * a REQUEST_SENSE command and see how much sense data comes back. ! 196: */ ! 197: stp->st_ctype = ST_TYPE_EMULEX; ! 198: cdb.cmd = SC_REQUEST_SENSE; ! 199: stp->subsip->si_cc = cdb.count = ST_EMULEX_SENSE_LEN; ! 200: stp->subsip->si_ma = STSBUF; ! 201: #ifdef SUN3 ! 202: if (stp->st_ha_type) ! 203: r = sidoit(&cdb, &scb, stp->subsip); ! 204: else ! 205: #endif ! 206: r = scdoit(&cdb, &scb, stp->subsip); ! 207: if (r != ST_EMULEX_SENSE_LEN) { ! 208: stp->st_ctype = ST_TYPE_SYSGEN; ! 209: cdb.cmd = SC_REQUEST_SENSE; ! 210: stp->subsip->si_cc = cdb.count = ST_SYSGEN_SENSE_LEN; ! 211: stp->subsip->si_ma = STSBUF; ! 212: #ifdef SUN3 ! 213: if (stp->st_ha_type) ! 214: r = sidoit(&cdb, &scb, stp->subsip); ! 215: else ! 216: #endif ! 217: r = scdoit(&cdb, &scb, stp->subsip); ! 218: if (r == -1) { ! 219: printf("stopen: cannot get sense, %d\n", r); ! 220: return (-1); ! 221: } ! 222: } ! 223: ! 224: /* ! 225: * Default format mode for emulex is qic24. ! 226: * Needs to be qic11. ! 227: */ ! 228: if (ISAEMULEX(stp)) { ! 229: sip->si_cc = EM_MS_PL_LEN; ! 230: if (stcmd(SC_QIC11, sip, 1) == 0) { ! 231: printf("stopen: mode select command fail"); ! 232: return (-1); ! 233: } ! 234: } ! 235: ! 236: /* ! 237: * Rewind a few times until it works. First one will fail if ! 238: * the SCSI bus is permanently busy if a previous op was interrupted ! 239: * in mid-transfer. Second one will fail with POR status, after ! 240: * the scsi bus is reset from the busy. Third one should work. ! 241: */ ! 242: sip->si_cc = 0; ! 243: if (stcmd(SC_REWIND, sip, 0) == 0 && ! 244: stcmd(SC_REWIND, sip, 0) == 0 && ! 245: stcmd(SC_REWIND, sip, 1) == 0) { ! 246: return (-1); ! 247: } ! 248: skip = sip->si_boff; ! 249: while (skip--) { ! 250: sip->si_cc = 0; ! 251: if (stcmd(SC_SPACE_FILE, sip, 1) == 0) { ! 252: return (-1); ! 253: } ! 254: } ! 255: stp->st_eof = 0; ! 256: stp->st_lastcmd = 0; ! 257: return (0); ! 258: } ! 259: ! 260: /* ! 261: * Close the tape drive. ! 262: */ ! 263: stclose(sip) ! 264: register struct saioreq *sip; ! 265: { ! 266: register struct stparam *stp; ! 267: ! 268: stp = (struct stparam *) sip->si_devdata; ! 269: if (stp->st_lastcmd == SC_WRITE) { ! 270: (void) stcmd(SC_WRITE_FILE_MARK, sip, 0); ! 271: } ! 272: (void) stcmd(SC_REWIND, sip, 0); ! 273: } ! 274: ! 275: ! 276: /* ! 277: * Perform a read or write of the SCSI tape. ! 278: */ ! 279: int ! 280: ststrategy(sip, rw) ! 281: register struct saioreq *sip; ! 282: int rw; ! 283: { ! 284: register struct stparam *stp; ! 285: ! 286: stp = (struct stparam *) sip->si_devdata; ! 287: if (stp->st_eof) { ! 288: stp->st_eof = 0; ! 289: return (0); ! 290: } ! 291: return (stcmd(rw == WRITE ? SC_WRITE : SC_READ, sip, 1)); ! 292: } ! 293: ! 294: /* ! 295: * Execute a scsi tape command ! 296: */ ! 297: int ! 298: stcmd(cmd, sip, errprint) ! 299: int cmd; ! 300: register struct saioreq *sip; ! 301: int errprint; ! 302: { ! 303: register struct st_emulex_mspl *mode; ! 304: register int r, i, c; ! 305: register char *buf; ! 306: register struct stparam *stp; ! 307: struct scsi_cdb cdb, scdb; ! 308: struct scsi_scb scb, sscb; ! 309: int count; ! 310: int qic; ! 311: int sense_length; ! 312: char *cp; ! 313: struct st_emulex_sense *ems; ! 314: struct st_sysgen_sense *scs; ! 315: ! 316: count = sip->si_cc; ! 317: stp = (struct stparam *)sip->si_devdata; ! 318: buf = sip->si_ma; ! 319: ! 320: if (cmd == SC_WRITE && buf != STBUF) { ! 321: bcopy(buf, STBUF, (unsigned)count); ! 322: } ! 323: ! 324: /* set up cdb */ ! 325: bzero((char *) &cdb, sizeof cdb); ! 326: cdb.cmd = cmd; ! 327: cdb.lun = stp->st_unit; ! 328: c = ROUNDUP(count) / DEV_BSIZE; ! 329: cdb.high_count = c >> 16; ! 330: cdb.mid_count = (c >> 8) & 0xFF; ! 331: cdb.low_count = c & 0xFF; ! 332: stp->subsip->si_ma = STBUF; ! 333: stp->subsip->si_cc = ROUNDUP(count); ! 334: ! 335: /* some fields in the cdb are command specific */ ! 336: switch (cmd) { ! 337: ! 338: case SC_QIC11: ! 339: stp->subsip->si_ma = 0; ! 340: stp->subsip->si_cc = 0; ! 341: if (ISAEMULEX(stp)) { ! 342: qic = ST_EMULEX_QIC11; ! 343: cdb.cmd = SC_MODE_SELECT; ! 344: goto MODE; ! 345: } else { ! 346: cdb.cmd = SC_QIC02; ! 347: cdb.high_count = ST_SYSGEN_QIC11; ! 348: break; ! 349: } ! 350: /* NOTREACHED */ ! 351: ! 352: case SC_QIC24: ! 353: stp->subsip->si_ma = 0; ! 354: stp->subsip->si_cc = 0; ! 355: if (ISAEMULEX(stp)) { ! 356: qic = ST_EMULEX_QIC24; ! 357: cdb.cmd = SC_MODE_SELECT; ! 358: goto MODE; ! 359: } else { ! 360: cdb.cmd = SC_QIC02; ! 361: cdb.high_count = ST_SYSGEN_QIC24; ! 362: break; ! 363: } ! 364: /* NOTREACHED */ ! 365: MODE: ! 366: case SC_MODE_SELECT: ! 367: mode = (struct st_emulex_mspl *)STSBUF; ! 368: bzero(mode, sizeof(*mode)); ! 369: mode->hdr.bufm = 1; ! 370: mode->bd.density = qic; ! 371: mode->hdr.bd_len = EM_MS_BD_LEN; ! 372: stp->subsip->si_ma = (char *)mode; ! 373: stp->subsip->si_cc = cdb.count = EM_MS_PL_LEN; ! 374: break; ! 375: ! 376: case SC_SPACE_FILE: ! 377: cdb.cmd = SC_SPACE; /* the real SCSI cmd */ ! 378: cdb.t_code = 1; /* space file, not rec */ ! 379: cdb.low_count = 1; /* space 1 file, not 0 */ ! 380: stp->subsip->si_ma = 0; ! 381: stp->subsip->si_cc = 0; ! 382: break; ! 383: ! 384: case SC_WRITE_FILE_MARK: ! 385: cdb.count = 1; ! 386: /* fall through... */ ! 387: ! 388: case SC_TEST_UNIT_READY: ! 389: case SC_REWIND: ! 390: case SC_LOAD: ! 391: stp->subsip->si_ma = 0; ! 392: stp->subsip->si_cc = 0; ! 393: break; ! 394: ! 395: case SC_READ: ! 396: case SC_WRITE: ! 397: if (ISAEMULEX(stp)) { ! 398: cdb.t_code = 1; ! 399: } ! 400: break; ! 401: ! 402: default: ! 403: if (errprint) ! 404: printf("st: unknown command\n"); ! 405: return (0); ! 406: } ! 407: ! 408: /* execute the command */ ! 409: #ifdef SUN3 ! 410: if (stp->st_ha_type) ! 411: r = sidoit(&cdb, &scb, stp->subsip); ! 412: else ! 413: #endif ! 414: r = scdoit(&cdb, &scb, stp->subsip); ! 415: ! 416: /* allow for tape blocking */ ! 417: if (r > count) ! 418: r = count; ! 419: /* error */ ! 420: if (r == -1) ! 421: return (0); ! 422: ! 423: if (cmd == SC_READ) { ! 424: if (min(count, r)) ! 425: bcopy(STBUF, buf, (unsigned)(min(count, r))); ! 426: } ! 427: ! 428: /* we may need to get sense data */ ! 429: if (scb.chk) { ! 430: bzero((char *) &scdb, sizeof scdb); ! 431: scdb.cmd = SC_REQUEST_SENSE; ! 432: scdb.lun = stp->st_unit; ! 433: if (ISAEMULEX(stp)) { ! 434: sense_length = stp->subsip->si_cc = ! 435: scdb.count = ST_EMULEX_SENSE_LEN; ! 436: } else { ! 437: sense_length = stp->subsip->si_cc = ! 438: scdb.count = ST_SYSGEN_SENSE_LEN; ! 439: } ! 440: stp->subsip->si_ma = STSBUF; ! 441: #ifdef SUN3 ! 442: if (stp->st_ha_type) ! 443: i = sidoit(&scdb, &sscb, stp->subsip ); ! 444: else ! 445: #endif ! 446: i = scdoit(&scdb, &sscb, stp->subsip ); ! 447: if (i != sense_length) { ! 448: if (errprint) { ! 449: printf("st: sense error\n"); ! 450: } ! 451: stp->st_eof = 1; ! 452: return (0); ! 453: } ! 454: if (ISAEMULEX(stp)) { ! 455: ems = (struct st_emulex_sense *)STSBUF; ! 456: if ((ems->ext_sense.fil_mk == 0) && errprint) { ! 457: printf("st: error:\n"); ! 458: printf("\tsense key is %x", ! 459: ems->ext_sense.key); ! 460: printf("\terror is %x\n", ! 461: ems->error); ! 462: } ! 463: stp->st_eof = 1; ! 464: return (r); ! 465: } else { ! 466: scs = (struct st_sysgen_sense *)STSBUF; ! 467: if ((scs->qic_sense.file_mark == 0) && errprint) { ! 468: #ifdef STBOOT ! 469: printf("st: error %x\n", ! 470: *(unsigned short *)&STSBUF[SENSELOC]); ! 471: #else STBOOT ! 472: printf("st: error %b\n", ! 473: *(unsigned short *)&STSBUF[SENSELOC], ! 474: SENSE_BITS); ! 475: #endif STBOOT ! 476: } ! 477: stp->st_eof = 1; ! 478: return (r); ! 479: } ! 480: } ! 481: if (r >= count) { ! 482: return (count ? count : 1); ! 483: } else { ! 484: if (errprint) { ! 485: printf("st: short transfer\n"); ! 486: } ! 487: return (r); ! 488: } ! 489: } ! 490:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.