Annotation of tme/scsi/scsi-bus.c, revision 1.1

1.1     ! root        1: /* $Id: scsi-bus.c,v 1.4 2003/10/16 02:35:21 fredette Exp $ */
        !             2: 
        !             3: /* scsi/scsi-bus.c - a generic SCSI bus element: */
        !             4: 
        !             5: /*
        !             6:  * Copyright (c) 2003 Matt Fredette
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. All advertising materials mentioning features or use of this software
        !            18:  *    must display the following acknowledgement:
        !            19:  *      This product includes software developed by Matt Fredette.
        !            20:  * 4. The name of the author may not be used to endorse or promote products
        !            21:  *    derived from this software without specific prior written permission.
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
        !            27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            33:  * POSSIBILITY OF SUCH DAMAGE.
        !            34:  */
        !            35: 
        !            36: #include <tme/common.h>
        !            37: _TME_RCSID("$Id: scsi-bus.c,v 1.4 2003/10/16 02:35:21 fredette Exp $");
        !            38: 
        !            39: /* includes: */
        !            40: #include <tme/generic/scsi.h>
        !            41: #ifdef HAVE_STDARG_H
        !            42: #include <stdarg.h>
        !            43: #else  /* HAVE_STDARG_H */
        !            44: #include <varargs.h>
        !            45: #endif /* HAVE_STDARG_H */
        !            46: 
        !            47: /* macros: */
        !            48: 
        !            49: /* the count of IDs: */
        !            50: #define TME_SCSI_BUS_ID_COUNT  (sizeof(tme_scsi_data_t) * 8)
        !            51: 
        !            52: /* the callout flags: */
        !            53: #define TME_SCSI_BUS_CALLOUT_CHECK             (0)
        !            54: #define TME_SCSI_BUS_CALLOUT_RUNNING           TME_BIT(0)
        !            55: #define TME_SCSI_BUS_CALLOUTS_MASK             (-2)
        !            56: #define  TME_SCSI_BUS_CALLOUT_CYCLE            TME_BIT(1)
        !            57: 
        !            58: /* structures: */
        !            59: 
        !            60: /* a scsi bus: */
        !            61: struct tme_scsi_bus {
        !            62: 
        !            63:   /* backpointer to our element: */
        !            64:   struct tme_element *tme_scsi_bus_element;
        !            65: 
        !            66:   /* our mutex: */
        !            67:   tme_mutex_t tme_scsi_bus_mutex;
        !            68: 
        !            69:   /* our connections: */
        !            70:   struct tme_connection *tme_scsi_bus_connections;
        !            71: 
        !            72:   /* the callout flags: */
        !            73:   int tme_scsi_bus_callout_flags;
        !            74: 
        !            75:   /* the current bus state: */
        !            76:   tme_scsi_control_t tme_scsi_bus_control;
        !            77:   tme_scsi_control_t tme_scsi_bus_data;
        !            78: };
        !            79: 
        !            80: /* internal information about a SCSI connection: */
        !            81: struct tme_scsi_connection_int {
        !            82: 
        !            83:   /* the external SCSI connection: */
        !            84:   struct tme_scsi_connection tme_scsi_connection_int;
        !            85: 
        !            86:   /* the control and data lines currently asserted by this connection: */
        !            87:   tme_scsi_control_t tme_scsi_connection_int_control;
        !            88:   tme_scsi_data_t tme_scsi_connection_int_data;
        !            89: 
        !            90:   /* the SCSI bus state last reported to the connection: */
        !            91:   tme_scsi_control_t tme_scsi_connection_int_last_control;
        !            92:   tme_scsi_control_t tme_scsi_connection_int_last_data;
        !            93: 
        !            94:   /* any sequence that this connection is running, and the step
        !            95:      within that sequence: */
        !            96:   const struct tme_scsi_sequence *tme_scsi_connection_int_sequence;
        !            97:   unsigned int tme_scsi_connection_int_sequence_step;
        !            98: 
        !            99:   /* any DMA structure for this connection: */
        !           100:   struct tme_scsi_dma *tme_scsi_connection_int_dma;
        !           101:   
        !           102:   /* specific callout flags for this connection: */
        !           103:   int tme_scsi_connection_int_callout_flags;
        !           104: };
        !           105: 
        !           106: /* the predefined sequence atom type: */
        !           107: typedef unsigned long tme_scsi_sequence_atom_t;
        !           108: 
        !           109: /* globals: */
        !           110: 
        !           111: /* atoms representing the predefined sequences.  the tme SCSI
        !           112:    interface allows a bus implementation to return predefined
        !           113:    sequences that are actually completely opaque - despite getting a
        !           114:    struct tme_scsi_sequence *, SCSI device implementations are not
        !           115:    allowed to even *dereference* a pointer returned by a bus
        !           116:    implementation's tme_scsi_connection_sequence_get method.  we take
        !           117:    advantage of this here to make a partial, optimized implementation: */
        !           118: const struct {
        !           119:   tme_scsi_sequence_atom_t tme_scsi_sequence_info_dma_initiator;
        !           120:   tme_scsi_sequence_atom_t tme_scsi_sequence_info_dma_target;
        !           121:   tme_scsi_sequence_atom_t tme_scsi_sequence_wait_select_half[TME_SCSI_BUS_ID_COUNT];
        !           122:   tme_scsi_sequence_atom_t tme_scsi_sequence_wait_select_full[TME_SCSI_BUS_ID_COUNT];
        !           123:   tme_scsi_sequence_atom_t tme_scsi_sequence_wait_change;
        !           124: } _tme_scsi_bus_sequences;
        !           125: 
        !           126: /* the SCSI bus callout function.  it must be called with the mutex locked: */
        !           127: static void
        !           128: _tme_scsi_bus_callout(struct tme_scsi_bus *scsi_bus, int new_callouts)
        !           129: {
        !           130:   struct tme_scsi_connection_int *conn_int;
        !           131:   struct tme_scsi_connection *conn_scsi;
        !           132:   int callouts, later_callouts;
        !           133:   tme_scsi_control_t control;
        !           134:   tme_scsi_data_t data;
        !           135:   int rc;
        !           136:   
        !           137:   /* add in any new callouts: */
        !           138:   scsi_bus->tme_scsi_bus_callout_flags |= new_callouts;
        !           139: 
        !           140:   /* if this function is already running in another thread, simply
        !           141:      return now.  the other thread will do our work: */
        !           142:   if (scsi_bus->tme_scsi_bus_callout_flags
        !           143:       & TME_SCSI_BUS_CALLOUT_RUNNING) {
        !           144:     return;
        !           145:   }
        !           146: 
        !           147:   /* callouts are now running: */
        !           148:   scsi_bus->tme_scsi_bus_callout_flags
        !           149:     |= TME_SCSI_BUS_CALLOUT_RUNNING;
        !           150: 
        !           151:   /* assume that we won't need any later callouts: */
        !           152:   later_callouts = 0;
        !           153: 
        !           154:   /* loop while callouts are needed: */
        !           155:   for (; ((callouts
        !           156:           = scsi_bus->tme_scsi_bus_callout_flags)
        !           157:          & TME_SCSI_BUS_CALLOUTS_MASK); ) {
        !           158: 
        !           159:     /* clear the needed callouts: */
        !           160:     scsi_bus->tme_scsi_bus_callout_flags
        !           161:       = (callouts
        !           162:         & ~TME_SCSI_BUS_CALLOUTS_MASK);
        !           163:     callouts &= TME_SCSI_BUS_CALLOUTS_MASK;
        !           164: 
        !           165:     /* if we need to call out SCSI bus cycles: */
        !           166:     if (callouts & TME_SCSI_BUS_CALLOUT_CYCLE) {
        !           167: 
        !           168:       /* loop over all devices on the bus: */
        !           169:       for (conn_int
        !           170:             = ((struct tme_scsi_connection_int *)
        !           171:                scsi_bus->tme_scsi_bus_connections);
        !           172:           conn_int != NULL;
        !           173:           conn_int
        !           174:             = ((struct tme_scsi_connection_int *)
        !           175:                conn_int->tme_scsi_connection_int.tme_scsi_connection.tme_connection_next)) {
        !           176:        
        !           177:        /* if this device doesn't need a callout, continue: */
        !           178:        if (!(conn_int->tme_scsi_connection_int_callout_flags
        !           179:              & TME_SCSI_BUS_CALLOUT_CYCLE)) {
        !           180:          continue;
        !           181:        }
        !           182: 
        !           183:        /* clear the callout flag on this device: */
        !           184:        conn_int->tme_scsi_connection_int_callout_flags
        !           185:          &= ~TME_SCSI_BUS_CALLOUT_CYCLE;
        !           186: 
        !           187:        /* get the current state of the bus: */
        !           188:        control = scsi_bus->tme_scsi_bus_control;
        !           189:        data = scsi_bus->tme_scsi_bus_data;
        !           190: 
        !           191:        /* remember this last bus state called out to this connection: */
        !           192:        conn_int->tme_scsi_connection_int_last_control
        !           193:          = control;
        !           194:        conn_int->tme_scsi_connection_int_last_data
        !           195:          = data;
        !           196: 
        !           197:        /* unlock the mutex: */
        !           198:        tme_mutex_unlock(&scsi_bus->tme_scsi_bus_mutex);
        !           199:        
        !           200:        /* do the callout: */
        !           201:        conn_scsi
        !           202:          = ((struct tme_scsi_connection *)
        !           203:             conn_int->tme_scsi_connection_int.tme_scsi_connection.tme_connection_other);
        !           204:        rc = ((*conn_scsi->tme_scsi_connection_cycle)
        !           205:              (conn_scsi,
        !           206:               control,
        !           207:               data,
        !           208:               conn_int->tme_scsi_connection_int_sequence,
        !           209:               NULL));
        !           210:        
        !           211:        /* lock the mutex: */
        !           212:        tme_mutex_lock(&scsi_bus->tme_scsi_bus_mutex);
        !           213:       
        !           214:        /* if the callout was unsuccessful, remember that at some later
        !           215:           time this callout should be attempted again: */
        !           216:        if (rc != TME_OK) {
        !           217:          conn_int->tme_scsi_connection_int_callout_flags
        !           218:            |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           219:          later_callouts
        !           220:            |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           221:        }
        !           222:       }
        !           223:     }
        !           224:   }
        !           225:   
        !           226:   /* put in any later callouts, and clear that callouts are running: */
        !           227:   scsi_bus->tme_scsi_bus_callout_flags = later_callouts;
        !           228: }
        !           229: 
        !           230: /* this handles a SCSI bus cycle: */
        !           231: static int
        !           232: _tme_scsi_bus_cycle(struct tme_scsi_connection *conn_scsi,
        !           233:                    tme_scsi_control_t control,
        !           234:                    tme_scsi_data_t data,
        !           235:                    const struct tme_scsi_sequence *sequence_asker,
        !           236:                    struct tme_scsi_dma *dma)
        !           237: {
        !           238:   struct tme_scsi_bus *scsi_bus;
        !           239:   struct tme_scsi_connection_int *conn_int_asker, *conn_int;
        !           240:   const struct tme_scsi_sequence *sequence;
        !           241:   struct tme_scsi_connection_int *dma_initiator;
        !           242:   struct tme_scsi_connection_int *dma_target;
        !           243:   struct tme_scsi_dma *dma_in, *dma_out;
        !           244:   unsigned long count;
        !           245:   int bus_changed;
        !           246:   int new_callouts;
        !           247:   int again;
        !           248:   tme_scsi_data_t id;
        !           249: 
        !           250:   /* recover our bus and internal connection: */
        !           251:   scsi_bus = conn_scsi->tme_scsi_connection.tme_connection_element->tme_element_private;
        !           252:   conn_int_asker = (struct tme_scsi_connection_int *) conn_scsi;
        !           253: 
        !           254:   /* assume we won't need any new callouts: */
        !           255:   new_callouts = 0;
        !           256: 
        !           257:   /* lock the mutex: */
        !           258:   tme_mutex_lock(&scsi_bus->tme_scsi_bus_mutex);
        !           259: 
        !           260:   /* update the signals that this device is asserting: */
        !           261:   conn_int_asker->tme_scsi_connection_int_control = control;
        !           262:   conn_int_asker->tme_scsi_connection_int_data = data;
        !           263: 
        !           264:   /* update the sequence for this device: */
        !           265:   if (sequence_asker != NULL) {
        !           266: 
        !           267:     /* being a partial implementation, we don't support device-defined
        !           268:        sequences - any sequence must be a predefined sequence that we
        !           269:        returned: */
        !           270:     if ((sequence_asker
        !           271:         < (const struct tme_scsi_sequence *) (char *) &_tme_scsi_bus_sequences)
        !           272:        || (sequence_asker
        !           273:            >= (const struct tme_scsi_sequence *) (char *) (&_tme_scsi_bus_sequences + 1))) {
        !           274:       abort();
        !           275:     }
        !           276:   }
        !           277:   conn_int_asker->tme_scsi_connection_int_sequence = sequence_asker;
        !           278:   conn_int_asker->tme_scsi_connection_int_sequence_step = 0;
        !           279: 
        !           280:   /* update the DMA structure for this device.  being a partial
        !           281:      implementation, we only support 8-bit asynchronous DMA: */
        !           282:   if (dma != NULL) {
        !           283:     if (((dma->tme_scsi_dma_flags
        !           284:          & TME_SCSI_DMA_WIDTH)
        !           285:         != TME_SCSI_DMA_8BIT)
        !           286:        || (dma->tme_scsi_dma_sync_offset
        !           287:            != 0)) {
        !           288:       abort();
        !           289:     }
        !           290:     if (dma->tme_scsi_dma_resid == 0) {
        !           291:       conn_int_asker->tme_scsi_connection_int_callout_flags
        !           292:        |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           293:       conn_int_asker->tme_scsi_connection_int_sequence
        !           294:        = NULL;
        !           295:       new_callouts
        !           296:        |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           297:       dma = NULL;
        !           298:     }
        !           299:   }
        !           300:   conn_int_asker->tme_scsi_connection_int_dma = dma;
        !           301: 
        !           302:   /* if during any iteration of the below loop, we see or cause a
        !           303:      change on the bus, we want to call out cycles to all devices
        !           304:      waiting on a simple change: */
        !           305:   bus_changed = FALSE;
        !           306: 
        !           307:   /* loop until things settle down: */
        !           308:   for (again = TRUE; again; ) {
        !           309:     again = FALSE;
        !           310: 
        !           311:     /* get the current state of the bus: */
        !           312:     control = 0;
        !           313:     data = 0;
        !           314:     for (conn_int
        !           315:           = ((struct tme_scsi_connection_int *)
        !           316:              scsi_bus->tme_scsi_bus_connections);
        !           317:         conn_int != NULL;
        !           318:         conn_int
        !           319:           = ((struct tme_scsi_connection_int *)
        !           320:              conn_int->tme_scsi_connection_int.tme_scsi_connection.tme_connection_next)) {
        !           321:       control |= conn_int->tme_scsi_connection_int_control;
        !           322:       data |= conn_int->tme_scsi_connection_int_data;
        !           323:     }
        !           324:     if ((control != scsi_bus->tme_scsi_bus_control)
        !           325:        || (data != scsi_bus->tme_scsi_bus_data)) {
        !           326:       bus_changed = TRUE;
        !           327:     }
        !           328:     scsi_bus->tme_scsi_bus_control = control;
        !           329:     scsi_bus->tme_scsi_bus_data = data;
        !           330: 
        !           331:     /* loop over all devices on the bus: */
        !           332:     dma_initiator = NULL;
        !           333:     dma_target = NULL;
        !           334:     for (conn_int
        !           335:           = ((struct tme_scsi_connection_int *)
        !           336:              scsi_bus->tme_scsi_bus_connections);
        !           337:         conn_int != NULL;
        !           338:         conn_int
        !           339:           = ((struct tme_scsi_connection_int *)
        !           340:              conn_int->tme_scsi_connection_int.tme_scsi_connection.tme_connection_next)) {
        !           341: 
        !           342:       /* dispatch on this device's sequence: */
        !           343:       sequence = conn_int->tme_scsi_connection_int_sequence;
        !           344: #define SEQUENCE_IS(s, f)                              \
        !           345:   (((s)                                                        \
        !           346:     >= ((const struct tme_scsi_sequence *)             \
        !           347:        &_tme_scsi_bus_sequences.f))                    \
        !           348:    && ((s)                                             \
        !           349:        < ((const struct tme_scsi_sequence *)           \
        !           350:          (&_tme_scsi_bus_sequences.f                   \
        !           351:           + 1))))
        !           352: #define SEQUENCE_INDEX(s, f)                           \
        !           353:   (((const tme_scsi_sequence_atom_t *) (s))            \
        !           354:    - &_tme_scsi_bus_sequences.f[0])
        !           355: 
        !           356:       /* a device with no sequence is ignoring the bus completely: */
        !           357:       if (sequence == NULL) {
        !           358:        /* nothing to do: */
        !           359:       }
        !           360: 
        !           361:       /* a device in TME_SCSI_SEQUENCE_WAIT_CHANGE is waiting on any
        !           362:         change to the bus state: */
        !           363:       else if (SEQUENCE_IS(sequence, tme_scsi_sequence_wait_change)) {
        !           364: 
        !           365:        /* if the bus has changed, callout a cycle on this device: */
        !           366:        if (bus_changed
        !           367:            || (control !=
        !           368:                conn_int->tme_scsi_connection_int_last_control)
        !           369:            || (data
        !           370:                != conn_int->tme_scsi_connection_int_last_data)) {
        !           371:          conn_int->tme_scsi_connection_int_callout_flags
        !           372:            |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           373:          conn_int->tme_scsi_connection_int_sequence
        !           374:            = NULL;
        !           375:          new_callouts
        !           376:            |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           377:        }
        !           378:       }
        !           379: 
        !           380:       /* a connection in TME_SCSI_SEQUENCE_WAIT_SELECT_HALF or
        !           381:         TME_SCSI_SEQUENCE_WAIT_SELECT_FULL is waiting to be selected: */
        !           382:       else if (SEQUENCE_IS(sequence,
        !           383:                           tme_scsi_sequence_wait_select_half)
        !           384:               || SEQUENCE_IS(sequence,
        !           385:                              tme_scsi_sequence_wait_select_full)) {
        !           386: 
        !           387:        /* get the SCSI ID for the connection: */
        !           388:        id = (SEQUENCE_IS(sequence,
        !           389:                          tme_scsi_sequence_wait_select_half)
        !           390:              ? SEQUENCE_INDEX(sequence,
        !           391:                               tme_scsi_sequence_wait_select_half)
        !           392:              : SEQUENCE_INDEX(sequence,
        !           393:                               tme_scsi_sequence_wait_select_full));
        !           394:        
        !           395:        /* dispatch on the sequence step: */
        !           396:        switch (conn_int->tme_scsi_connection_int_sequence_step) {
        !           397: 
        !           398:          /* "In all systems, the target shall determine that it is
        !           399:             selected when SEL and its SCSI ID bit are true and BSY and
        !           400:             I/O are false for at least a bus settle delay." */
        !           401:        case 0:
        !           402:          if (((control
        !           403:                & (TME_SCSI_SIGNAL_BSY
        !           404:                   | TME_SCSI_SIGNAL_SEL
        !           405:                   | TME_SCSI_SIGNAL_I_O))
        !           406:               == TME_SCSI_SIGNAL_SEL)
        !           407:              && (data
        !           408:                  & TME_BIT(id))) {
        !           409: 
        !           410:            /* this device is being selected: */
        !           411: 
        !           412:            /* if this device is in
        !           413:               TME_SCSI_SEQUENCE_WAIT_SELECT_HALF, callout a cycle on
        !           414:               this device: */
        !           415:            if (SEQUENCE_IS(sequence,
        !           416:                            tme_scsi_sequence_wait_select_half)) {
        !           417:              conn_int->tme_scsi_connection_int_callout_flags
        !           418:                |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           419:              conn_int->tme_scsi_connection_int_sequence
        !           420:                = NULL;
        !           421:              new_callouts
        !           422:                |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           423:            }
        !           424: 
        !           425:            /* otherwise, this device is in
        !           426:               TME_SCSI_SEQUENCE_WAIT_SELECT_FULL.  assert BSY on its
        !           427:               behalf and advance to the next state: */
        !           428:            else {
        !           429:              conn_int->tme_scsi_connection_int_control
        !           430:                |= TME_SCSI_SIGNAL_BSY;
        !           431:              conn_int->tme_scsi_connection_int_sequence_step++;
        !           432:              again = TRUE;
        !           433:              bus_changed = TRUE;
        !           434:            }
        !           435:          }
        !           436:          break;
        !           437: 
        !           438:          /* "At least two deskew delays after the initiator detects
        !           439:             BSY is true, it shall release SEL and may change the DATA
        !           440:             BUS."
        !           441: 
        !           442:             as the target, we wait for SEL to be negated: */
        !           443:        case 1:
        !           444:          if (!(control
        !           445:                & TME_SCSI_SIGNAL_SEL)) {
        !           446:          
        !           447:            /* callout a cycle on this device: */
        !           448:            conn_int->tme_scsi_connection_int_callout_flags
        !           449:              |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           450:            conn_int->tme_scsi_connection_int_sequence
        !           451:              = NULL;
        !           452:            new_callouts
        !           453:              |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           454:          }
        !           455:          break;
        !           456:        }
        !           457:       }
        !           458: 
        !           459:       /* there can be at most one device in an initiator or target
        !           460:         information transfer phase DMA sequence: */
        !           461:       else if (SEQUENCE_IS(sequence, tme_scsi_sequence_info_dma_initiator)) {
        !           462:        assert (dma_initiator == NULL);
        !           463:        dma_initiator = conn_int;
        !           464:       }
        !           465:       else if (SEQUENCE_IS(sequence, tme_scsi_sequence_info_dma_target)) {
        !           466:        assert (dma_target == NULL);
        !           467:        dma_target = conn_int;
        !           468:       }
        !           469:     }
        !           470: 
        !           471:     /* if we need to loop again, do so immediately: */
        !           472:     if (again) {
        !           473:       continue;
        !           474:     }
        !           475: 
        !           476:     /* if a device is in the initiator information transfer phase DMA
        !           477:        sequence, but the information transfer phase has changed,
        !           478:        callout a cycle on this device: */
        !           479:     if (dma_initiator != NULL
        !           480:        && (TME_SCSI_PHASE(control)
        !           481:            != TME_SCSI_PHASE(dma_initiator->tme_scsi_connection_int_last_control))) {
        !           482:       dma_initiator->tme_scsi_connection_int_callout_flags
        !           483:        |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           484:       dma_initiator->tme_scsi_connection_int_sequence
        !           485:        = NULL;
        !           486:       new_callouts
        !           487:        |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           488:       dma_initiator = NULL;
        !           489:     }
        !           490: 
        !           491:     /* if initiator and target are both in their respective DMA
        !           492:        sequences, we can do a bulk copy between them: */
        !           493:     if (dma_initiator != NULL
        !           494:        && dma_target != NULL) {
        !           495: 
        !           496:       /* sort the devices' DMA structures into input and output: */
        !           497:       if (control & TME_SCSI_SIGNAL_I_O) {
        !           498:        dma_in = dma_initiator->tme_scsi_connection_int_dma;
        !           499:        dma_out = dma_target->tme_scsi_connection_int_dma;
        !           500:       }
        !           501:       else {
        !           502:        dma_out = dma_initiator->tme_scsi_connection_int_dma;
        !           503:        dma_in = dma_target->tme_scsi_connection_int_dma;
        !           504:       }
        !           505:       assert (dma_out != NULL && dma_in != NULL);
        !           506: 
        !           507:       /* get the size of the bulk copy: */
        !           508:       count = TME_MIN(dma_out->tme_scsi_dma_resid,
        !           509:                      dma_in->tme_scsi_dma_resid);
        !           510:       assert (count > 0);
        !           511: 
        !           512:       /* do the bulk copy: */
        !           513:       memcpy(dma_in->tme_scsi_dma_in,
        !           514:             dma_out->tme_scsi_dma_out,
        !           515:             count);
        !           516: 
        !           517:       /* advance the DMA pointers: */
        !           518:       dma_in->tme_scsi_dma_in += count;
        !           519:       dma_out->tme_scsi_dma_out += count;
        !           520: 
        !           521:       /* if the target's DMA has been exhausted, be sure to negate
        !           522:         REQ, and callout a cycle on the device: */
        !           523:       dma = dma_target->tme_scsi_connection_int_dma;
        !           524:       if ((dma->tme_scsi_dma_resid -= count) == 0) {
        !           525: 
        !           526:        /* negate REQ on the target's behalf: */
        !           527:        dma_target->tme_scsi_connection_int_control
        !           528:          &= ~TME_SCSI_SIGNAL_REQ;
        !           529:        again = TRUE;
        !           530:        bus_changed = TRUE;
        !           531: 
        !           532:        /* request the callout: */
        !           533:        dma_target->tme_scsi_connection_int_callout_flags
        !           534:          |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           535:        dma_target->tme_scsi_connection_int_sequence
        !           536:          = NULL;
        !           537:        new_callouts
        !           538:          |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           539: 
        !           540:        /* no device is currently in the target information phase
        !           541:            transfer DMA sequence: */
        !           542:        dma_target = NULL;
        !           543:       }
        !           544: 
        !           545:       /* otherwise, the target's DMA has not been exhausted.  be sure
        !           546:         that we return to state zero in the DMA target sequence: */
        !           547:       else {
        !           548:        dma_target->tme_scsi_connection_int_sequence_step = 0;
        !           549:       }
        !           550:       
        !           551:       /* if the initiator's DMA has been exhausted, callout a cycle on
        !           552:          the device: */
        !           553:       dma = dma_initiator->tme_scsi_connection_int_dma;
        !           554:       if ((dma->tme_scsi_dma_resid -= count) == 0) {
        !           555: 
        !           556:        /* request the callout: */
        !           557:        dma_initiator->tme_scsi_connection_int_callout_flags
        !           558:          |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           559:        dma_initiator->tme_scsi_connection_int_sequence
        !           560:          = NULL;
        !           561:        new_callouts
        !           562:          |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           563: 
        !           564:        /* no device is currently in the initiator information phase
        !           565:            transfer DMA sequence: */
        !           566:        dma_initiator = NULL;
        !           567:       }
        !           568: 
        !           569:       /* otherwise, the initiator's DMA has not been exhausted.  be sure
        !           570:         that we return to state zero in the DMA initiator sequence: */
        !           571:       else {
        !           572:        dma_initiator->tme_scsi_connection_int_sequence_step = 0;
        !           573:       }      
        !           574:     }
        !           575: 
        !           576:     /* if we need to loop again, do so immediately: */
        !           577:     if (again) {
        !           578:       continue;
        !           579:     }
        !           580: 
        !           581:     /* if a device is in the target information transfer phase DMA
        !           582:        sequence: */
        !           583:     if (dma_target != NULL) {
        !           584: 
        !           585:       /* get this device's DMA structure: */
        !           586:       dma = dma_target->tme_scsi_connection_int_dma;
        !           587:       assert (dma != NULL);
        !           588: 
        !           589:       /* dispatch on the sequence step: */
        !           590:       switch (dma_target->tme_scsi_connection_int_sequence_step) {
        !           591: 
        !           592:        /* "If I/O is true (transfer to the initiator)... [after] ACK
        !           593:           is false the target may continue the transfer by driving
        !           594:           DB(7-0,P) and asserting REQ, as described above."
        !           595: 
        !           596:           "If I/O is false (transfer to the target)... [after ACK is
        !           597:           false the target] may continue the transfer by asserting
        !           598:           REQ, as described above." */
        !           599:       case 2:
        !           600:        if (control & TME_SCSI_SIGNAL_ACK) {
        !           601:          break;
        !           602:        }
        !           603: 
        !           604:        /* if the DMA has been exhausted, callout a cycle on this
        !           605:           device: */
        !           606:        if (control & TME_SCSI_SIGNAL_I_O) {
        !           607:          dma->tme_scsi_dma_out++;
        !           608:        }
        !           609:        else {
        !           610:          dma->tme_scsi_dma_in++;
        !           611:        }
        !           612:        if (--dma->tme_scsi_dma_resid == 0) {
        !           613:          dma_target->tme_scsi_connection_int_callout_flags
        !           614:            |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           615:          dma_target->tme_scsi_connection_int_sequence
        !           616:            = NULL;
        !           617:          new_callouts
        !           618:            |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           619:          break;
        !           620:        }
        !           621: 
        !           622:        /* FALLTHROUGH */
        !           623: 
        !           624:       /* "If I/O is true (transfer to the initiator), the target shall
        !           625:         first drive DB(7-0,P) to their desired values, delay at least
        !           626:         one deskew delay plus a cable skew delay, then assert REQ."
        !           627: 
        !           628:         "If I/O is false (transfer to the target) the target shall request 
        !           629:         information by asserting REQ. " */
        !           630:       case 0:
        !           631: 
        !           632:        /* assert REQ on the target's behalf: */
        !           633:        dma_target->tme_scsi_connection_int_control
        !           634:          |= TME_SCSI_SIGNAL_REQ;
        !           635:        again = TRUE;
        !           636:        bus_changed = TRUE;
        !           637: 
        !           638:        /* if I/O is asserted, assert the output data: */
        !           639:        if (control & TME_SCSI_SIGNAL_I_O) {
        !           640:          dma_target->tme_scsi_connection_int_data
        !           641:            = *(dma->tme_scsi_dma_out);
        !           642:        }
        !           643: 
        !           644:        /* advance to step one: */
        !           645:        dma_target->tme_scsi_connection_int_sequence_step = 1;
        !           646:        break;
        !           647: 
        !           648:        /* "If I/O is true (transfer to the initiator)... [when] ACK
        !           649:           becomes true at the target, the target may change or
        !           650:           release DB(7-0,P) and shall negate REQ."
        !           651: 
        !           652:           "If I/O is false (transfer to the target)... [when] ACK
        !           653:           becomes true at the target, the target shall read
        !           654:           DB(7-0,P), then negate REQ." */
        !           655:       case 1:
        !           656:        if (control & TME_SCSI_SIGNAL_ACK) {
        !           657: 
        !           658:          /* if I/O is negated, read the input data: */
        !           659:          if (!(control & TME_SCSI_SIGNAL_I_O)) {
        !           660:            *(dma->tme_scsi_dma_in) = data;
        !           661:          }
        !           662: 
        !           663:          /* negate REQ on the target's behalf: */
        !           664:          dma_target->tme_scsi_connection_int_control
        !           665:            &= ~TME_SCSI_SIGNAL_REQ;
        !           666:          again = TRUE;
        !           667:          bus_changed = TRUE;
        !           668:        
        !           669:          /* advance to step two: */
        !           670:          dma_target->tme_scsi_connection_int_sequence_step = 2;
        !           671:        }
        !           672:        break;
        !           673: 
        !           674:       default: assert (FALSE);
        !           675:       }
        !           676: 
        !           677:       /* if the bus is being reset: */
        !           678:       if (control & TME_SCSI_SIGNAL_RST) {
        !           679: 
        !           680:        /* negate all signals on the target's behalf: */
        !           681:        dma_target->tme_scsi_connection_int_control = 0;
        !           682:        dma_target->tme_scsi_connection_int_data = 0;
        !           683:        again = TRUE;
        !           684:        bus_changed = TRUE;
        !           685:        
        !           686:        /* callout a cycle on this device: */
        !           687:        dma_target->tme_scsi_connection_int_callout_flags
        !           688:          |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           689:        dma_target->tme_scsi_connection_int_sequence
        !           690:          = NULL;
        !           691:        new_callouts
        !           692:          |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           693:       }
        !           694:     }
        !           695: 
        !           696:     /* if we need to loop again, do so immediately: */
        !           697:     if (again) {
        !           698:       continue;
        !           699:     }
        !           700: 
        !           701:     /* if a device is in the initiator information transfer phase DMA
        !           702:        sequence: */
        !           703:     if (dma_initiator != NULL) {
        !           704: 
        !           705:       /* get this device's DMA structure: */
        !           706:       dma = dma_initiator->tme_scsi_connection_int_dma;
        !           707:       assert (dma != NULL);
        !           708:       
        !           709:       /* dispatch on the sequence step: */
        !           710:       switch (dma_initiator->tme_scsi_connection_int_sequence_step) {
        !           711:        
        !           712:        /* "If I/O is true (transfer to the initiator)... [the]
        !           713:           initiator shall read DB(7-0,P) after REQ is true, then
        !           714:           signal its acceptance of the data by asserting ACK."
        !           715:           
        !           716:           "If I/O is false (transfer to the target)... [the]
        !           717:           initiator shall drive DB(7-0,P) to their desired values
        !           718:           [after REQ is true], delay at least one deskew delay plus a
        !           719:           cable skew delay and assert ACK." */
        !           720:       case 0:
        !           721:        if (!(control & TME_SCSI_SIGNAL_REQ)) {
        !           722:          break;
        !           723:        }
        !           724:          
        !           725:        /* if I/O is true, read the data, else
        !           726:           write the data: */
        !           727:        if (control & TME_SCSI_SIGNAL_I_O) {
        !           728:          *dma->tme_scsi_dma_in = data;
        !           729:        }
        !           730:        else {
        !           731:          dma_initiator->tme_scsi_connection_int_data
        !           732:            = *(dma->tme_scsi_dma_out);
        !           733:        }
        !           734:        
        !           735:        /* assert ACK on the initiator's behalf: */
        !           736:        dma_initiator->tme_scsi_connection_int_control
        !           737:          |= TME_SCSI_SIGNAL_ACK;
        !           738:        again = TRUE;
        !           739:        bus_changed = TRUE;
        !           740:        
        !           741:        /* advance to step one: */
        !           742:        dma_initiator->tme_scsi_connection_int_sequence_step = 1;
        !           743:        break;
        !           744:        
        !           745:        /* "If I/O is true (transfer to the initiator)... [after]
        !           746:           REQ is false the initiator shall then negate ACK."
        !           747:           
        !           748:           "If I/O is false (transfer to the target)... [when]
        !           749:           REQ becomes false at the initiator, the initiator may 
        !           750:           change or release DB(7-0,P) and shall negate ACK." */
        !           751:       case 1:
        !           752:        if (control & TME_SCSI_SIGNAL_REQ) {
        !           753:          break;
        !           754:        }
        !           755:        
        !           756:        /* negate ACK on the initiator's behalf: */
        !           757:        dma_initiator->tme_scsi_connection_int_control
        !           758:          &= ~TME_SCSI_SIGNAL_ACK;
        !           759:        again = TRUE;
        !           760:        bus_changed = TRUE;
        !           761:        
        !           762:        /* if the DMA has been exhausted, callout a cycle on this
        !           763:           device: */
        !           764:        if (control & TME_SCSI_SIGNAL_I_O) {
        !           765:          dma->tme_scsi_dma_in++;
        !           766:        }
        !           767:        else {
        !           768:          dma->tme_scsi_dma_out++;
        !           769:        }
        !           770:        if (--dma->tme_scsi_dma_resid == 0) {
        !           771:          dma_initiator->tme_scsi_connection_int_callout_flags
        !           772:            |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           773:          dma_initiator->tme_scsi_connection_int_sequence
        !           774:            = NULL;
        !           775:          new_callouts |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           776:        }
        !           777:        
        !           778:        /* otherwise, advance to step zero: */
        !           779:        else {
        !           780:          dma_initiator->tme_scsi_connection_int_sequence_step = 0;
        !           781:        }
        !           782:        break;
        !           783:        
        !           784:       default:
        !           785:        assert (FALSE);
        !           786:       }
        !           787: 
        !           788:       /* if the bus is being reset: */
        !           789:       if (control & TME_SCSI_SIGNAL_RST) {
        !           790: 
        !           791:        /* negate all signals on the initiator's behalf: */
        !           792:        dma_target->tme_scsi_connection_int_control = 0;
        !           793:        dma_target->tme_scsi_connection_int_data = 0;
        !           794:        again = TRUE;
        !           795:        bus_changed = TRUE;
        !           796:        
        !           797:        /* callout a cycle on this device: */
        !           798:        dma_target->tme_scsi_connection_int_callout_flags
        !           799:          |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           800:        dma_target->tme_scsi_connection_int_sequence
        !           801:          = NULL;
        !           802:        new_callouts
        !           803:          |= TME_SCSI_BUS_CALLOUT_CYCLE;
        !           804:       }
        !           805:     }
        !           806:   }
        !           807: 
        !           808:   /* make any needed callouts: */
        !           809:   _tme_scsi_bus_callout(scsi_bus, new_callouts);
        !           810: 
        !           811:   /* unlock the mutex: */
        !           812:   tme_mutex_unlock(&scsi_bus->tme_scsi_bus_mutex);
        !           813: 
        !           814:   return (TME_OK);
        !           815: }
        !           816: 
        !           817: /* this returns a predefined SCSI sequence: */
        !           818: #ifdef HAVE_STDARG_H
        !           819: static const struct tme_scsi_sequence *
        !           820: _tme_scsi_bus_sequence_get(struct tme_scsi_connection *conn_scsi,
        !           821:                           unsigned int sequence_type,
        !           822:                           ...)
        !           823: #else  /* HAVE_STDARG_H */
        !           824: static const struct tme_scsi_sequence *_tme_scsi_bus_sequence_get(conn_scsi, sequence_type, va_alist)
        !           825:      struct tme_scsi_connection *conn_scsi;
        !           826:      unsigned int sequence_type;
        !           827:      va_dcl
        !           828: #endif /* HAVE_STDARG_H */
        !           829: {
        !           830:   va_list sequence_args;
        !           831:   const struct tme_scsi_sequence *sequence;
        !           832:   tme_scsi_data_t id0;
        !           833: 
        !           834:   /* start the variable arguments: */
        !           835: #ifdef HAVE_STDARG_H
        !           836:   va_start(sequence_args, sequence_type);
        !           837: #else  /* HAVE_STDARG_H */
        !           838:   va_start(sequence_args);
        !           839: #endif /* HAVE_STDARG_H */
        !           840: 
        !           841:   /* dispatch on the sequence type: */
        !           842: #define SEQUENCE(f) ((const struct tme_scsi_sequence *) &_tme_scsi_bus_sequences.f)
        !           843:   switch (sequence_type) {
        !           844:   case TME_SCSI_SEQUENCE_INFO_DMA_INITIATOR:
        !           845:     sequence = SEQUENCE(tme_scsi_sequence_info_dma_initiator);
        !           846:     break;
        !           847:   case TME_SCSI_SEQUENCE_INFO_DMA_TARGET:
        !           848:     sequence = SEQUENCE(tme_scsi_sequence_info_dma_target);
        !           849:     break;
        !           850:   case TME_SCSI_SEQUENCE_WAIT_SELECT_HALF:
        !           851:     id0 = va_arg(sequence_args, tme_scsi_data_t);
        !           852:     sequence = SEQUENCE(tme_scsi_sequence_wait_select_half[id0]);
        !           853:     break;
        !           854:   case TME_SCSI_SEQUENCE_WAIT_SELECT_FULL:
        !           855:     id0 = va_arg(sequence_args, tme_scsi_data_t);
        !           856:     sequence = SEQUENCE(tme_scsi_sequence_wait_select_full[id0]);
        !           857:     break;
        !           858:   case TME_SCSI_SEQUENCE_WAIT_CHANGE:
        !           859:     sequence = SEQUENCE(tme_scsi_sequence_wait_change);
        !           860:     break;
        !           861:   default:
        !           862:     abort();
        !           863:   }
        !           864: #undef SEQUENCE
        !           865: 
        !           866:   /* end the variable arguments: */
        !           867:   va_end(sequence_args);
        !           868: 
        !           869:   return (sequence);
        !           870: }
        !           871: 
        !           872: /* this scores a new connection: */
        !           873: static int
        !           874: _tme_scsi_bus_connection_score(struct tme_connection *conn,
        !           875:                               unsigned int *_score)
        !           876: {
        !           877:   struct tme_scsi_bus *scsi_bus;
        !           878:   struct tme_scsi_connection_int *conn_int_other;
        !           879: 
        !           880:   /* both sides must be SCSI connections: */
        !           881:   assert (conn->tme_connection_type == TME_CONNECTION_SCSI);
        !           882:   assert (conn->tme_connection_other->tme_connection_type == TME_CONNECTION_SCSI);
        !           883: 
        !           884:   /* recover our bus and the other internal connection side: */
        !           885:   scsi_bus = conn->tme_connection_element->tme_element_private;
        !           886:   conn_int_other = (struct tme_scsi_connection_int *) conn->tme_connection_other;
        !           887: 
        !           888:   /* you cannot connect a bus to a bus: */
        !           889:   *_score
        !           890:     = (conn_int_other->tme_scsi_connection_int.tme_scsi_connection_sequence_get
        !           891:        == NULL);
        !           892:   return (TME_OK);
        !           893: }
        !           894: 
        !           895: /* this makes a new connection: */
        !           896: static int
        !           897: _tme_scsi_bus_connection_make(struct tme_connection *conn,
        !           898:                              unsigned int state)
        !           899: {
        !           900:   struct tme_scsi_bus *scsi_bus;
        !           901:   struct tme_scsi_connection_int *conn_int;
        !           902: 
        !           903:   /* both sides must be SCSI connections: */
        !           904:   assert (conn->tme_connection_type == TME_CONNECTION_SCSI);
        !           905:   assert (conn->tme_connection_other->tme_connection_type == TME_CONNECTION_SCSI);
        !           906: 
        !           907:   /* recover our bus and our internal connection side: */
        !           908:   scsi_bus = conn->tme_connection_element->tme_element_private;
        !           909:   conn_int = (struct tme_scsi_connection_int *) conn;
        !           910:   
        !           911:   /* we're always set up to answer calls across the connection,
        !           912:      so we only have to do work when the connection has gone full,
        !           913:      namely taking the other side of the connection: */
        !           914:   if (state == TME_CONNECTION_FULL) {
        !           915: 
        !           916:     /* lock the mutex: */
        !           917:     tme_mutex_lock(&scsi_bus->tme_scsi_bus_mutex);
        !           918: 
        !           919:     /* add this connection to our list of connections: */
        !           920:     conn->tme_connection_next = scsi_bus->tme_scsi_bus_connections;
        !           921:     scsi_bus->tme_scsi_bus_connections = conn;
        !           922: 
        !           923:     /* unlock the mutex: */
        !           924:     tme_mutex_unlock(&scsi_bus->tme_scsi_bus_mutex);
        !           925:   }
        !           926: 
        !           927:   return (TME_OK);
        !           928: }
        !           929: 
        !           930: /* this breaks a connection: */
        !           931: static int 
        !           932: _tme_scsi_bus_connection_break(struct tme_connection *conn,
        !           933:                               unsigned int state)
        !           934: {
        !           935:   abort();
        !           936: }
        !           937: 
        !           938: /* this returns the new connections possible: */
        !           939: static int
        !           940: _tme_scsi_bus_connections_new(struct tme_element *element,
        !           941:                              const char * const *args,
        !           942:                              struct tme_connection **_conns,
        !           943:                              char **_output)
        !           944: {
        !           945:   struct tme_scsi_connection_int *conn_int;
        !           946:   struct tme_scsi_connection *conn_scsi;
        !           947:   struct tme_connection *conn;
        !           948: 
        !           949:   /* we never take any arguments: */
        !           950:   if (args[1] != NULL) {
        !           951:     tme_output_append_error(_output,
        !           952:                            "%s %s, ",
        !           953:                            args[1],
        !           954:                            _("unexpected"));
        !           955:     return (EINVAL);
        !           956:   }
        !           957: 
        !           958:   /* create our side of a SCSI connection: */
        !           959:   conn_int = tme_new0(struct tme_scsi_connection_int, 1);
        !           960:   conn_scsi = &conn_int->tme_scsi_connection_int;
        !           961:   conn = &conn_scsi->tme_scsi_connection;
        !           962: 
        !           963:   /* fill in the generic connection: */
        !           964:   conn->tme_connection_next = *_conns;
        !           965:   conn->tme_connection_type = TME_CONNECTION_SCSI;
        !           966:   conn->tme_connection_score = _tme_scsi_bus_connection_score;
        !           967:   conn->tme_connection_make = _tme_scsi_bus_connection_make;
        !           968:   conn->tme_connection_break = _tme_scsi_bus_connection_break;
        !           969: 
        !           970:   /* fill in the SCSI connection: */
        !           971:   conn_scsi->tme_scsi_connection_cycle = _tme_scsi_bus_cycle;
        !           972:   conn_scsi->tme_scsi_connection_sequence_get = _tme_scsi_bus_sequence_get;
        !           973: 
        !           974:   /* return the connection side possibility: */
        !           975:   *_conns = conn;
        !           976:   return (TME_OK);
        !           977: }
        !           978: 
        !           979: /* this creates a new SCSI bus element: */
        !           980: TME_ELEMENT_SUB_NEW_DECL(tme_scsi,bus) {
        !           981:   struct tme_scsi_bus *scsi_bus;
        !           982:   int usage;
        !           983:   int arg_i;
        !           984: 
        !           985:   /* check our arguments: */
        !           986:   arg_i = 1;
        !           987:   usage = FALSE;
        !           988: 
        !           989:   /* loop reading our arguments: */
        !           990:   for (;;) {
        !           991: 
        !           992:     if (0) {
        !           993:     }
        !           994: 
        !           995:     /* if we've run out of arguments: */
        !           996:     else if (args[arg_i + 0] == NULL) {
        !           997: 
        !           998:       break;
        !           999:     }
        !          1000: 
        !          1001:     /* this is a bad argument: */
        !          1002:     else {
        !          1003:       tme_output_append_error(_output,
        !          1004:                              "%s %s", 
        !          1005:                              args[arg_i],
        !          1006:                              _("unexpected"));
        !          1007:       usage = TRUE;
        !          1008:       break;
        !          1009:     }
        !          1010:   }
        !          1011: 
        !          1012:   if (usage) {
        !          1013:     tme_output_append_error(_output, 
        !          1014:                            "%s %s",
        !          1015:                            _("usage:"),
        !          1016:                            args[0]);
        !          1017:     return (EINVAL);
        !          1018:   }
        !          1019: 
        !          1020:   /* allocate and initialize the new SCSI bus: */
        !          1021:   scsi_bus = tme_new0(struct tme_scsi_bus, 1);
        !          1022:   tme_mutex_init(&scsi_bus->tme_scsi_bus_mutex);
        !          1023: 
        !          1024:   /* fill the element: */
        !          1025:   element->tme_element_private = scsi_bus;
        !          1026:   element->tme_element_connections_new = _tme_scsi_bus_connections_new;
        !          1027: 
        !          1028:   return (TME_OK);
        !          1029: }

unix.superglobalmegacorp.com

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