|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.