Annotation of cci/sys/vba/cy.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.