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

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

unix.superglobalmegacorp.com

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