Annotation of tme/scsi/scsi-bus.c, revision 1.1.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.