|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: rz_tape.c ! 28: * Author: Alessandro Forin, Carnegie Mellon University ! 29: * Date: 10/90 ! 30: * ! 31: * Top layer of the SCSI driver: interface with the MI. ! 32: * This file contains operations specific to TAPE-like devices. ! 33: */ ! 34: ! 35: #include <mach/std_types.h> ! 36: #include <scsi/compat_30.h> ! 37: ! 38: #include <sys/ioctl.h> ! 39: #ifdef MACH_KERNEL ! 40: #include <device/tape_status.h> ! 41: #else /*MACH_KERNEL*/ ! 42: #include <mips/PMAX/tape_status.h> ! 43: #endif /*MACH_KERNEL*/ ! 44: ! 45: #include <scsi/scsi.h> ! 46: #include <scsi/scsi_defs.h> ! 47: #include <scsi/rz.h> ! 48: ! 49: #if (NSCSI > 0) ! 50: ! 51: ! 52: void sctape_start(); /* forward */ ! 53: ! 54: int scsi_tape_timeout = 5*60; /* secs, tk50 is slow when positioning far apart */ ! 55: ! 56: int sctape_open(tgt, req) ! 57: target_info_t *tgt; ! 58: io_req_t req; ! 59: { ! 60: io_return_t ret; ! 61: io_req_t ior; ! 62: int i; ! 63: scsi_mode_sense_data_t *mod; ! 64: ! 65: #ifdef MACH_KERNEL ! 66: req->io_device->flag |= D_EXCL_OPEN; ! 67: #endif /*MACH_KERNEL*/ ! 68: ! 69: /* Preferably allow tapes to disconnect */ ! 70: if (BGET(scsi_might_disconnect,(unsigned char)tgt->masterno,tgt->target_id)) ! 71: BSET(scsi_should_disconnect,(unsigned char)tgt->masterno,tgt->target_id); ! 72: ! 73: /* ! 74: * Dummy ior for proper sync purposes ! 75: */ ! 76: io_req_alloc(ior,0); ! 77: ior->io_count = 0; ! 78: ! 79: /* ! 80: * Do a mode sense first, some drives might be picky ! 81: * about changing params [even if the standard might ! 82: * say otherwise, sigh.] ! 83: */ ! 84: do { ! 85: ior->io_op = IO_INTERNAL; ! 86: ior->io_next = 0; ! 87: ior->io_error = 0; ! 88: ret = scsi_mode_sense(tgt, 0, 32, ior); ! 89: } while (ret == SCSI_RET_RETRY); ! 90: ! 91: mod = (scsi_mode_sense_data_t *)tgt->cmd_ptr; ! 92: if (scsi_debug) { ! 93: int p[5]; ! 94: bcopy((char*)mod, (char*)p, sizeof(p)); ! 95: printf("[modsns(%x): x%x x%x x%x x%x x%x]", ret, ! 96: p[0], p[1], p[2], p[3], p[4]); ! 97: } ! 98: if (ret == SCSI_RET_DEVICE_DOWN) ! 99: goto out; ! 100: if (ret == SCSI_RET_SUCCESS) { ! 101: tgt->dev_info.tape.read_only = mod->wp; ! 102: tgt->dev_info.tape.speed = mod->speed; ! 103: tgt->dev_info.tape.density = mod->bdesc[0].density_code; ! 104: } /* else they all default sensibly, using zeroes */ ! 105: ! 106: /* Some tapes have limits on record-length */ ! 107: again: ! 108: ior->io_op = IO_INTERNAL; ! 109: ior->io_next = 0; ! 110: ior->io_error = 0; ! 111: ret = scsi_read_block_limits( tgt, ior); ! 112: if (ret == SCSI_RET_RETRY) goto again; ! 113: if (!ior->io_error && (ret == SCSI_RET_SUCCESS)) { ! 114: scsi_blimits_data_t *lim; ! 115: int maxl; ! 116: ! 117: lim = (scsi_blimits_data_t *) tgt->cmd_ptr; ! 118: ! 119: tgt->block_size = (lim->minlen_msb << 8) | ! 120: lim->minlen_lsb; ! 121: ! 122: maxl = (lim->maxlen_msb << 16) | ! 123: (lim->maxlen_sb << 8) | ! 124: lim->maxlen_lsb; ! 125: if (maxl == 0) ! 126: maxl = (unsigned)-1; ! 127: tgt->dev_info.tape.maxreclen = maxl; ! 128: tgt->dev_info.tape.fixed_size = (maxl == tgt->block_size); ! 129: } else { ! 130: /* let the user worry about it */ ! 131: /* default: tgt->block_size = 1; */ ! 132: tgt->dev_info.tape.maxreclen = (unsigned)-1; ! 133: tgt->dev_info.tape.fixed_size = FALSE; ! 134: } ! 135: ! 136: /* Try hard to do a mode select */ ! 137: for (i = 0; i < 5; i++) { ! 138: ior->io_op = IO_INTERNAL; ! 139: ior->io_error = 0; ! 140: ret = sctape_mode_select(tgt, 0, 0, FALSE, ior); ! 141: if (ret == SCSI_RET_SUCCESS) ! 142: break; ! 143: } ! 144: if (scsi_watchdog_period < scsi_tape_timeout) ! 145: scsi_watchdog_period += scsi_tape_timeout; ! 146: ! 147: #if 0 /* this might imply rewind, which we do not want, although yes, .. */ ! 148: /* we want the tape loaded */ ! 149: ior->io_op = IO_INTERNAL; ! 150: ior->io_next = 0; ! 151: ior->io_error = 0; ! 152: ret = scsi_start_unit(tgt, SCSI_CMD_SS_START, ior); ! 153: #endif ! 154: req->io_device->bsize = tgt->block_size; ! 155: out: ! 156: io_req_free(ior); ! 157: return ret; ! 158: } ! 159: ! 160: ! 161: io_return_t sctape_close(tgt) ! 162: target_info_t *tgt; ! 163: { ! 164: io_return_t ret = SCSI_RET_SUCCESS; ! 165: io_req_t ior; ! 166: ! 167: /* ! 168: * Dummy ior for proper sync purposes ! 169: */ ! 170: io_req_alloc(ior,0); ! 171: ior->io_op = IO_INTERNAL; ! 172: ior->io_next = 0; ! 173: ior->io_count = 0; ! 174: ! 175: if (tgt->ior) printf("TAPE: Close with pending requests ?? \n"); ! 176: ! 177: /* write a filemark if we xtnded/truncated the tape */ ! 178: if (tgt->flags & TGT_WRITTEN_TO) { ! 179: tgt->ior = ior; ! 180: ior->io_error = 0; ! 181: ret = scsi_write_filemarks(tgt, 2, ior); ! 182: if (ret != SCSI_RET_SUCCESS) ! 183: printf("%s%d: wfmark failed x%x\n", ! 184: (*tgt->dev_ops->driver_name)(TRUE), tgt->target_id, ret); ! 185: /* ! 186: * Don't bother repositioning if we'll rewind it ! 187: */ ! 188: if (tgt->flags & TGT_REWIND_ON_CLOSE) ! 189: goto rew; ! 190: retry: ! 191: tgt->ior = ior; ! 192: ior->io_op = IO_INTERNAL; ! 193: ior->io_error = 0; ! 194: ior->io_next = 0; ! 195: ret = scsi_space(tgt, SCSI_CMD_SP_FIL, -1, ior); ! 196: if (ret != SCSI_RET_SUCCESS) { ! 197: if (ret == SCSI_RET_RETRY) { ! 198: timeout(wakeup, tgt, hz); ! 199: await(tgt); ! 200: goto retry; ! 201: } ! 202: printf("%s%d: bspfile failed x%x\n", ! 203: (*tgt->dev_ops->driver_name)(TRUE), tgt->target_id, ret); ! 204: } ! 205: } ! 206: rew: ! 207: if (tgt->flags & TGT_REWIND_ON_CLOSE) { ! 208: /* Rewind tape */ ! 209: ior->io_error = 0; ! 210: ior->io_op = IO_INTERNAL; ! 211: ior->io_error = 0; ! 212: tgt->ior = ior; ! 213: (void) scsi_rewind(tgt, ior, FALSE); ! 214: iowait(ior); ! 215: if (tgt->done == SCSI_RET_RETRY) { ! 216: timeout(wakeup, tgt, 5*hz); ! 217: await(tgt); ! 218: goto rew; ! 219: } ! 220: } ! 221: io_req_free(ior); ! 222: ! 223: tgt->flags &= ~(TGT_ONLINE|TGT_WRITTEN_TO|TGT_REWIND_ON_CLOSE); ! 224: return ret; ! 225: } ! 226: ! 227: int sctape_strategy(ior) ! 228: register io_req_t ior; ! 229: { ! 230: target_info_t *tgt; ! 231: register int i = ior->io_unit; ! 232: ! 233: tgt = scsi_softc[rzcontroller(i)]->target[rzslave(i)]; ! 234: ! 235: if (((ior->io_op & IO_READ) == 0) && ! 236: tgt->dev_info.tape.read_only) { ! 237: ior->io_error = D_INVALID_OPERATION; ! 238: ior->io_op |= IO_ERROR; ! 239: ior->io_residual = ior->io_count; ! 240: iodone(ior); ! 241: return ior->io_error; ! 242: } ! 243: ! 244: return rz_simpleq_strategy( ior, sctape_start); ! 245: } ! 246: ! 247: static void ! 248: do_residue(ior, sns, bsize) ! 249: io_req_t ior; ! 250: scsi_sense_data_t *sns; ! 251: int bsize; ! 252: { ! 253: int residue; ! 254: ! 255: /* Not an error situation */ ! 256: ior->io_error = 0; ! 257: ior->io_op &= ~IO_ERROR; ! 258: ! 259: if (!sns->addr_valid) { ! 260: ior->io_residual = ior->io_count; ! 261: return; ! 262: } ! 263: ! 264: residue = sns->u.xtended.info0 << 24 | ! 265: sns->u.xtended.info1 << 16 | ! 266: sns->u.xtended.info2 << 8 | ! 267: sns->u.xtended.info3; ! 268: /* fixed ? */ ! 269: residue *= bsize; ! 270: /* ! 271: * NOTE: residue == requested - actual ! 272: * We only care if > 0 ! 273: */ ! 274: if (residue < 0) residue = 0;/* sanity */ ! 275: ior->io_residual += residue; ! 276: } ! 277: ! 278: void sctape_start( tgt, done) ! 279: target_info_t *tgt; ! 280: boolean_t done; ! 281: { ! 282: io_req_t head, ior = tgt->ior; ! 283: ! 284: if (ior == 0) ! 285: return; ! 286: ! 287: if (done) { ! 288: ! 289: /* see if we must retry */ ! 290: if ((tgt->done == SCSI_RET_RETRY) && ! 291: ((ior->io_op & IO_INTERNAL) == 0)) { ! 292: delay(1000000);/*XXX*/ ! 293: goto start; ! 294: } else ! 295: /* got a bus reset ? ouch, that hurts */ ! 296: if (tgt->done == (SCSI_RET_ABORTED|SCSI_RET_RETRY)) { ! 297: /* ! 298: * we really cannot retry because the tape position ! 299: * is lost. ! 300: */ ! 301: printf("Lost tape position\n"); ! 302: ior->io_error = D_IO_ERROR; ! 303: ior->io_op |= IO_ERROR; ! 304: } else ! 305: ! 306: /* check completion status */ ! 307: ! 308: if (tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) { ! 309: scsi_sense_data_t *sns; ! 310: ! 311: ior->io_op = ior->io_temporary; ! 312: ior->io_error = D_IO_ERROR; ! 313: ior->io_op |= IO_ERROR; ! 314: ! 315: sns = (scsi_sense_data_t *)tgt->cmd_ptr; ! 316: ! 317: if (scsi_debug) ! 318: scsi_print_sense_data(sns); ! 319: ! 320: if (scsi_check_sense_data(tgt, sns)) { ! 321: if (sns->u.xtended.ili) { ! 322: if (ior->io_op & IO_READ) { ! 323: do_residue(ior, sns, tgt->block_size); ! 324: if (scsi_debug) ! 325: printf("Tape Short Read (%d)\n", ! 326: ior->io_residual); ! 327: } ! 328: } else if (sns->u.xtended.eom) { ! 329: do_residue(ior, sns, tgt->block_size); ! 330: if (scsi_debug) ! 331: printf("End of Physical Tape!\n"); ! 332: } else if (sns->u.xtended.fm) { ! 333: do_residue(ior, sns, tgt->block_size); ! 334: if (scsi_debug) ! 335: printf("File Mark\n"); ! 336: } ! 337: } ! 338: } ! 339: ! 340: else if (tgt->done != SCSI_RET_SUCCESS) { ! 341: ! 342: if (tgt->done == SCSI_RET_NEED_SENSE) { ! 343: ! 344: ior->io_temporary = ior->io_op; ! 345: ior->io_op = IO_INTERNAL; ! 346: if (scsi_debug) ! 347: printf("[NeedSns x%x x%x]", ior->io_residual, ior->io_count); ! 348: scsi_request_sense(tgt, ior, 0); ! 349: return; ! 350: ! 351: } else if (tgt->done == SCSI_RET_RETRY) { ! 352: /* only retry here READs and WRITEs */ ! 353: if ((ior->io_op & IO_INTERNAL) == 0) { ! 354: ior->io_residual = 0; ! 355: goto start; ! 356: } else{ ! 357: ior->io_error = D_WOULD_BLOCK; ! 358: ior->io_op |= IO_ERROR; ! 359: } ! 360: } else { ! 361: ior->io_error = D_IO_ERROR; ! 362: ior->io_op |= IO_ERROR; ! 363: } ! 364: } ! 365: ! 366: if (scsi_debug) ! 367: printf("[Resid x%x]", ior->io_residual); ! 368: ! 369: /* dequeue next one */ ! 370: head = ior; ! 371: ! 372: simple_lock(&tgt->target_lock); ! 373: ior = head->io_next; ! 374: tgt->ior = ior; ! 375: if (ior) ! 376: ior->io_prev = head->io_prev; ! 377: simple_unlock(&tgt->target_lock); ! 378: ! 379: iodone(head); ! 380: ! 381: if (ior == 0) ! 382: return; ! 383: } ! 384: ior->io_residual = 0; ! 385: start: ! 386: if (ior->io_op & IO_READ) { ! 387: tgt->flags &= ~TGT_WRITTEN_TO; ! 388: sctape_read( tgt, ior ); ! 389: } else if ((ior->io_op & IO_INTERNAL) == 0) { ! 390: tgt->flags |= TGT_WRITTEN_TO; ! 391: sctape_write( tgt, ior ); ! 392: } ! 393: } ! 394: ! 395: io_return_t ! 396: sctape_get_status( dev, tgt, flavor, status, status_count) ! 397: int dev; ! 398: target_info_t *tgt; ! 399: dev_flavor_t flavor; ! 400: dev_status_t status; ! 401: natural_t *status_count; ! 402: { ! 403: switch (flavor) { ! 404: case DEV_GET_SIZE: ! 405: ! 406: status[DEV_GET_SIZE_DEVICE_SIZE] = 0; ! 407: status[DEV_GET_SIZE_RECORD_SIZE] = tgt->block_size; ! 408: *status_count = DEV_GET_SIZE_COUNT; ! 409: break; ! 410: case TAPE_STATUS: { ! 411: struct tape_status *ts = (struct tape_status *) status; ! 412: ! 413: ts->mt_type = MT_ISSCSI; ! 414: ts->speed = tgt->dev_info.tape.speed; ! 415: ts->density = tgt->dev_info.tape.density; ! 416: ts->flags = (tgt->flags & TGT_REWIND_ON_CLOSE) ? ! 417: TAPE_FLG_REWIND : 0; ! 418: if (tgt->dev_info.tape.read_only) ! 419: ts->flags |= TAPE_FLG_WP; ! 420: #ifdef MACH_KERNEL ! 421: *status_count = TAPE_STATUS_COUNT; ! 422: #endif ! 423: ! 424: break; ! 425: } ! 426: /* U*x compat */ ! 427: case MTIOCGET: { ! 428: struct mtget *g = (struct mtget *) status; ! 429: ! 430: bzero(g, sizeof(struct mtget)); ! 431: g->mt_type = 0x7; /* Ultrix compat */ ! 432: #ifdef MACH_KERNEL ! 433: *status_count = sizeof(struct mtget)/sizeof(int); ! 434: #endif ! 435: break; ! 436: } ! 437: default: ! 438: return D_INVALID_OPERATION; ! 439: } ! 440: return D_SUCCESS; ! 441: } ! 442: ! 443: io_return_t ! 444: sctape_set_status( dev, tgt, flavor, status, status_count) ! 445: int dev; ! 446: target_info_t *tgt; ! 447: dev_flavor_t flavor; ! 448: dev_status_t status; ! 449: natural_t status_count; ! 450: { ! 451: scsi_ret_t ret; ! 452: ! 453: switch (flavor) { ! 454: case TAPE_STATUS: { ! 455: struct tape_status *ts = (struct tape_status *) status; ! 456: if (ts->flags & TAPE_FLG_REWIND) ! 457: tgt->flags |= TGT_REWIND_ON_CLOSE; ! 458: else ! 459: tgt->flags &= ~TGT_REWIND_ON_CLOSE; ! 460: ! 461: if (ts->speed || ts->density) { ! 462: unsigned int ospeed, odensity; ! 463: io_req_t ior; ! 464: ! 465: io_req_alloc(ior,0); ! 466: ior->io_op = IO_INTERNAL; ! 467: ior->io_error = 0; ! 468: ior->io_next = 0; ! 469: ior->io_count = 0; ! 470: ! 471: ospeed = tgt->dev_info.tape.speed; ! 472: odensity = tgt->dev_info.tape.density; ! 473: tgt->dev_info.tape.speed = ts->speed; ! 474: tgt->dev_info.tape.density = ts->density; ! 475: ! 476: ret = sctape_mode_select(tgt, 0, 0, (ospeed == ts->speed), ior); ! 477: if (ret != SCSI_RET_SUCCESS) { ! 478: tgt->dev_info.tape.speed = ospeed; ! 479: tgt->dev_info.tape.density = odensity; ! 480: } ! 481: ! 482: io_req_free(ior); ! 483: } ! 484: ! 485: break; ! 486: } ! 487: /* U*x compat */ ! 488: case MTIOCTOP: { ! 489: struct tape_params *mt = (struct tape_params *) status; ! 490: io_req_t ior; ! 491: ! 492: if (scsi_debug) ! 493: printf("[sctape_sstatus: %x %x %x]\n", ! 494: flavor, mt->mt_operation, mt->mt_repeat_count); ! 495: ! 496: io_req_alloc(ior,0); ! 497: retry: ! 498: ior->io_count = 0; ! 499: ior->io_op = IO_INTERNAL; ! 500: ior->io_error = 0; ! 501: ior->io_next = 0; ! 502: tgt->ior = ior; ! 503: ! 504: /* compat: in U*x it is a short */ ! 505: switch ((short)(mt->mt_operation)) { ! 506: case MTWEOF: /* write an end-of-file record */ ! 507: ret = scsi_write_filemarks(tgt, mt->mt_repeat_count, ior); ! 508: break; ! 509: case MTFSF: /* forward space file */ ! 510: ret = scsi_space(tgt, SCSI_CMD_SP_FIL, mt->mt_repeat_count, ior); ! 511: break; ! 512: case MTBSF: /* backward space file */ ! 513: ret = scsi_space(tgt, SCSI_CMD_SP_FIL, -mt->mt_repeat_count,ior); ! 514: break; ! 515: case MTFSR: /* forward space record */ ! 516: ret = scsi_space(tgt, SCSI_CMD_SP_BLOCKS, mt->mt_repeat_count, ior); ! 517: break; ! 518: case MTBSR: /* backward space record */ ! 519: ret = scsi_space(tgt, SCSI_CMD_SP_BLOCKS, -mt->mt_repeat_count, ior); ! 520: break; ! 521: case MTREW: /* rewind */ ! 522: case MTOFFL: /* rewind and put the drive offline */ ! 523: ret = scsi_rewind(tgt, ior, TRUE); ! 524: iowait(ior); ! 525: if ((short)(mt->mt_operation) == MTREW) break; ! 526: ior->io_op = 0; ! 527: ior->io_next = 0; ! 528: ior->io_error = 0; ! 529: (void) scsi_start_unit(tgt, 0, ior); ! 530: break; ! 531: case MTNOP: /* no operation, sets status only */ ! 532: case MTCACHE: /* enable controller cache */ ! 533: case MTNOCACHE: /* disable controller cache */ ! 534: ret = SCSI_RET_SUCCESS; ! 535: break; ! 536: default: ! 537: tgt->ior = 0; ! 538: io_req_free(ior); ! 539: return D_INVALID_OPERATION; ! 540: } ! 541: ! 542: if (ret == SCSI_RET_RETRY) { ! 543: timeout(wakeup, ior, 5*hz); ! 544: await(ior); ! 545: goto retry; ! 546: } ! 547: ! 548: io_req_free(ior); ! 549: if (ret != SCSI_RET_SUCCESS) ! 550: return D_IO_ERROR; ! 551: break; ! 552: } ! 553: case MTIOCIEOT: ! 554: case MTIOCEEOT: ! 555: default: ! 556: return D_INVALID_OPERATION; ! 557: } ! 558: return D_SUCCESS; ! 559: } ! 560: #endif /* NSCSI > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.