Annotation of cci/sys/vba/cy.c, revision 1.1.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.