|
|
1.1 ! root 1: /* ! 2: ** Author: John R. Franks ! 3: ** Date: 16-Aug-85 ! 4: ** ! 5: ** This driver is used to control a Tapemaster tape controller. The ! 6: ** Tapemaster controller is a particularly unreasonable controller to work ! 7: ** with. ! 8: ** ! 9: ** We implement both a block device and a raw device with this driver. ! 10: ** (of course) Each device has it's own special requirement as defined below. ! 11: ** ! 12: ** The block device handles files which consist of a series of 1k byte ! 13: ** blocks. It can be read or written to like any random access device, except, ! 14: ** you can not read past the last position written to on tape. The reason ! 15: ** for this is entirly mechanical. Tape drive positioning is not accurate ! 16: ** enough to guarantee that we will not write over a portion of a following ! 17: ** record on the tape. I.e. If we had five known blocks on a tape and we ! 18: ** rewrote the fourth block on the tape, then the fifth block probably ! 19: ** had it's leading gap or the beginning of it's data overwritten. Clearly ! 20: ** the data can not be trusted, so, we just make it a rule that writting ! 21: ** to the tape in any form also defines the end of volume. ! 22: ** ! 23: ** The block device will seek automatically to the next block number if ! 24: ** the tape is mispositioned before the read is done. ! 25: ** ! 26: ** In general the block device should not be used except maybe to ! 27: ** read an exact disk image off of it. ! 28: ** ! 29: ** The raw device is responsible for large reads and writes, and all ! 30: ** ioctl control commands. Each command has to keep the tape in a consistant ! 31: ** state so that they will not be messed up by the sequence of user requests. ! 32: ** As an example: if a user back spaces after a write an end of volume record ! 33: ** will be written before the spacing occurs so that we will be able to ! 34: ** find the end of the file subsequent read operatons. ! 35: ** ! 36: ** The raw device also has the same restrictions on writes as the block ! 37: ** device. ! 38: ** ! 39: ** The ioctls supported by the system are: ! 40: ** ! 41: ** internal name value comments ! 42: ** DO_W_FM 0 Write a file mark to tape ! 43: ** DO_SFMF 1 search for a file mark in the forward direction ! 44: ** DO_SFMB 2 search fo a file mark in the backward direction. ! 45: ** DO_SPF 3 space forward one record ! 46: ** DO_SPB 4 space backward one record ! 47: ** DO_RWTA 5 rewind and wait ! 48: ** DO_RWUN 6 rewind and unload tape ! 49: ** DO_STAT 7 get drive status ! 50: ** DO_RWOV 8 rewind overlapped ! 51: ** DO_WAIT 9 wait for rewind to complete ! 52: */ ! 53: ! 54: /* Includes */ ! 55: ! 56: #include "cy.h" ! 57: #if NCY > 0 ! 58: int cydebug = 0; ! 59: #include "../h/param.h" ! 60: #include "../h/systm.h" ! 61: #include "../machine/mtpr.h" ! 62: #include "../h/vm.h" ! 63: #include "../h/buf.h" ! 64: #include "../machine/pte.h" ! 65: #include "../h/file.h" ! 66: #include "../h/dir.h" ! 67: #include "../h/user.h" ! 68: #include "../h/proc.h" ! 69: #include "../h/signal.h" ! 70: ! 71: #include "../h/uio.h" ! 72: #include "../h/ioctl.h" ! 73: #include "../h/mtio.h" ! 74: #include "../h/errno.h" ! 75: #include "../h/cmap.h" ! 76: #include "../vba/vbavar.h" ! 77: #include "../vba/cipher.h" ! 78: ! 79: ! 80: /* Definitions */ ! 81: ! 82: #define MAXCONTROLLERS 4 ! 83: #define MAX_BLOCKSIZE (TBUFSIZ*NBPG) ! 84: #define NUM_UNIT (NCY * 4) ! 85: ! 86: #define TRUE 1 ! 87: #define FALSE 0 ! 88: #define NOERROR 0 ! 89: #define RETRY 1 ! 90: #define EXTEND 2 ! 91: #define FATAL 3 ! 92: ! 93: #define MAINTAIN_POSITION 0 ! 94: #define DONT_MAINTAIN_POSITION 1 ! 95: ! 96: #define PROCESSED 0x80000000 ! 97: #define SLEEPING 0x80000000 ! 98: #define b_cmd av_back /* only unused word in request */ ! 99: ! 100: ! 101: /* ! 102: ** ioctl command offset definitions. (so we can issue ioctls internally) ! 103: */ ! 104: ! 105: #define DO_W_FM 0 ! 106: #define DO_SFMF 1 ! 107: #define DO_SFMB 2 ! 108: #define DO_SPF 3 ! 109: #define DO_SPB 4 ! 110: #define DO_RWTA 5 ! 111: #define DO_RWUN 6 ! 112: #define DO_STAT 7 ! 113: #define DO_RWOV 8 ! 114: #define DO_WAIT 9 ! 115: #define DO_WEOV 10 ! 116: #define DO_RRD 11 ! 117: #define DO_RWT 12 ! 118: #define DO_BRD 13 ! 119: #define DO_BWT 14 ! 120: ! 121: /* ! 122: ** Declarations for ioctl subroutines (needed for jump table below. ! 123: */ ! 124: ! 125: extern int cywrite_filemark(), cysearch_fm_forw(), cysearch_fm_back(); ! 126: extern int cy_space_forw(), cy_space_back(), cyrewind_tape_ta(); ! 127: extern int cyrewind_tape_unl(), cydrive_status(), cyrewind_tape_ov(); ! 128: extern int cyraw_read(), cyraw_write(), cybuf_read(), cybuf_write(); ! 129: extern int cywait_until_ready(), cywrite_0_fm(), cywrite_1_fm(); ! 130: extern int cywrite_2_fm(), cyno_op(), cywrite_eov(); ! 131: ! 132: /* ! 133: ** Jump table for ioctl functions (used in cystart). ! 134: */ ! 135: ! 136: static int (*cmd_tbl[15])() = { ! 137: cywrite_filemark, cysearch_fm_forw, cysearch_fm_back, cy_space_forw, ! 138: cy_space_back, cyrewind_tape_ta, cyrewind_tape_unl, cydrive_status, ! 139: cyrewind_tape_ov, cywait_until_ready, cywrite_eov, cyraw_read, ! 140: cyraw_write, cybuf_read, cybuf_write ! 141: }; ! 142: ! 143: /* Variables */ ! 144: ! 145: /* Autoconfigure entry point definitions */ ! 146: ! 147: extern int cyprobe(), cyslave(), cyattach(), cydgo(); ! 148: ! 149: /* physio routines */ ! 150: ! 151: extern unsigned cyminsize(); ! 152: ! 153: /* Define driver structures for UNIX */ ! 154: ! 155: extern char cy0utl[]; ! 156: #if NCY > 0 ! 157: extern char cy1utl[]; ! 158: #endif ! 159: ! 160: static fmt_scp *scp_ptrs[MAXCONTROLLERS] = { ! 161: (fmt_scp *)0xc0000c06, (fmt_scp *)0xc0000c16, ! 162: }; ! 163: ! 164: struct vba_ctlr *cyminfo[NCY]; ! 165: ! 166: struct vba_device *cydinfo[NUM_UNIT]; ! 167: ! 168: struct vba_driver cydriver = ! 169: { ! 170: cyprobe, cyslave, cyattach, cydgo, (long *)scp_ptrs, ! 171: "cipher", cydinfo, "", cyminfo ! 172: }; ! 173: ! 174: /* Define data structures for controllers */ ! 175: ! 176: typedef struct { ! 177: struct pte *map; ! 178: char *utl; ! 179: int (*interupt_path)(); ! 180: label_t environ; /* Environment variable for longjmps */ ! 181: struct buf *my_request; ! 182: struct buf *wakeup_request; ! 183: short bs; /* buffer size */ ! 184: fmt_ccb ccb; /* Channel control blocks */ ! 185: fmt_scb scb; /* System configuration blocks */ ! 186: fmt_tpb tpb; /* Tape parameter blocks */ ! 187: fmt_tpb last; /* Tape parameter blocks */ ! 188: fmt_tpb noop; /* Tape parameter blocks */ ! 189: long rawbuf[MAX_BLOCKSIZE/sizeof(long)+1]; ! 190: } ctlr_tab; ! 191: ! 192: extern int cy_normal_path(); ! 193: ! 194: ctlr_tab ctlr_info[NCY] = { ! 195: {CY0map, cy0utl, cy_normal_path} ! 196: #if NCY > 1 ! 197: ,{CY1map, cy1utl, cy_normal_path} ! 198: #if NCY > 2 ! 199: error /* Only 2 controllers can be used at this time */ ! 200: #endif ! 201: #endif ! 202: }; ! 203: ! 204: /* information needed for each drive */ ! 205: ! 206: typedef struct { ! 207: int (*cleanup)(); ! 208: struct buf u_queue; ! 209: struct buf rawbp; ! 210: long blkno; ! 211: long file_number; ! 212: short last_control; ! 213: short last_status; ! 214: short last_resid; ! 215: unsigned long bad_count; ! 216: unsigned control_proto: 16; ! 217: unsigned error_count : 8; ! 218: unsigned open : 1; ! 219: unsigned eof : 1; ! 220: unsigned bot : 1; ! 221: unsigned eot : 1; ! 222: char *message; ! 223: }unit_tab; ! 224: ! 225: unit_tab unit_info[NUM_UNIT]; ! 226: ! 227: ! 228: /* ! 229: ** Cyprobe checks to see if a controller is present on the VERSAbus. ! 230: ** An attempt is made to read from the controller's first register, if ! 231: ** a buss error does not occur then the controller is assumed to be ! 232: ** there. ! 233: ** ! 234: ** If the controller responds to the read request, then we go ahead ! 235: ** and initialize the controller for UNIX's use. If no problems were ! 236: ** reported during system initialization, then we return TRUE to the ! 237: ** system to indicate that the controller is there and everything is OK. ! 238: */ ! 239: ! 240: cyprobe(ctlr_vaddr) ! 241: register caddr_t ctlr_vaddr; ! 242: { ! 243: static int ctlr = -1; ! 244: ! 245: ctlr++; ! 246: if (!badcyaddr(ctlr_vaddr + 1)) ! 247: return cy_init_controller(ctlr_vaddr, ctlr, 1); ! 248: return FALSE; ! 249: } ! 250: ! 251: ! 252: /* ! 253: ** Cy_init_controller is called to initialize the controller after the ! 254: ** controller is reset or during Autoconfigure. All of the system control ! 255: ** blocks are initialized and the controller is asked to configure itself ! 256: ** for later use. ! 257: ** ! 258: ** If the print value is true cy_first_TM_attention will anounce ! 259: ** the type of controller we are (Tapemasher) and will print the size ! 260: ** of the internal controller buffer. ! 261: */ ! 262: ! 263: cy_init_controller(ctlr_vaddr, ctlr, print) ! 264: register caddr_t ctlr_vaddr; ! 265: register int ctlr; ! 266: register int print; ! 267: { ! 268: cy_init_sys_config_ptr(ctlr); ! 269: cy_init_sys_config_blk(ctlr); ! 270: cy_init_channel_control_blk(ctlr); ! 271: return cy_first_TM_attention(ctlr_vaddr, ctlr, print); ! 272: } ! 273: ! 274: ! 275: /* ! 276: ** Cyslave checks to see if a drive is attached to a controller. ! 277: ** There are no signals, on the serial buses from the tape drive to the ! 278: ** controller, to indicate that a drive is physically present on the ! 279: ** buss. We can only tell that a drive is there if a tape is loaded ! 280: ** on the drive and the drive is placed online. ! 281: ** ! 282: ** Since it would be ridiculus to force system operators to load ! 283: ** tapes on every tape drive on the system before every boot operation, ! 284: ** we simply indicate that the drive is there every time we are asked. ! 285: ** ! 286: ** In theory the system should be configured according to the ! 287: ** hardware configuration anyway and should not present a problem. ! 288: */ ! 289: ! 290: cyslave(vba_device_info, ctlr_vaddr) ! 291: register struct vba_device *vba_device_info; ! 292: register caddr_t ctlr_vaddr; ! 293: { ! 294: /* ! 295: * assume tape is connected because there is ! 296: * no way on earth to tell if the drive is connected or not. ! 297: */ ! 298: return TRUE; ! 299: } ! 300: ! 301: ! 302: /* ! 303: ** cyattach is used to add a drive to our internal tables. ! 304: */ ! 305: ! 306: cyattach(dev_info) ! 307: struct vba_device *dev_info; ! 308: { ! 309: register unit_tab *u_info = &unit_info[dev_info->ui_unit]; ! 310: register struct buf *ctlr_queue = &dev_info->ui_mi->um_tab; ! 311: register struct buf *unit_queue = ctlr_queue->b_forw; ! 312: register struct buf *start_queue = unit_queue; ! 313: ! 314: /* Add unit to controllers queue */ ! 315: if(ctlr_queue->b_forw == NULL) { ! 316: ctlr_queue->b_forw = &u_info->u_queue; ! 317: u_info->u_queue.b_forw = &u_info->u_queue; ! 318: } ! 319: else { ! 320: while(unit_queue->b_forw != start_queue) ! 321: unit_queue = unit_queue->b_forw; ! 322: u_info->u_queue.b_forw = start_queue; ! 323: unit_queue->b_forw = &u_info->u_queue; ! 324: } ! 325: u_info->cleanup = cyno_op; ! 326: u_info->last_status = 0; ! 327: u_info->last_control = 0; ! 328: u_info->file_number = 0; ! 329: u_info->bad_count = 0; ! 330: u_info->blkno = 0; ! 331: u_info->open = FALSE; ! 332: u_info->bot = TRUE; ! 333: u_info->eot = FALSE; ! 334: u_info->eof = FALSE; ! 335: u_info->message = NULL; ! 336: } ! 337: ! 338: ! 339: /* ! 340: ** Historic routine left over from VAX port but the definition is still ! 341: ** hanging around. ! 342: */ ! 343: ! 344: cydgo() ! 345: { ! 346: } ! 347: ! 348: /* ! 349: ** cy_init_sys_config_ptr initializes the Tapemaster system configuration ! 350: ** pointer. The Tapemaster controller requires it's own system pointer ! 351: ** in low memory. The absolute addresses are 0xc06 for controller #1, and ! 352: ** 0xc16 for controller #2. (The space definitions are in locore.s if you ! 353: ** want to add anther controller to the system. (good luck)) ! 354: ** ! 355: ** This routine sets the correct page to give kernel write access, ! 356: ** loads in the appropriate values, and then resets the page to kernel read ! 357: ** only access to prevent other routines from stepping all over the scp ! 358: ** and causing obscure tape problems. ! 359: ** ! 360: ** The format of the system configuration pointer is as follows: ! 361: ** ! 362: ** 8 bits 8 bits 32 bits (20 that count) ! 363: ** +----------+----------+----------------+ ! 364: ** | bus size | unused | Pointer to scb | ! 365: ** +----------+----------+----------------+ ! 366: */ ! 367: ! 368: cy_init_sys_config_ptr(ctlr) ! 369: register int ctlr; ! 370: { ! 371: register int *pte_ptr; ! 372: register fmt_scp *SCP = scp_ptrs[ctlr]; ! 373: ! 374: /* Set the page to kernel write access */ ! 375: pte_ptr = (int *)vtopte(0, btop(SCP)); ! 376: *pte_ptr &= ~PG_PROT; /* clear all protection bits */ ! 377: *pte_ptr |= PG_KW /* allow kernal writes */; ! 378: mtpr(SCP, TBIS); ! 379: /* load the correct values in the scp */ ! 380: SCP->bus_size = _16_BITS; ! 381: load_mbus_addr(&ctlr_info[ctlr].scb, SCP->scb_ptr); ! 382: /* Give read only privialages to the kernel */ ! 383: *pte_ptr &= ~PG_PROT; /* clear all protection bits */ ! 384: *pte_ptr |= PG_KR; /* allow only kernal */ ! 385: mtpr(SCP, TBIS); ! 386: } ! 387: ! 388: ! 389: /* ! 390: ** cy_init_sys_config_blk loads the appropriate values into the ! 391: ** system configuration block for the Tapemaster controller. ! 392: ** ! 393: ** This data structure does not contain any useful information ! 394: ** for us. The only possible use for this block is for a ! 395: ** consistancy check by the controller itself using the fixed value. ! 396: ** but that could have been done elsewhere. However the controller will ! 397: ** not run without it so we maintain this structure here..... ! 398: ** ! 399: ** The format of the system configuration block is as follows: ! 400: ** ! 401: ** 8 bits 8 bits 32 bits (20 that count) ! 402: ** +-----------+----------+----------------+ ! 403: ** | must be 3 | unused | Pointer to ccb | ! 404: ** +-----------+----------+----------------+ ! 405: */ ! 406: ! 407: cy_init_sys_config_blk(ctlr) ! 408: register int ctlr; ! 409: { ! 410: register fmt_scb *SCB = &ctlr_info[ctlr].scb; ! 411: ! 412: SCB->fixed_value = 0x3; ! 413: /* set pointer to the channel control block */ ! 414: load_mbus_addr(&ctlr_info[ctlr].ccb, SCB->ccb_ptr); ! 415: } ! 416: ! 417: ! 418: /* ! 419: ** Cy_init_channel_control_blk is used to load the initial values into ! 420: ** the ccb structures for the controller. ! 421: ** ! 422: ** The format of the channel control block is as follows: ! 423: ** ! 424: ** 8 bits 8 bits 32 bits (20 that count) ! 425: ** +-----------+----------+----------------+ ! 426: ** | CCW | gate | Pointer to tpb | ! 427: ** +-----------+----------+----------------+ ! 428: ** ! 429: ** the CCW field is used to control interupt operations. If the field is ! 430: ** equal to 11(hex) then interupts are enabled, if it contains a 9(hex) then ! 431: ** the Tapemaster controller is instructed to stop interupting (it will ! 432: ** flood the system with interupts until it is instructed to stop!) ! 433: ** ! 434: ** The gate field is used to syncronize the processor operations and ! 435: ** the controller. We close it when an operation is started, ! 436: ** It is opened by the controller when the operation is done. ! 437: */ ! 438: ! 439: cy_init_channel_control_blk(ctlr) ! 440: register int ctlr; ! 441: { ! 442: register fmt_ccb *CCB = &ctlr_info[ctlr].ccb; ! 443: ! 444: CCB->ccw = CLEAR_INTERUPT; ! 445: CCB->gate = GATE_OPEN; ! 446: /* set pointer to the tape parameter block */ ! 447: load_mbus_addr(&ctlr_info[ctlr].tpb, CCB->tpb_ptr); ! 448: } ! 449: ! 450: ! 451: /* ! 452: ** Cy_first_TM_attention is used to issue the very first command ! 453: ** after boot or after the controller is reset. This case is special ! 454: ** since we 1) should not interupt duing this sequence, 2) really need ! 455: ** to issue two commands, and 3) we need to get the controller's internal ! 456: ** buffer size for future reference. ! 457: ** ! 458: ** The print flag is used so that we only print out the greeting ! 459: ** message during Autoconfigure time. (it would be obnoxious if it ! 460: ** printed every time the drive times out.) ! 461: ** ! 462: ** The first NOOP command is issued to get the drive's attention. ! 463: ** The tpb is never even looked during the first attention. ! 464: ** ! 465: ** The second command actually configures the controller and returns ! 466: ** the internal buffersize for buffered I/O. ! 467: */ ! 468: ! 469: cy_first_TM_attention(ctlr_vaddr, ctlr, print) ! 470: register caddr_t ctlr_vaddr; ! 471: register int ctlr, print; ! 472: { ! 473: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 474: ! 475: /* set command to be CONFIGURE */ ! 476: c_info->tpb.cmd = NO_OP; ! 477: c_info->tpb.control = CW_16bits; ! 478: c_info->ccb.gate = GATE_CLOSED; ! 479: CY_ATTENTION(ctlr_vaddr); /* execute! */ ! 480: if(cywait(&c_info->ccb) || (c_info->tpb.status & CS_ERm)) { ! 481: printf("Tapemaster controller time-out during initialization!\n"); ! 482: return FALSE; ! 483: } ! 484: c_info->tpb.cmd = CONFIG; ! 485: c_info->tpb.control = CW_16bits; ! 486: c_info->ccb.gate = GATE_CLOSED; ! 487: CY_ATTENTION(ctlr_vaddr); /* execute! */ ! 488: if(cywait(&c_info->ccb) || (c_info->tpb.status & CS_ERm)) { ! 489: cyprint_err("Tapemaster configuration failure", ! 490: 0, c_info->tpb.status); ! 491: return FALSE; ! 492: } ! 493: uncache(&c_info->tpb.count); ! 494: c_info->bs = MULTIBUS_SHORT(c_info->tpb.count); ! 495: if(print) ! 496: printf("Tapemaster with %dkb buffer: controller #", ! 497: c_info->bs/1024); ! 498: return TRUE; ! 499: } ! 500: ! 501: ! 502: /* ! 503: ** Cyopen is called every time a process opens the tape for reading ! 504: ** or writting. Tape drives are single access in that only one process ! 505: ** can have the drive open at any one time. It is responsibility of ! 506: ** cyopen to keep track of whether the drive is already open and to ! 507: ** refuse access to everybody else on the system. ! 508: ** ! 509: ** The other functions of cyopen are to make sure a tape is mounted ! 510: ** and the drive is on-line, If the drive is currently rewinding we ! 511: ** should wait for it to complete before returning, if the drive is ! 512: ** at load point then our internal file pointers are reset, and to ! 513: ** set up a proto-type control word for use during later tape operations. ! 514: ** ! 515: ** The control proto-type is set up in open to save time later on. ! 516: ** It contains all the invariant information the controller needs to ! 517: ** access a drive. This information includes the unpacked unit number, ! 518: ** (See the UNIT macro below), the drive speed/density (always set at the ! 519: ** drive), the buss width (always 16 bit) and the interupts emnable bit ! 520: ** (always enabled). ! 521: */ ! 522: ! 523: /* macro to pack the unit number into Tapemaster format */ ! 524: #define UNIT(d) (((cydinfo[CYUNIT(d)]->ui_slave & 1) << 11) | \ ! 525: ((cydinfo[CYUNIT(d)]->ui_slave & 2) << 9) | \ ! 526: ((cydinfo[CYUNIT(d)]->ui_slave & 4) >> 2)) ! 527: ! 528: cyopen(dev, flag) ! 529: register int flag; ! 530: register dev_t dev; ! 531: { ! 532: register int status, unit = CYUNIT(dev); ! 533: register unit_tab *u_info = &unit_info[unit]; ! 534: ! 535: if (!(status = cyvalid_drive(unit))) { ! 536: u_info->control_proto = UNIT(dev) | CW_INTR | CW_16bits; ! 537: u_info->blkno = 0; ! 538: u_info->bad_count = 0; ! 539: u_info->eof = FALSE; ! 540: u_info->open = TRUE; ! 541: if(status = cy_open_error(dev,flag)) ! 542: u_info->open = FALSE; ! 543: } ! 544: return status; ! 545: } ! 546: ! 547: ! 548: /* ! 549: ** cyvalid_drive is called to make sure a drive is attached to ! 550: ** to the system and, if it is, if it is already open by another process. ! 551: ** If the drive is already open busy status is returned, if it is not ! 552: ** attached to the system then non-existant device is returned, otherwise, ! 553: ** zero is returned to indicate no error. ! 554: */ ! 555: ! 556: cyvalid_drive(unit) ! 557: register int unit; ! 558: { ! 559: /* if unit is less than maximum possible unit */ ! 560: if (unit < NUM_UNIT) ! 561: /* if the drive is attached */ ! 562: if (cydinfo[unit]) ! 563: /* if drive is not already open */ ! 564: if(!unit_info[unit].open) ! 565: return NOERROR; ! 566: else ! 567: return EBUSY; ! 568: return ENXIO; ! 569: } ! 570: ! 571: ! 572: /* ! 573: ** Cy_open_error is called by open after verifing that the drive ! 574: ** is eligable to be opened. The hardware status is checked and if ! 575: ** any errors are found (i.e. not online, write protected when opened for ! 576: ** writes, and opening past the end of tape marker) then the error number ! 577: ** is returned. ! 578: ** ! 579: ** As part of the sequence we must wait around if the drive is online ! 580: ** and rewinding until the rewind is done or the operator takes the drive ! 581: ** offline. During the wait we poll the drive every 5 seconds until ! 582: ** either of the above conditions are met. ! 583: */ ! 584: ! 585: cy_open_error(dev,flag) ! 586: register int flag; ! 587: register dev_t dev; ! 588: { ! 589: register int unit = CYUNIT(dev); ! 590: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 591: register ctlr_tab *c_info = &ctlr_info[cydinfo[unit]->ui_ctlr]; ! 592: ! 593: cycmd(dev, DO_WAIT, 1); ! 594: if(!(u_info->last_status & CS_OL)) ! 595: return ENXIO; ! 596: if((flag & FWRITE) && (u_info->last_status & CS_P)) { ! 597: uprintf("cy%d: Tape is write protected!\n", unit); ! 598: return ENXIO; ! 599: } ! 600: if(u_info->last_status & CS_LP) { ! 601: u_info->file_number = 0; ! 602: u_info->bot = TRUE; ! 603: u_info->eof = u_info->eot = FALSE; ! 604: } ! 605: return NOERROR; ! 606: } ! 607: ! 608: ! 609: /* ! 610: ** Cyclose is called every time a process closes a tape file, exits, ! 611: ** or is otherwise removed for the run queue. We take this oportunity to ! 612: ** mark the drive closed, write end of volume records (two tape marks), and ! 613: ** rewind the tape (if requested that we do so). ! 614: ** ! 615: ** Take note that we write the end of volume records by spacing backwards. ! 616: ** This is done because the all the commands keep track of the necessary ! 617: ** special cases. It just so happens that spacing back after a write will ! 618: ** generate an end of volume record before spacing back. After the space back ! 619: ** is called we space forward to position ourselfs between the two filemarks ! 620: ** in anticipation of further writes to tape. ! 621: ** ! 622: ** Also, the rewind logic takes care of end of volume records so if ! 623: ** we just issue a overlapped rewind request if we were opened using ! 624: ** the rewinding special file. ! 625: */ ! 626: ! 627: cyclose(dev, flag) ! 628: register dev_t dev; ! 629: register flag; ! 630: { ! 631: register int unit = CYUNIT(dev); ! 632: register unit_tab *u_info = &unit_info[unit]; ! 633: ! 634: if(u_info->last_status & CS_OL) ! 635: if((flag & FWRITE) && (minor(dev) & T_NOREWIND)) ! 636: cycmd(dev, DO_WEOV, 1); ! 637: else if(!(minor(dev) & T_NOREWIND)) ! 638: cycmd(dev, DO_RWOV, 1); ! 639: if(u_info->bad_count != 0) { ! 640: u_info->bad_count *= 889; ! 641: uprintf("cy%d: Warning - %d.%dcm of tape were used for recovering bad spots.\n", unit, u_info->bad_count/100, u_info->bad_count%100); ! 642: u_info->bad_count = 0; ! 643: } ! 644: u_info->open = 0; ! 645: } ! 646: ! 647: ! 648: /* ! 649: ** Cycmd is used intrernally to implement all the ioctl functions ! 650: ** that are needed by the driver. We duplicate the code in physio ! 651: ** that is used for syncronizing the processes (sleep / wakeup) so ! 652: ** that we can treat our internal command requests exactly like ! 653: ** regular reads and writes. They get put on the controller queue, ! 654: ** start processes them and iodone is called to wake us up on completion. ! 655: ** ! 656: ** We don't call physio directly because it expects data to be moved ! 657: ** and has a lot more overhead than we really need. ! 658: */ ! 659: ! 660: cycmd(dev, command, count) ! 661: register dev_t dev; ! 662: register long command; ! 663: register int count; ! 664: { ! 665: register int unit = CYUNIT(dev); ! 666: register unit_tab *u_info = &unit_info[unit]; ! 667: register unsigned short error; ! 668: register int priority = spl3(); ! 669: ! 670: while (u_info->rawbp.b_flags & B_BUSY) { ! 671: u_info->rawbp.b_flags |= B_WANTED; ! 672: sleep(&u_info->rawbp, PRIBIO+1); ! 673: } ! 674: splx(priority); ! 675: ! 676: /* load the request queue element */ ! 677: u_info->rawbp.b_error = 0; ! 678: u_info->rawbp.b_dev = dev; ! 679: u_info->rawbp.b_cmd = (struct buf *)command; ! 680: u_info->rawbp.b_bcount = count; ! 681: u_info->rawbp.b_flags = B_PHYS | B_BUSY; ! 682: queue_request(&u_info->rawbp, &u_info->u_queue, cydinfo[unit]->ui_mi); ! 683: ! 684: /* wait for operation to complete */ ! 685: while(!(u_info->rawbp.b_flags & B_DONE)) ! 686: sleep(&u_info->rawbp, PRIBIO); ! 687: u_info->rawbp.b_flags &= ~(B_PHYS | B_BUSY); ! 688: if(u_info->rawbp.b_flags & B_WANTED) ! 689: wakeup (&u_info->rawbp); ! 690: return geterror(&u_info->rawbp); ! 691: } ! 692: ! 693: /* ! 694: ** Check the validity of the request and then place ! 695: ** the request on the controller's request queue if it is ok. ! 696: ** ! 697: ** Take note that the only validity check is the block size. ! 698: ** all other checking, such as, drive number, online, controller attached, ! 699: ** is done in the open routine. ! 700: ** ! 701: ** If the drive dropped offline this will be notced int the ! 702: ** start / interupt routine (depending on when it dropped offline). ! 703: */ ! 704: ! 705: cystrategy(request) ! 706: register struct buf *request; ! 707: { ! 708: register int unit = CYUNIT(request->b_dev); ! 709: register unit_tab *u_info = &unit_info[unit]; ! 710: register struct buf *unit_queue; ! 711: ! 712: /* check the validity of the request */ ! 713: if (request->b_bcount <= MAX_BLOCKSIZE) { ! 714: /* place request on queue and start it if everything is ok */ ! 715: unit_queue = &u_info->u_queue; ! 716: buf_setup(request, MAX_BLOCKSIZE); ! 717: if(request->b_flags & B_PHYS) ! 718: if(request->b_flags & B_READ) ! 719: request->b_cmd = (struct buf *)DO_RRD; ! 720: else ! 721: request->b_cmd = (struct buf *)DO_RWT; ! 722: else ! 723: if(request->b_flags & B_READ) ! 724: request->b_cmd = (struct buf *)DO_BRD; ! 725: else { ! 726: request->b_cmd = (struct buf *)DO_BWT; ! 727: ! 728: } ! 729: queue_request(request, unit_queue, cydinfo[unit]->ui_mi); ! 730: return; ! 731: } ! 732: uprintf("cy%d: Maximum block size is %dk!\n", unit, MAX_BLOCKSIZE/1024); ! 733: request->b_error = EIO; ! 734: request->b_resid = request->b_bcount; ! 735: request->b_flags |= B_ERROR; ! 736: iodone(request); ! 737: } ! 738: ! 739: ! 740: /* ! 741: ** The routines below are used to handle a unit's request queue. ! 742: ** The queue is a linked list of buf structures. The linkage is as follows: ! 743: ** ! 744: ** +------------------------------------------------+ ! 745: ** | v ! 746: ** | +-----------+ +-----------+ +-----------+ ! 747: ** | | av_forw |------>| av_forw |--~ ~-->| av_forw |-->NULL ! 748: ** | +-----------+ +-----------+ +-----------+ ! 749: ** +-| av_back | | ......... | | ......... | ! 750: ** +-----------+ +-----------+ +-----------+ ! 751: ** | ......... | First queue Last queue ! 752: ** +-----------+ element element ! 753: ** head of unit queue ! 754: ** (unit_tab[unit].queue) ! 755: */ ! 756: ! 757: /* ! 758: ** Queue_request places a queue element on the end of a unit's ! 759: ** request queue. ! 760: */ ! 761: ! 762: queue_request(request, unit_queue, vba_ctlr_info) ! 763: register struct buf *request; ! 764: register struct buf *unit_queue; ! 765: struct vba_ctlr *vba_ctlr_info; ! 766: { ! 767: register int priority = spl3(); ! 768: ! 769: request->av_forw = NULL; ! 770: if (unit_queue->av_forw == NULL) ! 771: unit_queue->av_forw = request; ! 772: else ! 773: unit_queue->av_back->av_forw = request; ! 774: unit_queue->av_back = request; ! 775: cystart(vba_ctlr_info, request, priority); ! 776: } ! 777: ! 778: ! 779: /* ! 780: ** Dequeue_request removes the first element in a unit's request queue. ! 781: */ ! 782: ! 783: dequeue_request(unit_queue) ! 784: register struct buf *unit_queue; ! 785: { ! 786: register int priority = spl3(); ! 787: ! 788: if ((unit_queue->av_forw = unit_queue->av_forw->av_forw) == NULL) ! 789: unit_queue->av_back = NULL; ! 790: splx(priority); ! 791: } ! 792: ! 793: ! 794: /* ! 795: ** Cystart is called once for every request that is placed on a ! 796: ** controller's queue. Start is responsible for fetching requests for ! 797: ** a controller queue, starting the operation, and waiting for completion, ! 798: ** and releasing the buf structure back to UNIX or cycmd, before fetching ! 799: ** the next request. ! 800: ** ! 801: ** The controller's queue looks like this: ! 802: ** ! 803: ** +---------------------------------------+ ! 804: ** | | ! 805: ** +-----------+ | +-----------+ +-----------+ | ! 806: ** | b_forw |---+-->| b_forw |--~ ~-->| b_forw |--+ ! 807: ** +-----------+ +-----------+ +-----------+ ! 808: ** | b_back | | ......... | | ......... | ! 809: ** +-----------+ +-----------+ +-----------+ ! 810: ** | ......... | First unit queue Last unit queue ! 811: ** +-----------+ element element ! 812: ** head of controller queue ! 813: ** (cyminfo[ctlr].um_tab) ! 814: ** ! 815: ** To access the unit queues we simply get the controller's unit queue ! 816: ** pointer and if anything is on the unit queue that we are pointing to ! 817: ** we start that command, otherwise we get the next pointer and go on. ! 818: ** we know to stop looking when we have gone through the entire list ! 819: ** without starting any activity. We know we are at the end of the ! 820: ** queue when the next pointer equals the original pointer int the queue. ! 821: ** ! 822: ** To provind a fair scheduling policy we simply repoint the controller's ! 823: ** queue pointer to the next unit queue every time a command is started. ! 824: ** ! 825: ** If the controller is currently busy then we just return so that the ! 826: ** calling routine can go to sleep until we are finished processing the ! 827: ** request. ! 828: ** ! 829: ** Each buf structure has an index into a jump table loaded into ! 830: ** it by strategy or cycmd depending on where the buff originated. ! 831: ** this index is loaded so that start processing can continue without ! 832: ** much delay, and so that each operation can have it's unique requirements ! 833: ** satisfied in a clear and consistent manor. ! 834: ** ! 835: ** Each and every routine that is called by start is responsible for ! 836: ** proper tape positioning, writting end of file marks correctly, error ! 837: ** recovery, and whatever else may unique about the particular operation. ! 838: ** Each routine calls cyexecute whenever it actually wants to issue a ! 839: ** command to the controller. Each routine is also responsible for releasing ! 840: ** the request when is is done with it. ! 841: */ ! 842: ! 843: cystart(vba_ctlr_info, request, priority) ! 844: register struct vba_ctlr *vba_ctlr_info; ! 845: register struct buf *request; ! 846: { ! 847: struct buf *cyget_next(); ! 848: extern int cystart_timeout(); ! 849: register int unit = CYUNIT(request->b_dev); ! 850: register int ctlr = vba_ctlr_info->um_ctlr; ! 851: register struct buf *next, *ctlr_queue = &vba_ctlr_info->um_tab; ! 852: register unit_tab *u_info = &unit_info[unit]; ! 853: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 854: ! 855: if(ctlr_queue->b_active & SLEEPING) { ! 856: untimeout(cystart_timeout, ctlr_queue); ! 857: cystart_timeout(ctlr_queue); ! 858: } ! 859: if(ctlr_queue->b_active) { ! 860: sleep(request, PRIBIO-1); ! 861: if(request->b_flags & PROCESSED) { ! 862: if(u_info->message != NULL) { ! 863: uprintf("cy%d: %s!\n", unit, u_info->message); ! 864: u_info->message = NULL; ! 865: } ! 866: request->b_flags &= ~PROCESSED; ! 867: iodone(request); ! 868: return; ! 869: } ! 870: } ! 871: ctlr_queue->b_active = TRUE; ! 872: splx(priority); ! 873: c_info->my_request = request; ! 874: cydo_my_command(ctlr, ctlr_queue, c_info); ! 875: if(u_info->message != NULL) { ! 876: uprintf("cy%d: %s!\n", unit, u_info->message); ! 877: u_info->message = NULL; ! 878: } ! 879: request->b_flags &= ~PROCESSED; ! 880: iodone(request); ! 881: if((next = cyget_next(ctlr_queue)) != NULL) ! 882: wakeup(next); ! 883: else ! 884: ctlr_queue->b_active = FALSE; ! 885: } ! 886: ! 887: ! 888: /* ! 889: ** Cystart_timeout wakes up the start routine after it's 3 ! 890: ** second wait time is up or when a new command enters the queue. ! 891: ** ! 892: ** The timer is used to give up the processor while all drives ! 893: ** on the queue are rewinding and we need to wait for them to be dome. ! 894: ** Without this feature we would hog the processor polling for the drives ! 895: ** to be done. ! 896: */ ! 897: ! 898: cystart_timeout(ctlr_queue) ! 899: register struct buf *ctlr_queue; ! 900: { ! 901: ctlr_queue->b_active &= ~SLEEPING; ! 902: wakeup(ctlr_queue); ! 903: } ! 904: ! 905: ! 906: /* ! 907: ** Cydo_my command scans the request queues once for a ! 908: ** particular controller and calls the appropriate processing routine ! 909: ** each time we find a request that can be started. ! 910: ** ! 911: ** We return TRUE if a command is executed during this round. IF either ! 912: ** the queue is empty or all commands on the queue are waiting for the drives ! 913: ** to rewind we return FALSE. ! 914: */ ! 915: ! 916: cydo_my_command(ctlr, ctlr_queue, c_info) ! 917: register struct buf *ctlr_queue; ! 918: register ctlr_tab *c_info; ! 919: { ! 920: struct buf *cyget_next(); ! 921: register struct buf *unit_queue, *next; ! 922: ! 923: while((next = cyget_next(ctlr_queue)) != NULL) { ! 924: if(ctlr_queue->b_forw->b_active & SLEEPING) { ! 925: ctlr_queue->b_active |= SLEEPING; ! 926: timeout(cystart_timeout, ctlr_queue, 1*60); ! 927: sleep(ctlr_queue, PRIBIO); ! 928: continue; ! 929: } ! 930: if(setjmp(&ctlr_info[ctlr].environ)) ! 931: cydone(ctlr_queue); ! 932: else { ! 933: register int cmd=(int)(next->b_cmd); ! 934: ! 935: (*cmd_tbl[cmd])(next, ctlr_queue); ! 936: } ! 937: if(next->b_flags & PROCESSED) ! 938: if(c_info->my_request != next) ! 939: wakeup(next); ! 940: else ! 941: return; ! 942: } ! 943: } ! 944: ! 945: ! 946: struct buf *cyget_next(ctlr_queue) ! 947: register struct buf *ctlr_queue; ! 948: { ! 949: register struct buf *request, *unit_queue, *next = NULL; ! 950: ! 951: ctlr_queue->b_forw = ctlr_queue->b_forw->b_forw; ! 952: unit_queue = ctlr_queue->b_forw; ! 953: do { ! 954: if((request = unit_queue->av_forw) != NULL) ! 955: if(!(unit_queue->b_active & SLEEPING)) { ! 956: ctlr_queue->b_forw = unit_queue; ! 957: return request; ! 958: } ! 959: else ! 960: next = unit_queue; ! 961: unit_queue = unit_queue->b_forw; ! 962: } while(unit_queue != ctlr_queue->b_forw); ! 963: if(next != NULL) { ! 964: ctlr_queue->b_forw = next; ! 965: return next->av_forw; ! 966: } ! 967: return NULL; ! 968: } ! 969: ! 970: ! 971: /* ! 972: ** Cydone is called by each routine that is thorugh processing a ! 973: ** user request. It removes the request from our queues, counts down ! 974: ** the number of active requests that we have in our queues and releases ! 975: ** the request back to UNIX. ! 976: */ ! 977: ! 978: cydone(ctlr_queue) ! 979: register struct buf *ctlr_queue; ! 980: { ! 981: register struct buf *unit_queue = ctlr_queue->b_forw; ! 982: register struct buf *request = unit_queue->av_forw; ! 983: register int unit = CYUNIT(request->b_dev); ! 984: register ctlr_tab *c_info = &ctlr_info[cydinfo[unit]->ui_ctlr]; ! 985: ! 986: unit_queue->av_forw->b_flags |= PROCESSED; ! 987: dequeue_request(unit_queue); ! 988: } ! 989: ! 990: ! 991: /* ! 992: ** All the routines between here and Cyintr are used to process the ! 993: ** individual commands (read, write, rewind, ...) that can possibly be ! 994: ** generated by the system. ! 995: ** ! 996: ** Each command is responsible for a few things. 1) Each has to keep ! 997: ** track of special cases that are related to the individual command and ! 998: ** the previous commands sequence, 2) each is required to call iodone when ! 999: ** command is actually finished, 3) it must use cyexecute to actually ! 1000: ** start the controller, and 4) they are required to keep the tape in ! 1001: ** a consistant state so that other commands will not be messed up. ! 1002: /* ! 1003: */ ! 1004: ! 1005: /* ! 1006: ** cyraw_read handles the read requests from the raw device (cyread). ! 1007: ** ! 1008: ** The special cases are: ! 1009: ** 1) we can not read after a write. (writting defines end of file) ! 1010: ** 2) reading past end of file returns 0 bytes; ! 1011: */ ! 1012: ! 1013: cyraw_read(request, ctlr_queue) ! 1014: register struct buf *request; ! 1015: register struct buf *ctlr_queue; ! 1016: { ! 1017: register int unit = CYUNIT(request->b_dev); ! 1018: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1019: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1020: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1021: register int addr, lock_flag, command; ! 1022: ! 1023: if((u_info->cleanup != cyno_op) || u_info->eof) { ! 1024: request->b_resid = request->b_bcount; ! 1025: request->b_error = ENXIO, request->b_flags |= B_ERROR; ! 1026: cydone(ctlr_queue); ! 1027: return; ! 1028: } ! 1029: if(request->b_bcount > c_info->bs) ! 1030: command = READ_TA, lock_flag = CW_LOCK; ! 1031: else ! 1032: command = READ_BU, lock_flag = 0; ! 1033: u_info->blkno++; ! 1034: addr = get_ioadr(request,c_info->rawbuf,c_info->map,c_info->utl); ! 1035: cyexecute(command, request->b_bcount, addr, lock_flag, unit, 10, FALSE); ! 1036: end_transfer(request, c_info->rawbuf, c_info->map, c_info->utl); ! 1037: cydone(ctlr_queue); ! 1038: } ! 1039: ! 1040: ! 1041: /* ! 1042: ** cyraw_write handles the write requests from the raw device. ! 1043: ** ! 1044: ** The special cases are: ! 1045: ** 1) we don't allow writes after end of tape is reached. ! 1046: */ ! 1047: ! 1048: cyraw_write(request, ctlr_queue) ! 1049: register struct buf *request; ! 1050: register struct buf *ctlr_queue; ! 1051: { ! 1052: register int unit = CYUNIT(request->b_dev); ! 1053: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1054: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1055: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1056: register int addr, lock_flag, command; ! 1057: ! 1058: if(u_info->eot) { ! 1059: request->b_resid = request->b_bcount; ! 1060: request->b_error = ENXIO, request->b_flags |= B_ERROR; ! 1061: longjmp(&c_info->environ); ! 1062: } ! 1063: u_info->cleanup = cywrite_2_fm; ! 1064: if(request->b_bcount > c_info->bs) ! 1065: command = WRIT_TA, lock_flag = CW_LOCK; ! 1066: else ! 1067: command = WRIT_BU, lock_flag = 0; ! 1068: u_info->blkno++; ! 1069: addr = get_ioadr(request,c_info->rawbuf,c_info->map,c_info->utl); ! 1070: cyexecute(command, request->b_bcount, addr, lock_flag, unit, 10, FALSE); ! 1071: end_transfer(request, c_info->rawbuf, c_info->map, c_info->utl); ! 1072: cydone(ctlr_queue); ! 1073: } ! 1074: ! 1075: ! 1076: /* ! 1077: ** cywrite_filemark processes the ioctl to write filemarks to tape. ! 1078: */ ! 1079: ! 1080: cywrite_filemark(request, ctlr_queue) ! 1081: register struct buf *request; ! 1082: register struct buf *ctlr_queue; ! 1083: { ! 1084: register int unit = CYUNIT(request->b_dev); ! 1085: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1086: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1087: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1088: ! 1089: if(request->b_bcount) { ! 1090: request->b_bcount--; ! 1091: if(u_info->cleanup == cywrite_1_fm) ! 1092: u_info->cleanup = cywrite_0_fm; ! 1093: if((u_info->cleanup==cywrite_2_fm)||(u_info->cleanup==cyno_op)) ! 1094: u_info->cleanup = cywrite_1_fm; ! 1095: u_info->file_number++; ! 1096: u_info->eof = TRUE; ! 1097: u_info->blkno = 0; ! 1098: cyexecute(WRIT_FM, (short)1, 0, 0, unit, 10, FALSE); ! 1099: return; ! 1100: } ! 1101: cydone(ctlr_queue); ! 1102: } ! 1103: ! 1104: ! 1105: /* ! 1106: ** cysearch_fm_forw is the ioctl to search for a filemark in the ! 1107: ** forward direction on tape. ! 1108: ** ! 1109: ** Since only one device can be active on a given controller at any ! 1110: ** given instant in time, we try to be nice and let onther devices on ! 1111: ** this controller be scheduled after we space over each record. This will ! 1112: ** at least give the apperance of overlapped operations on the controller. ! 1113: ** ! 1114: ** The special cases are: ! 1115: ** 1) if the last command was a write the we can't search. ! 1116: */ ! 1117: ! 1118: cysearch_fm_forw(request, ctlr_queue) ! 1119: register struct buf *request; ! 1120: register struct buf *ctlr_queue; ! 1121: { ! 1122: register int unit = CYUNIT(request->b_dev); ! 1123: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1124: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1125: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1126: ! 1127: if((u_info->cleanup != cyno_op) || u_info->eot) { ! 1128: request->b_resid = request->b_bcount; ! 1129: request->b_error = ENXIO, request->b_flags |= B_ERROR; ! 1130: longjmp(&c_info->environ); ! 1131: } ! 1132: if(request->b_bcount && !u_info->eot) { ! 1133: if(!u_info->eot) { ! 1134: u_info->blkno++; ! 1135: cyexecute(SPAC_FM, 1, 0, 0, unit, 5, FALSE); ! 1136: if(!(u_info->eof || u_info->eot)) ! 1137: return; ! 1138: } ! 1139: request->b_bcount--; ! 1140: u_info->eof = FALSE; ! 1141: if(!u_info->eot) { ! 1142: u_info->file_number++; ! 1143: u_info->blkno = 0; ! 1144: return; ! 1145: } ! 1146: } ! 1147: if(u_info->eot) { ! 1148: request->b_resid = request->b_bcount; ! 1149: request->b_flags |= B_ERROR, request->b_error = ENXIO; ! 1150: } ! 1151: cydone(ctlr_queue); ! 1152: } ! 1153: ! 1154: ! 1155: /* ! 1156: ** cysearch_fm_back is the ioctl to search for a filemark in the ! 1157: ** reverse direction on tape. ! 1158: ** ! 1159: ** Since only one device can be active on a given controller at any ! 1160: ** given instant in time, we try to be nice and let onther devices on ! 1161: ** this controller be scheduled after we space over each record. This will ! 1162: ** at least give the apperance of overlapped operations on the controller. ! 1163: ** ! 1164: ** The special cases are: ! 1165: ** 1) can't search past begining of tape. ! 1166: ** 2) if the lasr operation was a write data then we need to add ! 1167: ** an end of volume record before we start searching. ! 1168: */ ! 1169: ! 1170: cysearch_fm_back(request, ctlr_queue) ! 1171: register struct buf *request; ! 1172: register struct buf *ctlr_queue; ! 1173: { ! 1174: register int unit = CYUNIT(request->b_dev); ! 1175: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1176: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1177: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1178: ! 1179: if(!u_info->bot) { ! 1180: (*u_info->cleanup)(unit, MAINTAIN_POSITION); ! 1181: if(u_info->blkno == 0) ! 1182: request->b_bcount++; ! 1183: u_info->blkno = 0xffffffff; ! 1184: if(request->b_bcount && !u_info->bot) { ! 1185: cyexecute(SPAC_FM, 1, 0, CW_REV, unit, 6, FALSE); ! 1186: if(u_info->eof) { ! 1187: u_info->eof = FALSE; ! 1188: u_info->file_number--; ! 1189: request->b_bcount--; ! 1190: } ! 1191: return; ! 1192: } ! 1193: if(u_info->bot) { ! 1194: u_info->file_number = 0; ! 1195: if(request->b_bcount) { ! 1196: request->b_resid = request->b_bcount; ! 1197: request->b_error = ENXIO; ! 1198: request->b_flags |= B_ERROR; ! 1199: } ! 1200: } ! 1201: else { ! 1202: request->b_cmd = (struct buf *)DO_SFMF; ! 1203: request->b_bcount = 1; ! 1204: return; ! 1205: } ! 1206: } ! 1207: u_info->blkno = 0; ! 1208: u_info->eof = FALSE; ! 1209: cydone(ctlr_queue); ! 1210: } ! 1211: ! 1212: ! 1213: /* ! 1214: ** cy_space_forw is used to search forward a given number of records on ! 1215: ** tape. ! 1216: ** ! 1217: ** Since only one device can be active on a given controller at any ! 1218: ** given instant in time, we try to be nice and let onther devices on ! 1219: ** this controller be scheduled after we space over each record. This will ! 1220: ** at least give the apperance of overlapped operations on the controller. ! 1221: ** ! 1222: ** The special cases are: ! 1223: ** 1) we can't space over a filemark. ! 1224: ** 2) if the last command was a write data or filemark we can't space forward. ! 1225: */ ! 1226: ! 1227: cy_space_forw(request, ctlr_queue) ! 1228: register struct buf *request; ! 1229: register struct buf *ctlr_queue; ! 1230: { ! 1231: register int unit = CYUNIT(request->b_dev); ! 1232: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1233: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1234: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1235: ! 1236: if((u_info->cleanup != cyno_op) || u_info->eof) { ! 1237: request->b_resid = request->b_bcount; ! 1238: request->b_error = ENXIO, request->b_flags |= B_ERROR; ! 1239: longjmp(&c_info->environ); ! 1240: } ! 1241: if(request->b_bcount) { ! 1242: u_info->blkno++; ! 1243: cyexecute(SPAC_FM, 1, 0, 0, unit, 10, FALSE); ! 1244: if(!u_info->eof && request->b_bcount) { ! 1245: request->b_bcount--; ! 1246: return; ! 1247: } ! 1248: } ! 1249: if(u_info->eof) { ! 1250: request->b_resid = request->b_bcount; ! 1251: request->b_error = ENXIO, request->b_flags |= B_ERROR; ! 1252: } ! 1253: cydone(ctlr_queue); ! 1254: } ! 1255: ! 1256: ! 1257: /* ! 1258: ** Cy_space_back spaces backward a given number of records. ! 1259: ** ! 1260: ** Since only one device can be active on a given controller at any ! 1261: ** given instant in time, we try to be nice and let onther devices on ! 1262: ** this controller be scheduled after we space over each record. This will ! 1263: ** at least give the apperance of overlapped operations on the controller. ! 1264: ** ! 1265: ** The special cases are: ! 1266: ** 1) we can't space over a filemark. ! 1267: ** 2) we can't space past the beginning of tape. ! 1268: ** 3) if the last operation was a write data then we need to add ! 1269: ** an end of volume record before we start searching. ! 1270: */ ! 1271: ! 1272: cy_space_back(request, ctlr_queue) ! 1273: register struct buf *request; ! 1274: register struct buf *ctlr_queue; ! 1275: { ! 1276: register int unit = CYUNIT(request->b_dev); ! 1277: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1278: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1279: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1280: ! 1281: if(!u_info->bot) { ! 1282: (*u_info->cleanup)(unit, MAINTAIN_POSITION); ! 1283: if(request->b_bcount+1 && !u_info->bot && !u_info->eof) { ! 1284: request->b_bcount--; ! 1285: u_info->blkno--; ! 1286: cyexecute(SPACE, 1, 0, CW_REV, unit, 15, FALSE); ! 1287: return; ! 1288: } ! 1289: if(!u_info->bot) { ! 1290: request->b_bcount = 1; ! 1291: cy_space_forw(request); ! 1292: } ! 1293: u_info->eof = FALSE; ! 1294: } ! 1295: cydone(ctlr_queue); ! 1296: } ! 1297: ! 1298: ! 1299: /* ! 1300: ** cyrewind_tape_ta does a waiting rewind to of the tape. ! 1301: ** ! 1302: ** An overlapped rewind is issued and then we change the command type to ! 1303: ** a wait for ready ioctl. Wait for ready contains the logic to poll ! 1304: ** without blocking anything in the system, until the drive becomes ready or ! 1305: ** drops off line whichever comes first. ! 1306: */ ! 1307: ! 1308: cyrewind_tape_ta(request, ctlr_queue) ! 1309: register struct buf *request; ! 1310: register struct buf *ctlr_queue; ! 1311: { ! 1312: cyrewind_tape(request, REWD_OV); ! 1313: request->b_cmd = (struct buf *)DO_WAIT; ! 1314: } ! 1315: ! 1316: ! 1317: /* ! 1318: ** cyrewind_tape_unl does an overlapped rewind and then unloads the ! 1319: ** tape after the tape completes the rewind. This feature is handled by ! 1320: ** the individual tape drive and in some cases can not unload a tape. In ! 1321: ** this case it acts exactly like an overlapped rewind. ! 1322: */ ! 1323: ! 1324: cyrewind_tape_unl(request, ctlr_queue) ! 1325: register struct buf *request; ! 1326: register struct buf *ctlr_queue; ! 1327: { ! 1328: cyrewind_tape(request, OFF_UNL); ! 1329: cydone(ctlr_queue); ! 1330: } ! 1331: ! 1332: ! 1333: /* ! 1334: ** cyrewind_tape_ov is used to do overlapped rewinds on the system. ! 1335: ** Close is a classic example of where an overlapped rewind is needed. ! 1336: ** It would be stupid in that case to force the user to wait around ! 1337: ** (up to 5 minutes) until the tape has finished rewind. ! 1338: */ ! 1339: ! 1340: cyrewind_tape_ov(request, ctlr_queue) ! 1341: register struct buf *request; ! 1342: register struct buf *ctlr_queue; ! 1343: { ! 1344: cyrewind_tape(request, REWD_OV); ! 1345: cydone(ctlr_queue); ! 1346: } ! 1347: ! 1348: /* ! 1349: ** cyrewind tape is the common code for all rewind commands. ! 1350: ** ! 1351: ** The special cases are: ! 1352: ** 3) if the last operation was a write data then we need to add ! 1353: ** an end of volume record before we start searching. ! 1354: */ ! 1355: ! 1356: cyrewind_tape(request, command) ! 1357: register struct buf *request; ! 1358: long command; ! 1359: { ! 1360: register int unit = CYUNIT(request->b_dev); ! 1361: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1362: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1363: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1364: register int time = (command == REWD_OV) ? 10 : 10*60; ! 1365: ! 1366: (*u_info->cleanup)(unit, DONT_MAINTAIN_POSITION); ! 1367: u_info->blkno = 0; ! 1368: u_info->eof = FALSE; ! 1369: u_info->bot = TRUE; ! 1370: u_info->eot = FALSE; ! 1371: u_info->file_number = 0; ! 1372: request->b_resid = 0; ! 1373: u_info->cleanup = cyno_op; ! 1374: cyexecute(command, 0, 0, 0, unit, time, FALSE); ! 1375: } ! 1376: ! 1377: ! 1378: /* ! 1379: ** Cywait_until_ready is used to wait for rewinds to complete. ! 1380: ** We check the status and if the tape is still rewinding we re-enter ourself ! 1381: ** on the activity queue to give other requests a chance to execute before we ! 1382: ** check the status again. One other thing is that we only want to check ! 1383: ** the status every five seconds. so we set a timer for five seconds and ! 1384: ** check the time left every time we enter this routine. If there is still ! 1385: ** time left then we simply reinsert ourself on the queue again and wait ! 1386: ** until next time .. ! 1387: */ ! 1388: ! 1389: ! 1390: cywait_until_ready(request, ctlr_queue) ! 1391: register struct buf *request; ! 1392: register struct buf *ctlr_queue; ! 1393: { ! 1394: extern int cywait_timeout(); ! 1395: register int unit = CYUNIT(request->b_dev); ! 1396: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1397: register unit_tab *u_info = &unit_info[unit]; ! 1398: ! 1399: cyexecute(DRIVE_S, 0, 0, 0, unit, 10, FALSE); ! 1400: if((!(u_info->last_status & CS_OL)) || (u_info->last_status & CS_RDY)) { ! 1401: cydone(ctlr_queue); ! 1402: return; ! 1403: } ! 1404: ctlr_queue->b_forw->b_active |= SLEEPING; ! 1405: timeout(cywait_timeout, ctlr_queue->b_forw, 2*60); ! 1406: } ! 1407: ! 1408: ! 1409: /* ! 1410: ** cywait_timeout resets the timing flag for nice_wait after 3 seconds ! 1411: ** is up. This makes this drive eligible for scheduling again. ! 1412: */ ! 1413: ! 1414: cywait_timeout(unit_queue) ! 1415: struct buf *unit_queue; ! 1416: { ! 1417: unit_queue->b_active &= ~SLEEPING; ! 1418: } ! 1419: ! 1420: ! 1421: /* ! 1422: ** cydrive_status is used to process the status ioctl request. ! 1423: ** it depends entirly on the interupt routines to load the last_XXX ! 1424: ** registers in unit_info[]. ! 1425: */ ! 1426: ! 1427: cydrive_status(request, ctlr_queue) ! 1428: register struct buf *request; ! 1429: register struct buf *ctlr_queue; ! 1430: { ! 1431: register int unit = CYUNIT(request->b_dev); ! 1432: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1433: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1434: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1435: ! 1436: cyexecute(DRIVE_S, 0, 0, 0, unit, 10, FALSE); ! 1437: cydone(ctlr_queue); ! 1438: } ! 1439: ! 1440: ! 1441: /* ! 1442: ** cybuf_read handles the read requests from the block device. ! 1443: ** ! 1444: ** The special cases are: ! 1445: ** 1) we can not read after a write. (writting defines end of file) ! 1446: ** 2) reading past end of file returns 0 bytes; ! 1447: ** 3) if we are mispositioned we have to seek to the correct block. ! 1448: ** 4) we can hit end of tape while seeking. ! 1449: ** 5) we want to be nice to other processes while seeking so we ! 1450: ** break the request up into smaller requests. ! 1451: ** 6) returns error if the block was larger than requested. ! 1452: */ ! 1453: ! 1454: cybuf_read(request, ctlr_queue) ! 1455: register struct buf *request; ! 1456: register struct buf *ctlr_queue; ! 1457: { ! 1458: register int unit = CYUNIT(request->b_dev); ! 1459: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1460: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1461: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1462: register int addr, command, bus_lock; ! 1463: ! 1464: cydebug = 1; ! 1465: if(cyseek(request, ctlr_queue)) { ! 1466: if(u_info->cleanup != cyno_op) { ! 1467: clrbuf(request); ! 1468: longjmp(&c_info->environ); ! 1469: } ! 1470: if(request->b_bcount > c_info->bs) ! 1471: command = READ_TA, bus_lock = CW_LOCK; ! 1472: else ! 1473: command = READ_BU, bus_lock = 0; ! 1474: u_info->blkno++; ! 1475: addr=get_ioadr(request,c_info->rawbuf,c_info->map,c_info->utl); ! 1476: cyexecute(command,request->b_bcount,addr,bus_lock,unit,8,FALSE); ! 1477: end_transfer(request, c_info->rawbuf, c_info->map, c_info->utl); ! 1478: cydone(ctlr_queue); ! 1479: } ! 1480: } ! 1481: ! 1482: ! 1483: /* ! 1484: ** cybuf_write handles the write requests from the block device. ! 1485: ** ! 1486: ** The special cases are: ! 1487: ** 1) if we are mispositioned we have to seek to the correct block. ! 1488: ** 2) we can hit end of tape while seeking. ! 1489: ** 3) we want to be nice to other processes while seeking so we ! 1490: ** break the request up into smaller requests. ! 1491: ** 4) we don't allow writes after end of tape is reached. ! 1492: */ ! 1493: ! 1494: cybuf_write(request, ctlr_queue) ! 1495: register struct buf *request; ! 1496: register struct buf *ctlr_queue; ! 1497: { ! 1498: register int unit = CYUNIT(request->b_dev); ! 1499: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1500: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1501: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1502: register int addr, command, bus_lock; ! 1503: ! 1504: if(u_info->eot && (request->b_blkno >= u_info->blkno)) { ! 1505: request->b_error = ENXIO, request->b_flags |= B_ERROR; ! 1506: request->b_resid = request->b_bcount; ! 1507: longjmp(&c_info->environ); ! 1508: } ! 1509: if(cyseek(request, ctlr_queue)) { ! 1510: u_info->cleanup = cywrite_2_fm; ! 1511: u_info->blkno++; ! 1512: if(request->b_bcount > c_info->bs) ! 1513: command = WRIT_TA, bus_lock |= CW_LOCK; ! 1514: else ! 1515: command = WRIT_BU, bus_lock = 0; ! 1516: addr=get_ioadr(request,c_info->rawbuf,c_info->map,c_info->utl); ! 1517: load_mbus_addr((char *)addr, &c_info->tpb.data_ptr); ! 1518: cyexecute(command,request->b_bcount,addr,bus_lock,unit,5,FALSE); ! 1519: end_transfer(request, c_info->rawbuf, c_info->map, c_info->utl); ! 1520: cydone(ctlr_queue); ! 1521: } ! 1522: } ! 1523: ! 1524: ! 1525: /* ! 1526: ** cyseek is used by the block device to position the tape correctly ! 1527: ** before each read or write request. ! 1528: ** ! 1529: ** The special cases are: ! 1530: ** 1) we can hit end of tape while seeking. ! 1531: ** 2) we want to be nice to other processes while seeking so we ! 1532: ** break the request up into smaller requests. ! 1533: */ ! 1534: ! 1535: cyseek(request, ctlr_queue) ! 1536: register struct buf *request; ! 1537: register struct buf *ctlr_queue; ! 1538: { ! 1539: register int unit = CYUNIT(request->b_dev); ! 1540: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1541: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1542: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1543: ! 1544: if(request->b_blkno < u_info->blkno) { ! 1545: register int count; ! 1546: ! 1547: (*u_info->cleanup)(unit, MAINTAIN_POSITION); ! 1548: count = ((request->b_blkno+1) == u_info->blkno) ? 2 : 1; ! 1549: u_info->blkno -= count; ! 1550: cyexecute(SPAC_FM, 1, 0, CW_REV, unit, 10, FALSE); ! 1551: if(!u_info->eof) ! 1552: return FALSE; ! 1553: u_info->eof = FALSE; ! 1554: request->b_blkno = u_info->blkno + 1; ! 1555: } ! 1556: if(request->b_blkno > u_info->blkno) { ! 1557: if((u_info->cleanup != cyno_op) || u_info->eof || u_info->eot) { ! 1558: request->b_resid = request->b_bcount; ! 1559: request->b_error = ENXIO, request->b_flags |= B_ERROR; ! 1560: longjmp(&c_info->environ); ! 1561: } ! 1562: u_info->blkno++; ! 1563: cyexecute(SPAC_FM, 1, 0, 0, unit, 10, FALSE); ! 1564: return FALSE; ! 1565: } ! 1566: return TRUE; ! 1567: } ! 1568: ! 1569: ! 1570: /* ! 1571: */ ! 1572: ! 1573: cywrite_eov(request, ctlr_queue) ! 1574: register struct buf *request; ! 1575: register struct buf *ctlr_queue; ! 1576: { ! 1577: extern int cyno_op(); ! 1578: register int unit = CYUNIT(request->b_dev); ! 1579: register unit_tab *u_info = &unit_info[CYUNIT(unit)]; ! 1580: ! 1581: if(u_info->cleanup != cyno_op) { ! 1582: (*u_info->cleanup)(unit, DONT_MAINTAIN_POSITION); ! 1583: cyexecute(SPACE, 2, 0, CW_REV, unit, 10, FALSE); ! 1584: cyexecute(SPACE, 1, 0, 0, unit, 10, FALSE); ! 1585: unit_info[unit].cleanup = cyno_op; ! 1586: u_info->blkno = 0; ! 1587: } ! 1588: cydone(ctlr_queue); ! 1589: } ! 1590: ! 1591: ! 1592: /* ! 1593: ** Do nothing ! 1594: */ ! 1595: ! 1596: cyno_op(unit, action) ! 1597: int unit, action; ! 1598: { ! 1599: } ! 1600: ! 1601: ! 1602: /* ! 1603: ** Write 0 file marks to tape ! 1604: */ ! 1605: ! 1606: cywrite_0_fm(unit, action) ! 1607: int unit, action; ! 1608: { ! 1609: unit_info[unit].cleanup = cyno_op; ! 1610: } ! 1611: ! 1612: ! 1613: /* ! 1614: ** Write 1 file mark to tape ! 1615: */ ! 1616: ! 1617: cywrite_1_fm(unit, action) ! 1618: int unit, action; ! 1619: { ! 1620: cyexecute(WRIT_FM, 1, 0, 0, unit, 5, FALSE); ! 1621: if(action == MAINTAIN_POSITION) { ! 1622: cyexecute(SPACE, 2, 0, CW_REV, unit, 10, FALSE); ! 1623: cyexecute(SPACE, 1, 0, 0, unit, 10, FALSE); ! 1624: } ! 1625: unit_info[unit].cleanup = cyno_op; ! 1626: } ! 1627: ! 1628: ! 1629: /* ! 1630: ** Write 2 file marks to tape ! 1631: */ ! 1632: ! 1633: cywrite_2_fm(unit, action) ! 1634: int unit, action; ! 1635: { ! 1636: cyexecute(WRIT_FM, 1, 0, 0, unit, 5, FALSE); ! 1637: cyexecute(WRIT_FM, 1, 0, 0, unit, 5, FALSE); ! 1638: if(action == MAINTAIN_POSITION) { ! 1639: cyexecute(SPACE, 3, 0, CW_REV, unit, 10, FALSE); ! 1640: cyexecute(SPACE, 1, 0, 0, unit, 2, FALSE); ! 1641: } ! 1642: unit_info[unit].cleanup = cyno_op; ! 1643: } ! 1644: ! 1645: ! 1646: /* ! 1647: ** Cyexecute is used to start all commands to the controller. We ! 1648: ** do all common code here before starting. ! 1649: */ ! 1650: ! 1651: cyexecute(command, count, addr, control_flags, unit, time, interupt_routine) ! 1652: register int command; ! 1653: int count, addr, control_flags, unit, time, interupt_routine; ! 1654: { ! 1655: extern int cytimeout(); ! 1656: extern int cy_normal_path(); ! 1657: register int priority; ! 1658: register int ctlr = cydinfo[unit]->ui_ctlr; ! 1659: register unit_tab *u_info = &unit_info[unit]; ! 1660: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1661: register struct buf *request = u_info->u_queue.av_forw; ! 1662: ! 1663: c_info->tpb.cmd = command; ! 1664: c_info->tpb.control = u_info->control_proto | control_flags; ! 1665: c_info->tpb.status = c_info->tpb.count = (short)0; ! 1666: load_mbus_addr((char *)addr, &c_info->tpb.data_ptr); ! 1667: switch(command) { ! 1668: case READ_BU : ! 1669: case READ_TA : ! 1670: case WRIT_BU : ! 1671: case WRIT_TA : ! 1672: c_info->tpb.size = MULTIBUS_SHORT((short)count); ! 1673: c_info->tpb.rec_over = (short)0; ! 1674: break; ! 1675: default: ! 1676: c_info->tpb.size = (short)0; ! 1677: c_info->tpb.rec_over = MULTIBUS_SHORT((short)count); ! 1678: break; ! 1679: } ! 1680: load_mbus_addr((char *)0, c_info->tpb.link_ptr); ! 1681: if(!interupt_routine) ! 1682: c_info->last = c_info->tpb; ! 1683: /* ! 1684: gag! but it the last possible moment to wait ! 1685: for this controller to get out of it's own way..... ! 1686: */ ! 1687: uncache(&c_info->ccb.gate); ! 1688: while(c_info->ccb.gate == GATE_CLOSED) ! 1689: uncache(&c_info->ccb.gate); ! 1690: load_mbus_addr(&c_info->tpb, c_info->ccb.tpb_ptr); ! 1691: c_info->ccb.ccw = NORMAL_INTERUPT; ! 1692: c_info->ccb.gate = GATE_CLOSED; ! 1693: if(!interupt_routine) ! 1694: c_info->interupt_path = cy_normal_path; ! 1695: timeout(cytimeout, ctlr, time*60); ! 1696: priority = spl3(); ! 1697: CY_ATTENTION(cyminfo[ctlr]->um_addr); ! 1698: if(!interupt_routine) { ! 1699: sleep(c_info, PRIBIO+3); ! 1700: splx(priority); ! 1701: if(request->b_flags & B_ERROR) { ! 1702: if((command == READ_BU) || (command == READ_TA) || ! 1703: (command == WRIT_BU) || (command == WRIT_TA)) ! 1704: end_transfer(request, c_info->rawbuf, ! 1705: c_info->map,c_info->utl); ! 1706: longjmp(&c_info->environ); ! 1707: } ! 1708: return; ! 1709: } ! 1710: splx(priority); ! 1711: } ! 1712: ! 1713: ! 1714: /* ! 1715: ** cytimeout is the interupt timeout routine. We assume that a ! 1716: ** particular command has gone astray, so we completely reset the controller, ! 1717: ** and call the interupt routine to help us clean up. Before the interupt ! 1718: ** routine is called we jam a controller timeout value in the status register ! 1719: ** to fake out the calling routines. ! 1720: */ ! 1721: ! 1722: cytimeout(ctlr) ! 1723: register int ctlr; ! 1724: { ! 1725: register int priority = spl3(); ! 1726: register char *ctlr_vaddr = cyminfo[ctlr]->um_addr; ! 1727: register int tmp_stat; ! 1728: ! 1729: uncache(&ctlr_info[ctlr].tpb.status); ! 1730: tmp_stat = ctlr_info[ctlr].tpb.status; ! 1731: CY_RESET(ctlr_vaddr); ! 1732: cy_init_controller(ctlr_vaddr, ctlr, 0); ! 1733: splx(priority); ! 1734: ctlr_info[ctlr].tpb = ctlr_info[ctlr].last; ! 1735: ctlr_info[ctlr].tpb.status = (tmp_stat & ~CS_ERm) | CS_OL | ER_TIMOUT; ! 1736: cyintr(ctlr); ! 1737: } ! 1738: ! 1739: /* ! 1740: ** Cyintr is the interupt routine for the Tapemaster controller. ! 1741: ** ! 1742: ** Due to controller problems, the first thing we have to do is turn ! 1743: ** off the Tapemaster interupting mechanism. If we don't we will be flooded ! 1744: ** with bogus interupts and the system will spend all it's time processing ! 1745: ** them. To Turn the interupts off we issue a NOOP command with the 'turn ! 1746: ** off interupts' code in the ccb. ! 1747: ** ! 1748: ** take note that since this command TURNS OFF the interupts it ! 1749: ** itself CANNOT interupt... This means that polling must be done ! 1750: ** at sometime to make sure that tis command is completed. The polling ! 1751: ** is done before the next command is issued to reduce polling (halting ! 1752: ** UNIX) time. ! 1753: ** ! 1754: ** After we turn off interupts we uncache all the values in the tpb ! 1755: ** and call the correct processing routine. This routine can be for normal ! 1756: ** interupts or for interupts generated during a retry operation. ! 1757: */ ! 1758: ! 1759: cyintr(ctlr) ! 1760: register int ctlr; ! 1761: { ! 1762: extern int cytimeout(); ! 1763: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1764: ! 1765: untimeout(cytimeout, ctlr); ! 1766: /* turn off interupts for the stupid controller */ ! 1767: c_info->ccb.ccw = CLEAR_INTERUPT; ! 1768: c_info->noop.cmd = NO_OP; ! 1769: c_info->noop.control = (short)0; ! 1770: load_mbus_addr(&c_info->noop, c_info->ccb.tpb_ptr); ! 1771: c_info->ccb.gate = GATE_CLOSED; ! 1772: CY_ATTENTION(cyminfo[ctlr]->um_addr); ! 1773: uncache_tpb(c_info); ! 1774: (*c_info->interupt_path)(ctlr); ! 1775: } ! 1776: ! 1777: ! 1778: /* ! 1779: ** This is the portion of the interupt routine that processes all ! 1780: ** normal cases i.e. non retry cases. We check the operations status ! 1781: ** if it is retryable we set the interupt path to the retry routines and ! 1782: ** start the backward spaceing. when the spacing is done the retry logic ! 1783: ** will be called and this routine will be skipped entirely. ! 1784: ** ! 1785: ** If the command is ok or not retryable we set the status accordingly ! 1786: ** and wakeup cyexecute to continue processing. ! 1787: */ ! 1788: ! 1789: cy_normal_path(ctlr) ! 1790: register int ctlr; ! 1791: { ! 1792: extern int cy_retry_path(); ! 1793: extern int cy_extended_gap_path(); ! 1794: register int error; ! 1795: register struct buf *ctlr_queue = &cyminfo[ctlr]->um_tab; ! 1796: register struct buf *unit_queue = ctlr_queue->b_forw; ! 1797: register struct buf *request = unit_queue->av_forw; ! 1798: register int unit = CYUNIT(request->b_dev); ! 1799: register unit_tab *u_info = &unit_info[unit]; ! 1800: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1801: ! 1802: if (error = cydecode_error(unit, c_info->tpb.status)) { ! 1803: if(error != FATAL) { ! 1804: if (error == RETRY) ! 1805: c_info->interupt_path = cy_retry_path; ! 1806: else ! 1807: c_info->interupt_path = cy_extended_gap_path; ! 1808: cyexecute(SPACE, 2, 0, CW_REV, unit, 5, TRUE); ! 1809: return; ! 1810: } ! 1811: } ! 1812: request->b_resid=request->b_bcount-MULTIBUS_SHORT(c_info->tpb.count); ! 1813: u_info->error_count = 0; ! 1814: u_info->last_resid = request->b_resid; ! 1815: u_info->last_status = c_info->tpb.status; ! 1816: u_info->last_control = c_info->tpb.control; ! 1817: if (error == FATAL) ! 1818: request->b_flags |= B_ERROR, request->b_error = EIO; ! 1819: wakeup(c_info); ! 1820: } ! 1821: ! 1822: ! 1823: /* ! 1824: ** Cy_retry_path finishes up the retry sequence for the tape. ! 1825: ** If we were going in the reverse direction it means that we have to ! 1826: ** space forward to correctly position ourselfs in back of the tape gap ! 1827: ** instead of in front of it. If we were going forward it means that ! 1828: ** we are positioned correctly and we can actually restart the instruction ! 1829: ** that failed before. ! 1830: */ ! 1831: ! 1832: cy_retry_path(ctlr) ! 1833: register int ctlr; ! 1834: { ! 1835: extern int cy_do_again_path(); ! 1836: register struct buf *ctlr_queue = &cyminfo[ctlr]->um_tab; ! 1837: register struct buf *unit_queue = ctlr_queue->b_forw; ! 1838: register struct buf *request = unit_queue->av_forw; ! 1839: register int unit = CYUNIT(request->b_dev); ! 1840: register unit_tab *u_info = &unit_info[unit]; ! 1841: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1842: ! 1843: if(!(c_info->tpb.status & CS_OL)) { ! 1844: c_info->interupt_path = cy_normal_path; ! 1845: cy_normal_path(ctlr); ! 1846: return; ! 1847: } ! 1848: if(c_info->tpb.control & CW_REV) { ! 1849: if(!(c_info->tpb.status & CS_LP)) { ! 1850: c_info->interupt_path = cy_do_again_path; ! 1851: cyexecute(SPACE, 1, 0, 0, unit, 5, TRUE); ! 1852: return; ! 1853: } ! 1854: cy_do_again_path(ctlr); ! 1855: } ! 1856: } ! 1857: ! 1858: ! 1859: /* ! 1860: ** ! 1861: */ ! 1862: ! 1863: cy_extended_gap_path(ctlr) ! 1864: register int ctlr; ! 1865: { ! 1866: extern int cy_do_again_path(); ! 1867: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1868: register struct buf *ctlr_queue = &cyminfo[ctlr]->um_tab; ! 1869: register struct buf *unit_queue = ctlr_queue->b_forw; ! 1870: register struct buf *request = unit_queue->av_forw; ! 1871: register int unit = CYUNIT(request->b_dev); ! 1872: ! 1873: if(!(c_info->tpb.status & CS_OL)) { ! 1874: c_info->interupt_path = cy_normal_path; ! 1875: cy_normal_path(ctlr); ! 1876: return; ! 1877: } ! 1878: if(c_info->tpb.control & CW_REV) { ! 1879: if(!(c_info->tpb.status & CS_LP)) { ! 1880: cyexecute(SPACE, 1, 0, 0, unit, 5, TRUE); ! 1881: return; ! 1882: } ! 1883: } ! 1884: c_info->interupt_path = cy_do_again_path; ! 1885: cyexecute(ERASE_F, unit_info[unit].error_count, 0, 0, unit, 5, TRUE); ! 1886: } ! 1887: ! 1888: ! 1889: /* ! 1890: ** ! 1891: */ ! 1892: ! 1893: cy_do_again_path(ctlr) ! 1894: register int ctlr; ! 1895: { ! 1896: extern int cy_normal_path(); ! 1897: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 1898: ! 1899: if(!(c_info->tpb.status & CS_OL)) { ! 1900: c_info->interupt_path = cy_normal_path; ! 1901: cy_normal_path(ctlr); ! 1902: return; ! 1903: } ! 1904: c_info->tpb = c_info->last; ! 1905: uncache(&c_info->ccb.gate); ! 1906: while(c_info->ccb.gate == GATE_CLOSED) ! 1907: uncache(&c_info->ccb.gate); ! 1908: load_mbus_addr(&c_info->tpb, c_info->ccb.tpb_ptr); ! 1909: c_info->ccb.ccw = NORMAL_INTERUPT; ! 1910: c_info->ccb.gate = GATE_CLOSED; ! 1911: c_info->interupt_path = cy_normal_path; ! 1912: CY_ATTENTION(cyminfo[ctlr]->um_addr); ! 1913: } ! 1914: ! 1915: ! 1916: /* ! 1917: ** for each longword in the tpb we call uncache to purge it from ! 1918: ** the cache. This is done so that we can correctly access tpb data ! 1919: ** that was placed there by the controller. ! 1920: */ ! 1921: ! 1922: uncache_tpb(c_info) ! 1923: ctlr_tab *c_info; ! 1924: { ! 1925: register long *ptr = (long *)&c_info->tpb; ! 1926: register int i; ! 1927: ! 1928: for(i=0; i<((sizeof(fmt_tpb)+sizeof(long)-1)/sizeof(long)); i++) ! 1929: uncache(ptr++); ! 1930: } ! 1931: ! 1932: ! 1933: /* ! 1934: ** Cyprint_error is the common printing routine for all messages ! 1935: ** that need to print the tape status along with it. This is so we ! 1936: ** we can save space, have consistant messages, and we can send the messages ! 1937: ** to the correct places. ! 1938: */ ! 1939: ! 1940: cyprint_err(message, unit, status) ! 1941: register char *message; ! 1942: register int unit, status; ! 1943: { ! 1944: status &= 0xffff; ! 1945: printf("cy%d: %s! Status = %x\n", unit, message, status); ! 1946: } ! 1947: ! 1948: /* ! 1949: ** Decode the error to determine whether the previous command was ! 1950: ** ok, retryable, or fatal and return the value. If it was a hardware ! 1951: ** problem we print the message to the console, otherwise we print it ! 1952: ** to the user's terminal later when execute returns. ! 1953: */ ! 1954: ! 1955: cydecode_error(unit, status) ! 1956: register int unit, status; ! 1957: { ! 1958: register unit_tab *u_info = &unit_info[unit]; ! 1959: register ctlr_tab *c_info = &ctlr_info[cydinfo[unit]->ui_ctlr]; ! 1960: int ctlr = cydinfo[unit]->ui_ctlr; ! 1961: ! 1962: if(!(status & CS_OL) && (c_info->tpb.cmd != OFF_UNL)) { ! 1963: u_info->message = "Drive is not on-line"; ! 1964: cyprint_err(u_info->message, unit, status); ! 1965: return FATAL; ! 1966: } ! 1967: u_info->bot = ((status & CS_LP) != 0); ! 1968: u_info->eof = ((status & CS_FM) != 0); ! 1969: switch(status & CS_ERm) { ! 1970: case ER_EOT: ! 1971: if(c_info->tpb.control & CW_REV) { ! 1972: u_info->bot = TRUE; ! 1973: u_info->eot = FALSE; ! 1974: } ! 1975: else if(!u_info->eot){ ! 1976: u_info->message = "End of tape"; ! 1977: u_info->bot = FALSE; ! 1978: u_info->eot = TRUE; ! 1979: } ! 1980: case 0 : ! 1981: case ER_FM: ! 1982: case ER_NOSTRM: ! 1983: return NOERROR; ! 1984: case ER_TIMOUT: ! 1985: case ER_TIMOUT1: ! 1986: case ER_TIMOUT2: ! 1987: case ER_TIMOUT3: ! 1988: case ER_TIMOUT4: ! 1989: u_info->message = "Drive timed out during transfer"; ! 1990: cyprint_err(u_info->message, unit, status); ! 1991: return FATAL; ! 1992: case ER_NEX: ! 1993: u_info->message = ! 1994: "Controller referenced non-existant system memory"; ! 1995: cyprint_err(u_info->message, unit, status); ! 1996: return FATAL; ! 1997: case ER_DIAG: ! 1998: case ER_JUMPER: ! 1999: u_info->message = "Controller diagnostics failed"; ! 2000: cyprint_err(u_info->message, unit, status); ! 2001: return FATAL; ! 2002: case ER_STROBE: ! 2003: if (c_info->tpb.cmd == READ_BU) { ! 2004: c_info->last.cmd = READ_TA; ! 2005: return RETRY; ! 2006: } ! 2007: if(c_info->tpb.cmd == READ_TA) ! 2008: return NOERROR; ! 2009: u_info->message = "Unsatisfactory media found"; ! 2010: return FATAL; ! 2011: case ER_FIFO: ! 2012: case ER_NOTRDY: ! 2013: u_info->error_count = 1; ! 2014: return RETRY; ! 2015: case ER_PROT: ! 2016: u_info->message = "Tape is write protected"; ! 2017: return FATAL; ! 2018: case ER_CHKSUM: ! 2019: u_info->message = "Checksum error in controller proms"; ! 2020: cyprint_err(u_info->message, unit, status); ! 2021: return FATAL; ! 2022: case ER_HARD: ! 2023: u_info->error_count++; ! 2024: if((c_info->tpb.cmd == WRIT_TA) || ! 2025: (c_info->tpb.cmd == WRIT_BU) || ! 2026: (c_info->tpb.cmd == WRIT_FM)) { ! 2027: u_info->bad_count++; ! 2028: return EXTEND; ! 2029: } ! 2030: u_info->message = "Unrecoverable media error during read"; ! 2031: return FATAL; ! 2032: case ER_PARITY: ! 2033: if(++u_info->error_count < 8) ! 2034: return RETRY; ! 2035: u_info->message = "Unrecoverable tape parity error"; ! 2036: return FATAL; ! 2037: case ER_BLANK: ! 2038: u_info->message="Blank tape found (data expected)"; ! 2039: return FATAL; ! 2040: case ER_HDWERR: ! 2041: default: ! 2042: u_info->message = "Unrecoverble hardware error"; ! 2043: cyprint_err(u_info->message, unit, status); ! 2044: return FATAL; ! 2045: } ! 2046: } ! 2047: ! 2048: ! 2049: /* ! 2050: ** Raw read interface to unix. Since all the checking is done at a ! 2051: ** lower level we don't check anything here and we simply return the results. ! 2052: */ ! 2053: ! 2054: cyread(dev, uio) ! 2055: register dev_t dev; ! 2056: register struct uio *uio; ! 2057: { ! 2058: register int unit = CYUNIT(dev); ! 2059: register unit_tab *u_info = &unit_info[unit]; ! 2060: ! 2061: return physio(cystrategy, &u_info->rawbp, dev, B_READ, cyminsize, uio); ! 2062: } ! 2063: ! 2064: ! 2065: /* ! 2066: ** Raw write interface to unix. Since all the checking is done at a ! 2067: ** lower level we don't check anything here and we simply return the results. ! 2068: */ ! 2069: ! 2070: cywrite(dev, uio) ! 2071: register dev_t dev; ! 2072: register struct uio *uio; ! 2073: { ! 2074: register int unit = CYUNIT(dev); ! 2075: register unit_tab *u_info = &unit_info[unit]; ! 2076: ! 2077: return physio(cystrategy,&u_info->rawbp, dev, B_WRITE, cyminsize, uio); ! 2078: } ! 2079: ! 2080: /* ! 2081: ** Cyioctl is called by UNIX every time an ioctl call is made by a user ! 2082: ** program. We don't really do much here except call cycmd to process the ! 2083: ** ioctl command. We don't decode the ioctl type here because our internal ! 2084: ** jump table accessed by start is ordered by the ioctl number passes here. ! 2085: ** ! 2086: ** The only special processing is in the status command. This is because ! 2087: ** we actually return various data to the user's program with only that ! 2088: ** command. ! 2089: */ ! 2090: ! 2091: cyioctl(dev, command, data, flag) ! 2092: register dev_t dev; ! 2093: register int command; ! 2094: register struct mtop *data; ! 2095: register int flag; ! 2096: { ! 2097: if(command == MTIOCTOP) ! 2098: if((unsigned)(data->mt_op <= DO_WAIT)) ! 2099: return cycmd(dev, data->mt_op, data->mt_count); ! 2100: else ! 2101: return EIO; ! 2102: else if(command == MTIOCGET) { ! 2103: register unit_tab *u_info = &unit_info[CYUNIT(dev)]; ! 2104: ! 2105: ((struct mtget *)data)->mt_type = MT_ISCY; ! 2106: ((struct mtget *)data)->mt_dsreg = u_info->last_control; ! 2107: ((struct mtget *)data)->mt_erreg = u_info->last_status; ! 2108: ((struct mtget *)data)->mt_resid = u_info->last_resid; ! 2109: ((struct mtget *)data)->mt_fileno = u_info->file_number; ! 2110: ((struct mtget *)data)->mt_blkno = u_info->blkno; ! 2111: cycmd(dev, DO_STAT, 1); ! 2112: return NOERROR; ! 2113: } ! 2114: return ENXIO; ! 2115: } ! 2116: ! 2117: /* ! 2118: ** Cydump is called during a system crash to dump all of main memory. ! 2119: ** We don't do any special checking here except we will exit early if ! 2120: ** an i/o error occurs. The other point is we poll for completion of each ! 2121: ** command since we don't want to do any special processing, we are ! 2122: ** the only process running anyway, and possibly the cpu interupt's ! 2123: ** were not working anyway. (what if sombody stepped on low core?) ! 2124: */ ! 2125: ! 2126: cydump(dev) ! 2127: register dev_t dev; ! 2128: { ! 2129: register int unit = CYUNIT(dev); ! 2130: register int ctlr = cydinfo[unit]->ui_ctlr; ! 2131: register unit_tab *u_info = &unit_info[unit]; ! 2132: register ctlr_tab *c_info = &ctlr_info[ctlr]; ! 2133: register int blk_siz; ! 2134: register int num = maxfree; ! 2135: register int start = 0x800; ! 2136: ! 2137: if ((unit >= NCY) || cydinfo[unit]) ! 2138: return(ENXIO); ! 2139: u_info->control_proto = CW_LOCK | CW_25ips | CW_16bits; ! 2140: if (cywait(&c_info->ccb)) ! 2141: return(EFAULT); ! 2142: while (num > 0) { ! 2143: blk_siz = num > TBUFSIZ ? TBUFSIZ : num; ! 2144: bcopy(start*NBPG, c_info->rawbuf, blk_siz*NBPG); ! 2145: c_info->tpb.cmd = WRIT_TA; ! 2146: c_info->tpb.control = u_info->control_proto; ! 2147: c_info->tpb.status = 0; ! 2148: c_info->tpb.size = MULTIBUS_SHORT(blk_siz*NBPG); ! 2149: load_mbus_addr((char *)0, c_info->tpb.link_ptr); ! 2150: load_mbus_addr(c_info->rawbuf,&(c_info->tpb.data_ptr)); ! 2151: load_mbus_addr(&c_info->tpb, c_info->ccb.tpb_ptr); ! 2152: c_info->ccb.gate = GATE_CLOSED; ! 2153: CY_ATTENTION(cyminfo[ctlr]->um_addr); ! 2154: start += blk_siz; ! 2155: num -= blk_siz; ! 2156: if (cywait(&c_info->ccb)) ! 2157: return(EFAULT); ! 2158: uncache(&c_info->tpb); ! 2159: if (c_info->tpb.status&CS_ERm) /* error */ ! 2160: return (EIO); ! 2161: } ! 2162: for(num=0; num<2; num++) { ! 2163: c_info->tpb.cmd = WRIT_FM; ! 2164: c_info->tpb.control = u_info->control_proto; ! 2165: c_info->tpb.status = c_info->tpb.size = 0; ! 2166: c_info->tpb.count = MULTIBUS_SHORT(1); ! 2167: load_mbus_addr((char *)0, c_info->tpb.link_ptr); ! 2168: load_mbus_addr(c_info->rawbuf,&(c_info->tpb.data_ptr)); ! 2169: load_mbus_addr(&c_info->tpb, c_info->ccb.tpb_ptr); ! 2170: c_info->ccb.gate = GATE_CLOSED; ! 2171: CY_ATTENTION(cyminfo[ctlr]->um_addr); ! 2172: if (cywait(&c_info->ccb)) ! 2173: return(EFAULT); ! 2174: uncache(&c_info->tpb); ! 2175: if (c_info->tpb.status&CS_ERm) /* error */ ! 2176: return (EIO); ! 2177: } ! 2178: c_info->tpb.cmd = REWD_OV; ! 2179: c_info->tpb.control = u_info->control_proto; ! 2180: c_info->tpb.status = c_info->tpb.size = 0; ! 2181: c_info->tpb.count = MULTIBUS_SHORT(1); ! 2182: load_mbus_addr((char *)0, c_info->tpb.link_ptr); ! 2183: load_mbus_addr(c_info->rawbuf,&(c_info->tpb.data_ptr)); ! 2184: load_mbus_addr(&c_info->tpb, c_info->ccb.tpb_ptr); ! 2185: c_info->ccb.gate = GATE_CLOSED; ! 2186: CY_ATTENTION(cyminfo[ctlr]->um_addr); ! 2187: if (cywait(&c_info->ccb)) ! 2188: return EFAULT; ! 2189: uncache(&c_info->tpb); ! 2190: return 0; ! 2191: } ! 2192: ! 2193: ! 2194: /* ! 2195: ** Poll until the controller is ready. ! 2196: */ ! 2197: ! 2198: cywait(ccb_ptr) ! 2199: register fmt_ccb *ccb_ptr; ! 2200: { ! 2201: register int cnt = 5000; ! 2202: ! 2203: uncache(&ccb_ptr->gate); ! 2204: while ((cnt-- > 0) && (ccb_ptr->gate == GATE_CLOSED)) { ! 2205: DELAY(1000); ! 2206: uncache(&ccb_ptr->gate); ! 2207: } ! 2208: return cnt <= 0; ! 2209: } ! 2210: ! 2211: ! 2212: /* ! 2213: ** Load_mbus_addr is used to load a 20 bit pointer into the ! 2214: ** Tapemaster registers. Take note of all the strange convolutions ! 2215: ** this controller forces us through to get the job done. ! 2216: */ ! 2217: ! 2218: load_mbus_addr(in, out) ! 2219: char *in; ! 2220: short *out; ! 2221: { ! 2222: register int tmp_in = (int)in; ! 2223: register char *out_ptr = (char *)out; ! 2224: ! 2225: *out_ptr++ = (char)(tmp_in & 0xff); ! 2226: *out_ptr++ = (char)((tmp_in >> 8) & 0xff); ! 2227: *out_ptr++ = (char)0; ! 2228: *out_ptr++ = (char)((tmp_in & 0xf0000) >> 12); ! 2229: } ! 2230: ! 2231: ! 2232: /* ! 2233: ** CYMINSIZE s supposed to adjust the buffer size for any raw i/o. ! 2234: ** since tapes can not read the tail end of partial blocks we ignore ! 2235: ** this request and strategy will return an appropriate error message later. ! 2236: ** ! 2237: ** If this is not done UNIX will lose data that is on the tape. ! 2238: */ ! 2239: ! 2240: unsigned cyminsize(request) ! 2241: register struct buf *request; ! 2242: { ! 2243: if(request->b_bcount > MAX_BLOCKSIZE) ! 2244: request->b_bcount = MAX_BLOCKSIZE; ! 2245: } ! 2246: ! 2247: ! 2248: /* ! 2249: ** cyreset is used to unconditionally reset all controllers to ! 2250: ** their initial state. ! 2251: */ ! 2252: ! 2253: cyreset(vba) ! 2254: register int vba; ! 2255: { ! 2256: register int ctlr; ! 2257: register caddr_t ctlr_vaddr; ! 2258: ! 2259: for(ctlr = 0; ctlr<NCY; ctlr++) ! 2260: if(cyminfo[ctlr]) ! 2261: if(cyminfo[ctlr]->um_vbanum == vba) { ! 2262: ctlr_vaddr = cyminfo[ctlr]->um_addr; ! 2263: CY_RESET(ctlr_vaddr); ! 2264: if(!cy_init_controller(ctlr_vaddr, ctlr, 0)) { ! 2265: printf("cy: controller #%d failed to reset!\n", ctlr); ! 2266: cyminfo[ctlr] = NULL; ! 2267: } ! 2268: } ! 2269: } ! 2270: ! 2271: ! 2272: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.