|
|
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.