Annotation of sys/dev/ic/siop_common.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: siop_common.c,v 1.30 2007/08/05 19:05:09 kettenis Exp $ */
2: /* $NetBSD: siop_common.c,v 1.37 2005/02/27 00:27:02 perry Exp $ */
3:
4: /*
5: * Copyright (c) 2000, 2002 Manuel Bouyer.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Manuel Bouyer.
18: * 4. The name of the author may not be used to endorse or promote products
19: * derived from this software without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31: *
32: */
33:
34: /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
35:
36: #include <sys/param.h>
37: #include <sys/systm.h>
38: #include <sys/device.h>
39: #include <sys/malloc.h>
40: #include <sys/buf.h>
41: #include <sys/kernel.h>
42: #include <sys/scsiio.h>
43:
44: #include <machine/endian.h>
45: #include <machine/bus.h>
46:
47: #include <scsi/scsi_all.h>
48: #include <scsi/scsi_message.h>
49: #include <scsi/scsiconf.h>
50:
51: #define SIOP_NEEDS_PERIOD_TABLES
52: #include <dev/ic/siopreg.h>
53: #include <dev/ic/siopvar_common.h>
54: #include <dev/ic/siopvar.h>
55:
56: #undef DEBUG
57: #undef DEBUG_DR
58: #undef DEBUG_NEG
59:
60: int
61: siop_common_attach(sc)
62: struct siop_common_softc *sc;
63: {
64: int error, i;
65: bus_dma_segment_t seg;
66: int rseg;
67:
68: /*
69: * Allocate DMA-safe memory for the script and map it.
70: */
71: if ((sc->features & SF_CHIP_RAM) == 0) {
72: error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE,
73: PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
74: if (error) {
75: printf("%s: unable to allocate script DMA memory, "
76: "error = %d\n", sc->sc_dev.dv_xname, error);
77: return error;
78: }
79: error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE,
80: (caddr_t *)&sc->sc_script,
81: BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
82: if (error) {
83: printf("%s: unable to map script DMA memory, "
84: "error = %d\n", sc->sc_dev.dv_xname, error);
85: return error;
86: }
87: error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
88: PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
89: if (error) {
90: printf("%s: unable to create script DMA map, "
91: "error = %d\n", sc->sc_dev.dv_xname, error);
92: return error;
93: }
94: error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
95: sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
96: if (error) {
97: printf("%s: unable to load script DMA map, "
98: "error = %d\n", sc->sc_dev.dv_xname, error);
99: return error;
100: }
101: sc->sc_scriptaddr =
102: sc->sc_scriptdma->dm_segs[0].ds_addr;
103: sc->ram_size = PAGE_SIZE;
104: }
105:
106: /*
107: * sc->sc_link is the template for all device sc_link's
108: * for devices attached to this adapter. It is passed to
109: * the upper layers in config_found().
110: */
111: sc->sc_link.adapter_softc = sc;
112: sc->sc_link.adapter_buswidth =
113: (sc->features & SF_BUS_WIDE) ? 16 : 8;
114: sc->sc_link.adapter_target =
115: bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCID);
116: if (sc->sc_link.adapter_target == 0 ||
117: sc->sc_link.adapter_target >=
118: sc->sc_link.adapter_buswidth)
119: sc->sc_link.adapter_target = SIOP_DEFAULT_TARGET;
120:
121: for (i = 0; i < 16; i++)
122: sc->targets[i] = NULL;
123:
124: /* find min/max sync period for this chip */
125: sc->st_maxsync = 0;
126: sc->dt_maxsync = 0;
127: sc->st_minsync = 255;
128: sc->dt_minsync = 255;
129: for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
130: if (sc->clock_period != scf_period[i].clock)
131: continue;
132: if (sc->st_maxsync < scf_period[i].period)
133: sc->st_maxsync = scf_period[i].period;
134: if (sc->st_minsync > scf_period[i].period)
135: sc->st_minsync = scf_period[i].period;
136: }
137: if (sc->st_maxsync == 255 || sc->st_minsync == 0)
138: panic("siop: can't find my sync parameters");
139: for (i = 0; i < sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); i++) {
140: if (sc->clock_period != dt_scf_period[i].clock)
141: continue;
142: if (sc->dt_maxsync < dt_scf_period[i].period)
143: sc->dt_maxsync = dt_scf_period[i].period;
144: if (sc->dt_minsync > dt_scf_period[i].period)
145: sc->dt_minsync = dt_scf_period[i].period;
146: }
147: if (sc->dt_maxsync == 255 || sc->dt_minsync == 0)
148: panic("siop: can't find my sync parameters");
149: return 0;
150: }
151:
152: void
153: siop_common_reset(sc)
154: struct siop_common_softc *sc;
155: {
156: u_int32_t stest3;
157:
158: /* reset the chip */
159: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
160: delay(1000);
161: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
162:
163: /* init registers */
164: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
165: SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
166: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
167: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div);
168: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0);
169: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
170: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
171: 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
172: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
173: 0xff & ~(SIEN1_HTH | SIEN1_GEN));
174: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0);
175: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
176: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
177: (0xb << STIME0_SEL_SHIFT));
178: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
179: sc->sc_link.adapter_target | SCID_RRE);
180: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
181: 1 << sc->sc_link.adapter_target);
182: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL,
183: (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM);
184: if (sc->features & SF_CHIP_AAIP)
185: bus_space_write_1(sc->sc_rt, sc->sc_rh,
186: SIOP_AIPCNTL1, AIPCNTL1_DIS);
187:
188: /* enable clock doubler or quadrupler if appropriate */
189: if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) {
190: stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3);
191: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
192: STEST1_DBLEN);
193: if (sc->features & SF_CHIP_QUAD) {
194: /* wait for PPL to lock */
195: while ((bus_space_read_1(sc->sc_rt, sc->sc_rh,
196: SIOP_STEST4) & STEST4_LOCK) == 0)
197: delay(10);
198: } else {
199: /* data sheet says 20us - more won't hurt */
200: delay(100);
201: }
202: /* halt scsi clock, select doubler/quad, restart clock */
203: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3,
204: stest3 | STEST3_HSC);
205: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
206: STEST1_DBLEN | STEST1_DBLSEL);
207: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3);
208: } else {
209: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0);
210: }
211: if (sc->features & SF_CHIP_FIFO)
212: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5,
213: bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) |
214: CTEST5_DFS);
215: if (sc->features & SF_CHIP_LED0) {
216: /* Set GPIO0 as output if software LED control is required */
217: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL,
218: bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL) & 0xfe);
219: }
220: if (sc->features & SF_BUS_ULTRA3) {
221: /* reset SCNTL4 */
222: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0);
223: }
224: sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
225: STEST4_MODE_MASK;
226:
227: /*
228: * initialise the RAM. Without this we may get scsi gross errors on
229: * the 1010
230: */
231: if (sc->features & SF_CHIP_RAM)
232: bus_space_set_region_4(sc->sc_ramt, sc->sc_ramh,
233: 0, 0, sc->ram_size / 4);
234: sc->sc_reset(sc);
235: }
236:
237: /* prepare tables before sending a cmd */
238: void
239: siop_setuptables(siop_cmd)
240: struct siop_common_cmd *siop_cmd;
241: {
242: int i;
243: struct siop_common_softc *sc = siop_cmd->siop_sc;
244: struct scsi_xfer *xs = siop_cmd->xs;
245: int target = xs->sc_link->target;
246: int lun = xs->sc_link->lun;
247: int msgoffset = 1;
248: int *targ_flags = &sc->targets[target]->flags;
249: int quirks;
250:
251: siop_cmd->siop_tables->id = siop_htoc32(sc, sc->targets[target]->id);
252: memset(siop_cmd->siop_tables->msg_out, 0,
253: sizeof(siop_cmd->siop_tables->msg_out));
254: /* request sense doesn't disconnect */
255: if (siop_cmd->status == CMDST_SENSE)
256: siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
257: else if ((sc->features & SF_CHIP_GEBUG) &&
258: (sc->targets[target]->flags & TARF_ISWIDE) == 0)
259: /*
260: * 1010 bug: it seems that the 1010 has problems with reselect
261: * when not in wide mode (generate false SCSI gross error).
262: * The FreeBSD sym driver has comments about it but their
263: * workaround (disable SCSI gross error reporting) doesn't
264: * work with my adapter. So disable disconnect when not
265: * wide.
266: */
267: siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
268: else
269: siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 1);
270: siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, msgoffset);
271: if (sc->targets[target]->status == TARST_ASYNC) {
272: *targ_flags &= TARF_DT; /* Save TARF_DT 'cuz we don't set it here */
273: quirks = xs->sc_link->quirks;
274:
275: if ((quirks & SDEV_NOTAGS) == 0)
276: *targ_flags |= TARF_TAG;
277: if (((quirks & SDEV_NOWIDE) == 0) &&
278: (sc->features & SF_BUS_WIDE))
279: *targ_flags |= TARF_WIDE;
280: if ((quirks & SDEV_NOSYNC) == 0)
281: *targ_flags |= TARF_SYNC;
282:
283: if ((sc->features & SF_CHIP_GEBUG) &&
284: (*targ_flags & TARF_WIDE) == 0)
285: /*
286: * 1010 workaround: can't do disconnect if not wide,
287: * so can't do tag
288: */
289: *targ_flags &= ~TARF_TAG;
290:
291: /* Safe to call siop_add_dev() multiple times */
292: siop_add_dev((struct siop_softc *)sc, target, lun);
293:
294: if ((*targ_flags & TARF_DT) &&
295: (sc->mode == STEST4_MODE_LVD)) {
296: sc->targets[target]->status = TARST_PPR_NEG;
297: siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync,
298: sc->maxoff);
299: } else if (*targ_flags & TARF_WIDE) {
300: sc->targets[target]->status = TARST_WIDE_NEG;
301: siop_wdtr_msg(siop_cmd, msgoffset,
302: MSG_EXT_WDTR_BUS_16_BIT);
303: } else if (*targ_flags & TARF_SYNC) {
304: sc->targets[target]->status = TARST_SYNC_NEG;
305: siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync,
306: (sc->maxoff > 31) ? 31 : sc->maxoff);
307: } else {
308: sc->targets[target]->status = TARST_OK;
309: siop_update_xfer_mode(sc, target);
310: }
311: } else if (sc->targets[target]->status == TARST_OK &&
312: (*targ_flags & TARF_TAG) &&
313: siop_cmd->status != CMDST_SENSE) {
314: siop_cmd->flags |= CMDFL_TAG;
315: }
316: siop_cmd->siop_tables->status =
317: siop_htoc32(sc, SCSI_SIOP_NOSTATUS); /* set invalid status */
318:
319: if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) ||
320: siop_cmd->status == CMDST_SENSE) {
321: bzero(siop_cmd->siop_tables->data,
322: sizeof(siop_cmd->siop_tables->data));
323: for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
324: siop_cmd->siop_tables->data[i].count =
325: siop_htoc32(sc,
326: siop_cmd->dmamap_data->dm_segs[i].ds_len);
327: siop_cmd->siop_tables->data[i].addr =
328: siop_htoc32(sc,
329: siop_cmd->dmamap_data->dm_segs[i].ds_addr);
330: }
331: }
332: }
333:
334: int
335: siop_wdtr_neg(siop_cmd)
336: struct siop_common_cmd *siop_cmd;
337: {
338: struct siop_common_softc *sc = siop_cmd->siop_sc;
339: struct siop_common_target *siop_target = siop_cmd->siop_target;
340: int target = siop_cmd->xs->sc_link->target;
341: struct siop_common_xfer *tables = siop_cmd->siop_tables;
342:
343: if (siop_target->status == TARST_WIDE_NEG) {
344: /* we initiated wide negotiation */
345: switch (tables->msg_in[3]) {
346: case MSG_EXT_WDTR_BUS_8_BIT:
347: siop_target->flags &= ~TARF_ISWIDE;
348: sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
349: break;
350: case MSG_EXT_WDTR_BUS_16_BIT:
351: if (siop_target->flags & TARF_WIDE) {
352: siop_target->flags |= TARF_ISWIDE;
353: sc->targets[target]->id |= (SCNTL3_EWS << 24);
354: break;
355: }
356: /* FALLTHROUGH */
357: default:
358: /*
359: * hum, we got more than what we can handle, shouldn't
360: * happen. Reject, and stay async
361: */
362: siop_target->flags &= ~TARF_ISWIDE;
363: siop_target->status = TARST_OK;
364: siop_target->offset = siop_target->period = 0;
365: siop_update_xfer_mode(sc, target);
366: printf("%s: rejecting invalid wide negotiation from "
367: "target %d (%d)\n", sc->sc_dev.dv_xname, target,
368: tables->msg_in[3]);
369: tables->t_msgout.count = siop_htoc32(sc, 1);
370: tables->msg_out[0] = MSG_MESSAGE_REJECT;
371: return SIOP_NEG_MSGOUT;
372: }
373: tables->id = siop_htoc32(sc, sc->targets[target]->id);
374: bus_space_write_1(sc->sc_rt, sc->sc_rh,
375: SIOP_SCNTL3,
376: (sc->targets[target]->id >> 24) & 0xff);
377: /* we now need to do sync */
378: if (siop_target->flags & TARF_SYNC) {
379: siop_target->status = TARST_SYNC_NEG;
380: siop_sdtr_msg(siop_cmd, 0, sc->st_minsync,
381: (sc->maxoff > 31) ? 31 : sc->maxoff);
382: return SIOP_NEG_MSGOUT;
383: } else {
384: siop_target->status = TARST_OK;
385: siop_update_xfer_mode(sc, target);
386: return SIOP_NEG_ACK;
387: }
388: } else {
389: /* target initiated wide negotiation */
390: if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
391: && (siop_target->flags & TARF_WIDE)) {
392: siop_target->flags |= TARF_ISWIDE;
393: sc->targets[target]->id |= SCNTL3_EWS << 24;
394: } else {
395: siop_target->flags &= ~TARF_ISWIDE;
396: sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
397: }
398: tables->id = siop_htoc32(sc, sc->targets[target]->id);
399: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
400: (sc->targets[target]->id >> 24) & 0xff);
401: /*
402: * we did reset wide parameters, so fall back to async,
403: * but don't schedule a sync neg, target should initiate it
404: */
405: siop_target->status = TARST_OK;
406: siop_target->offset = siop_target->period = 0;
407: siop_update_xfer_mode(sc, target);
408: siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ?
409: MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT);
410: return SIOP_NEG_MSGOUT;
411: }
412: }
413:
414: int
415: siop_ppr_neg(siop_cmd)
416: struct siop_common_cmd *siop_cmd;
417: {
418: struct siop_common_softc *sc = siop_cmd->siop_sc;
419: struct siop_common_target *siop_target = siop_cmd->siop_target;
420: int target = siop_cmd->xs->sc_link->target;
421: struct siop_common_xfer *tables = siop_cmd->siop_tables;
422: int sync, offset, options, scf = 0;
423: int i;
424:
425: #ifdef DEBUG_NEG
426: printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname);
427: for (i = 0; i < 8; i++)
428: printf(" 0x%x", tables->msg_in[i]);
429: printf("\n");
430: #endif
431:
432: if (siop_target->status == TARST_PPR_NEG) {
433: /* we initiated PPR negotiation */
434: sync = tables->msg_in[3];
435: offset = tables->msg_in[5];
436: options = tables->msg_in[7];
437: if (options != MSG_EXT_PPR_PROT_DT) {
438: /* should't happen */
439: printf("%s: ppr negotiation for target %d: "
440: "no DT option\n", sc->sc_dev.dv_xname, target);
441: siop_target->status = TARST_ASYNC;
442: siop_target->flags &= ~(TARF_DT | TARF_ISDT);
443: siop_target->offset = 0;
444: siop_target->period = 0;
445: goto reject;
446: }
447:
448: if (offset > sc->maxoff || sync < sc->dt_minsync ||
449: sync > sc->dt_maxsync) {
450: printf("%s: ppr negotiation for target %d: "
451: "offset (%d) or sync (%d) out of range\n",
452: sc->sc_dev.dv_xname, target, offset, sync);
453: /* should not happen */
454: siop_target->status = TARST_ASYNC;
455: siop_target->flags &= ~(TARF_DT | TARF_ISDT);
456: siop_target->offset = 0;
457: siop_target->period = 0;
458: goto reject;
459: } else {
460: for (i = 0; i <
461: sizeof(dt_scf_period) / sizeof(dt_scf_period[0]);
462: i++) {
463: if (sc->clock_period != dt_scf_period[i].clock)
464: continue;
465: if (dt_scf_period[i].period == sync) {
466: /* ok, found it. we now are sync. */
467: siop_target->offset = offset;
468: siop_target->period = sync;
469: scf = dt_scf_period[i].scf;
470: siop_target->flags |= TARF_ISDT;
471: }
472: }
473: if ((siop_target->flags & TARF_ISDT) == 0) {
474: printf("%s: ppr negotiation for target %d: "
475: "sync (%d) incompatible with adapter\n",
476: sc->sc_dev.dv_xname, target, sync);
477: /*
478: * we didn't find it in our table, do async
479: * send reject msg, start SDTR/WDTR neg
480: */
481: siop_target->status = TARST_ASYNC;
482: siop_target->flags &= ~(TARF_DT | TARF_ISDT);
483: siop_target->offset = 0;
484: siop_target->period = 0;
485: goto reject;
486: }
487: }
488: if (tables->msg_in[6] != 1) {
489: printf("%s: ppr negotiation for target %d: "
490: "transfer width (%d) incompatible with dt\n",
491: sc->sc_dev.dv_xname, target, tables->msg_in[6]);
492: /* DT mode can only be done with wide transfers */
493: siop_target->status = TARST_ASYNC;
494: siop_target->flags &= ~(TARF_DT | TARF_ISDT);
495: siop_target->offset = 0;
496: siop_target->period = 0;
497: goto reject;
498: }
499: siop_target->flags |= TARF_ISWIDE;
500: sc->targets[target]->id |= (SCNTL3_EWS << 24);
501: sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
502: sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT);
503: sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
504: sc->targets[target]->id |=
505: (siop_target->offset & SXFER_MO_MASK) << 8;
506: sc->targets[target]->id &= ~0xff;
507: sc->targets[target]->id |= SCNTL4_U3EN;
508: siop_target->status = TARST_OK;
509: siop_update_xfer_mode(sc, target);
510: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
511: (sc->targets[target]->id >> 24) & 0xff);
512: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
513: (sc->targets[target]->id >> 8) & 0xff);
514: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4,
515: sc->targets[target]->id & 0xff);
516: return SIOP_NEG_ACK;
517: } else {
518: /* target initiated PPR negotiation, shouldn't happen */
519: printf("%s: rejecting invalid PPR negotiation from "
520: "target %d\n", sc->sc_dev.dv_xname, target);
521: reject:
522: tables->t_msgout.count = siop_htoc32(sc, 1);
523: tables->msg_out[0] = MSG_MESSAGE_REJECT;
524: return SIOP_NEG_MSGOUT;
525: }
526: }
527:
528: int
529: siop_sdtr_neg(siop_cmd)
530: struct siop_common_cmd *siop_cmd;
531: {
532: struct siop_common_softc *sc = siop_cmd->siop_sc;
533: struct siop_common_target *siop_target = siop_cmd->siop_target;
534: int target = siop_cmd->xs->sc_link->target;
535: int sync, maxoffset, offset, i;
536: int send_msgout = 0;
537: struct siop_common_xfer *tables = siop_cmd->siop_tables;
538:
539: /* limit to Ultra/2 parameters, need PPR for Ultra/3 */
540: maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff;
541:
542: sync = tables->msg_in[3];
543: offset = tables->msg_in[4];
544:
545: if (siop_target->status == TARST_SYNC_NEG) {
546: /* we initiated sync negotiation */
547: siop_target->status = TARST_OK;
548: #ifdef DEBUG
549: printf("sdtr: sync %d offset %d\n", sync, offset);
550: #endif
551: if (offset > maxoffset || sync < sc->st_minsync ||
552: sync > sc->st_maxsync)
553: goto reject;
554: for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
555: i++) {
556: if (sc->clock_period != scf_period[i].clock)
557: continue;
558: if (scf_period[i].period == sync) {
559: /* ok, found it. we now are sync. */
560: siop_target->offset = offset;
561: siop_target->period = sync;
562: sc->targets[target]->id &=
563: ~(SCNTL3_SCF_MASK << 24);
564: sc->targets[target]->id |= scf_period[i].scf
565: << (24 + SCNTL3_SCF_SHIFT);
566: if (sync < 25 && /* Ultra */
567: (sc->features & SF_BUS_ULTRA3) == 0)
568: sc->targets[target]->id |=
569: SCNTL3_ULTRA << 24;
570: else
571: sc->targets[target]->id &=
572: ~(SCNTL3_ULTRA << 24);
573: sc->targets[target]->id &=
574: ~(SXFER_MO_MASK << 8);
575: sc->targets[target]->id |=
576: (offset & SXFER_MO_MASK) << 8;
577: sc->targets[target]->id &= ~0xff; /* scntl4 */
578: goto end;
579: }
580: }
581: /*
582: * we didn't find it in our table, do async and send reject
583: * msg
584: */
585: reject:
586: send_msgout = 1;
587: tables->t_msgout.count = siop_htoc32(sc, 1);
588: tables->msg_out[0] = MSG_MESSAGE_REJECT;
589: sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
590: sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
591: sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
592: sc->targets[target]->id &= ~0xff; /* scntl4 */
593: siop_target->offset = siop_target->period = 0;
594: } else { /* target initiated sync neg */
595: #ifdef DEBUG
596: printf("sdtr (target): sync %d offset %d\n", sync, offset);
597: #endif
598: if (offset == 0 || sync > sc->st_maxsync) { /* async */
599: goto async;
600: }
601: if (offset > maxoffset)
602: offset = maxoffset;
603: if (sync < sc->st_minsync)
604: sync = sc->st_minsync;
605: /* look for sync period */
606: for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
607: i++) {
608: if (sc->clock_period != scf_period[i].clock)
609: continue;
610: if (scf_period[i].period == sync) {
611: /* ok, found it. we now are sync. */
612: siop_target->offset = offset;
613: siop_target->period = sync;
614: sc->targets[target]->id &=
615: ~(SCNTL3_SCF_MASK << 24);
616: sc->targets[target]->id |= scf_period[i].scf
617: << (24 + SCNTL3_SCF_SHIFT);
618: if (sync < 25 && /* Ultra */
619: (sc->features & SF_BUS_ULTRA3) == 0)
620: sc->targets[target]->id |=
621: SCNTL3_ULTRA << 24;
622: else
623: sc->targets[target]->id &=
624: ~(SCNTL3_ULTRA << 24);
625: sc->targets[target]->id &=
626: ~(SXFER_MO_MASK << 8);
627: sc->targets[target]->id |=
628: (offset & SXFER_MO_MASK) << 8;
629: sc->targets[target]->id &= ~0xff; /* scntl4 */
630: siop_sdtr_msg(siop_cmd, 0, sync, offset);
631: send_msgout = 1;
632: goto end;
633: }
634: }
635: async:
636: siop_target->offset = siop_target->period = 0;
637: sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
638: sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
639: sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
640: sc->targets[target]->id &= ~0xff; /* scntl4 */
641: siop_sdtr_msg(siop_cmd, 0, 0, 0);
642: send_msgout = 1;
643: }
644: end:
645: if (siop_target->status == TARST_OK)
646: siop_update_xfer_mode(sc, target);
647: #ifdef DEBUG
648: printf("id now 0x%x\n", sc->targets[target]->id);
649: #endif
650: tables->id = siop_htoc32(sc, sc->targets[target]->id);
651: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
652: (sc->targets[target]->id >> 24) & 0xff);
653: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
654: (sc->targets[target]->id >> 8) & 0xff);
655: if (send_msgout) {
656: return SIOP_NEG_MSGOUT;
657: } else {
658: return SIOP_NEG_ACK;
659: }
660: }
661:
662: void
663: siop_sdtr_msg(siop_cmd, offset, ssync, soff)
664: struct siop_common_cmd *siop_cmd;
665: int offset;
666: int ssync, soff;
667: {
668: siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
669: siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN;
670: siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR;
671: siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
672: siop_cmd->siop_tables->msg_out[offset + 4] = soff;
673: siop_cmd->siop_tables->t_msgout.count =
674: siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_SDTR_LEN + 2);
675: }
676:
677: void
678: siop_wdtr_msg(siop_cmd, offset, wide)
679: struct siop_common_cmd *siop_cmd;
680: int offset;
681: int wide;
682: {
683: siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
684: siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN;
685: siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR;
686: siop_cmd->siop_tables->msg_out[offset + 3] = wide;
687: siop_cmd->siop_tables->t_msgout.count =
688: siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_WDTR_LEN + 2);
689: }
690:
691: void
692: siop_ppr_msg(siop_cmd, offset, ssync, soff)
693: struct siop_common_cmd *siop_cmd;
694: int offset;
695: int ssync, soff;
696: {
697: siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
698: siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN;
699: siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR;
700: siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
701: siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */
702: siop_cmd->siop_tables->msg_out[offset + 5] = soff;
703: siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */
704: siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT;
705: siop_cmd->siop_tables->t_msgout.count =
706: siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_PPR_LEN + 2);
707: }
708:
709: void
710: siop_minphys(bp)
711: struct buf *bp;
712: {
713: if (bp->b_bcount > SIOP_MAXFER)
714: bp->b_bcount = SIOP_MAXFER;
715:
716: minphys(bp);
717: }
718:
719: void
720: siop_ma(siop_cmd)
721: struct siop_common_cmd *siop_cmd;
722: {
723: int offset, dbc, sstat;
724: struct siop_common_softc *sc = siop_cmd->siop_sc;
725: scr_table_t *table; /* table with partial xfer */
726:
727: /*
728: * compute how much of the current table didn't get handled when
729: * a phase mismatch occurs
730: */
731: if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
732: == 0)
733: return; /* no valid data transfer */
734:
735: offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
736: if (offset >= SIOP_NSG) {
737: printf("%s: bad offset in siop_sdp (%d)\n",
738: sc->sc_dev.dv_xname, offset);
739: return;
740: }
741: table = &siop_cmd->siop_tables->data[offset];
742: #ifdef DEBUG_DR
743: printf("siop_ma: offset %d count=%d addr=0x%x ", offset,
744: table->count, table->addr);
745: #endif
746: dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
747: if (siop_cmd->xs->flags & SCSI_DATA_OUT) {
748: if (sc->features & SF_CHIP_DFBC) {
749: dbc +=
750: bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC);
751: } else {
752: /* need to account stale data in FIFO */
753: int dfifo =
754: bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO);
755: if (sc->features & SF_CHIP_FIFO) {
756: dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh,
757: SIOP_CTEST5) & CTEST5_BOMASK) << 8;
758: dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff;
759: } else {
760: dbc += (dfifo - (dbc & 0x7f)) & 0x7f;
761: }
762: }
763: sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
764: if (sstat & SSTAT0_OLF)
765: dbc++;
766: if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0)
767: dbc++;
768: if (siop_cmd->siop_target->flags & TARF_ISWIDE) {
769: sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
770: SIOP_SSTAT2);
771: if (sstat & SSTAT2_OLF1)
772: dbc++;
773: if ((sstat & SSTAT2_ORF1) &&
774: (sc->features & SF_CHIP_DFBC) == 0)
775: dbc++;
776: }
777: /* clear the FIFO */
778: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
779: bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
780: CTEST3_CLF);
781: }
782: siop_cmd->flags |= CMDFL_RESID;
783: siop_cmd->resid = dbc;
784: }
785:
786: void
787: siop_sdp(siop_cmd, offset)
788: struct siop_common_cmd *siop_cmd;
789: int offset;
790: {
791: struct siop_common_softc *sc = siop_cmd->siop_sc;
792: scr_table_t *table;
793:
794: if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
795: == 0)
796: return; /* no data pointers to save */
797:
798: /*
799: * offset == SIOP_NSG may be a valid condition if we get a Save data
800: * pointer when the xfer is done. Just ignore the Save data pointer
801: * in this case
802: */
803: if (offset == SIOP_NSG)
804: return;
805: #ifdef DIAGNOSTIC
806: if (offset > SIOP_NSG) {
807: sc_print_addr(siop_cmd->xs->sc_link);
808: printf(": offset %d > %d\n", offset, SIOP_NSG);
809: panic("siop_sdp: offset");
810: }
811: #endif
812: /*
813: * Save data pointer. We do this by adjusting the tables to point
814: * at the begginning of the data not yet transfered.
815: * offset points to the first table with untransfered data.
816: */
817:
818: /*
819: * before doing that we decrease resid from the amount of data which
820: * has been transfered.
821: */
822: siop_update_resid(siop_cmd, offset);
823:
824: /*
825: * First let see if we have a resid from a phase mismatch. If so,
826: * we have to adjst the table at offset to remove transfered data.
827: */
828: if (siop_cmd->flags & CMDFL_RESID) {
829: siop_cmd->flags &= ~CMDFL_RESID;
830: table = &siop_cmd->siop_tables->data[offset];
831: /* "cut" already transfered data from this table */
832: table->addr =
833: siop_htoc32(sc, siop_ctoh32(sc, table->addr) +
834: siop_ctoh32(sc, table->count) - siop_cmd->resid);
835: table->count = siop_htoc32(sc, siop_cmd->resid);
836: }
837:
838: /*
839: * now we can remove entries which have been transfered.
840: * We just move the entries with data left at the beggining of the
841: * tables
842: */
843: bcopy(&siop_cmd->siop_tables->data[offset],
844: &siop_cmd->siop_tables->data[0],
845: (SIOP_NSG - offset) * sizeof(scr_table_t));
846: }
847:
848: void
849: siop_update_resid(siop_cmd, offset)
850: struct siop_common_cmd *siop_cmd;
851: int offset;
852: {
853: struct siop_common_softc *sc = siop_cmd->siop_sc;
854: scr_table_t *table;
855: int i;
856:
857: if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
858: == 0)
859: return; /* no data to transfer */
860:
861: /*
862: * update resid. First account for the table entries which have
863: * been fully completed.
864: */
865: for (i = 0; i < offset; i++)
866: siop_cmd->xs->resid -=
867: siop_ctoh32(sc, siop_cmd->siop_tables->data[i].count);
868: /*
869: * if CMDFL_RESID is set, the last table (pointed by offset) is a
870: * partial transfers. If not, offset points to the entry folloing
871: * the last full transfer.
872: */
873: if (siop_cmd->flags & CMDFL_RESID) {
874: table = &siop_cmd->siop_tables->data[offset];
875: siop_cmd->xs->resid -=
876: siop_ctoh32(sc, table->count) - siop_cmd->resid;
877: }
878: }
879:
880: int
881: siop_iwr(siop_cmd)
882: struct siop_common_cmd *siop_cmd;
883: {
884: int offset;
885: scr_table_t *table; /* table with IWR */
886: struct siop_common_softc *sc = siop_cmd->siop_sc;
887: /* handle ignore wide residue messages */
888:
889: /* if target isn't wide, reject */
890: if ((siop_cmd->siop_target->flags & TARF_ISWIDE) == 0) {
891: siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, 1);
892: siop_cmd->siop_tables->msg_out[0] = MSG_MESSAGE_REJECT;
893: return SIOP_NEG_MSGOUT;
894: }
895: /* get index of current command in table */
896: offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
897: /*
898: * if the current table did complete, we're now pointing at the
899: * next one. Go back one if we didn't see a phase mismatch.
900: */
901: if ((siop_cmd->flags & CMDFL_RESID) == 0)
902: offset--;
903: table = &siop_cmd->siop_tables->data[offset];
904:
905: if ((siop_cmd->flags & CMDFL_RESID) == 0) {
906: if (siop_ctoh32(sc, table->count) & 1) {
907: /* we really got the number of bytes we expected */
908: return SIOP_NEG_ACK;
909: } else {
910: /*
911: * now we really had a short xfer, by one byte.
912: * handle it just as if we had a phase mistmatch
913: * (there is a resid of one for this table).
914: * Update scratcha1 to reflect the fact that
915: * this xfer isn't complete.
916: */
917: siop_cmd->flags |= CMDFL_RESID;
918: siop_cmd->resid = 1;
919: bus_space_write_1(sc->sc_rt, sc->sc_rh,
920: SIOP_SCRATCHA + 1, offset);
921: return SIOP_NEG_ACK;
922: }
923: } else {
924: /*
925: * we already have a short xfer for this table; it's
926: * just one byte less than we though it was
927: */
928: siop_cmd->resid--;
929: return SIOP_NEG_ACK;
930: }
931: }
932:
933: void
934: siop_clearfifo(sc)
935: struct siop_common_softc *sc;
936: {
937: int timeout = 0;
938: int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
939:
940: #ifdef DEBUG_INTR
941: printf("DMA fifo not empty !\n");
942: #endif
943: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
944: ctest3 | CTEST3_CLF);
945: while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
946: CTEST3_CLF) != 0) {
947: delay(1);
948: if (++timeout > 1000) {
949: printf("clear fifo failed\n");
950: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
951: bus_space_read_1(sc->sc_rt, sc->sc_rh,
952: SIOP_CTEST3) & ~CTEST3_CLF);
953: return;
954: }
955: }
956: }
957:
958: int
959: siop_modechange(sc)
960: struct siop_common_softc *sc;
961: {
962: int retry;
963: int sist0, sist1, stest2;
964: for (retry = 0; retry < 5; retry++) {
965: /*
966: * datasheet says to wait 100ms and re-read SIST1,
967: * to check that DIFFSENSE is stable.
968: * We may delay() 5 times for 100ms at interrupt time;
969: * hopefully this will not happen often.
970: */
971: delay(100000);
972: sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
973: sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
974: if (sist1 & SIEN1_SBMC)
975: continue; /* we got an irq again */
976: sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
977: STEST4_MODE_MASK;
978: stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
979: switch(sc->mode) {
980: case STEST4_MODE_DIF:
981: printf("%s: switching to differential mode\n",
982: sc->sc_dev.dv_xname);
983: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
984: stest2 | STEST2_DIF);
985: break;
986: case STEST4_MODE_SE:
987: printf("%s: switching to single-ended mode\n",
988: sc->sc_dev.dv_xname);
989: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
990: stest2 & ~STEST2_DIF);
991: break;
992: case STEST4_MODE_LVD:
993: printf("%s: switching to LVD mode\n",
994: sc->sc_dev.dv_xname);
995: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
996: stest2 & ~STEST2_DIF);
997: break;
998: default:
999: printf("%s: invalid SCSI mode 0x%x\n",
1000: sc->sc_dev.dv_xname, sc->mode);
1001: return 0;
1002: }
1003: return 1;
1004: }
1005: printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
1006: sc->sc_dev.dv_xname);
1007: return 0;
1008: }
1009:
1010: void
1011: siop_resetbus(sc)
1012: struct siop_common_softc *sc;
1013: {
1014: int scntl1;
1015: scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1016: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1017: scntl1 | SCNTL1_RST);
1018: /* minimum 25 us, more time won't hurt */
1019: delay(100);
1020: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1021: }
1022:
1023: void
1024: siop_update_xfer_mode(sc, target)
1025: struct siop_common_softc *sc;
1026: int target;
1027: {
1028: struct siop_common_target *siop_target;
1029:
1030: siop_target = sc->targets[target];
1031:
1032: printf("%s: target %d now using %s%s%d bit ",
1033: sc->sc_dev.dv_xname, target,
1034: (siop_target->flags & TARF_TAG) ? "tagged " : "",
1035: (siop_target->flags & TARF_ISDT) ? "DT " : "",
1036: (siop_target->flags & TARF_ISWIDE) ? 16 : 8);
1037:
1038: if (siop_target->offset == 0)
1039: printf("async ");
1040: else {
1041: switch (siop_target->period) {
1042: case 9: /* 12.5ns cycle */
1043: printf("80.0");
1044: break;
1045: case 10: /* 25 ns cycle */
1046: printf("40.0");
1047: break;
1048: case 12: /* 48 ns cycle */
1049: printf("20.0");
1050: break;
1051: case 18: /* 72 ns cycle */
1052: printf("13.3");
1053: break;
1054: case 25: /* 100 ns cycle */
1055: printf("10.0");
1056: break;
1057: case 37: /* 118 ns cycle */
1058: printf("6.67");
1059: break;
1060: case 50: /* 200 ns cycle */
1061: printf("5.0");
1062: break;
1063: case 75: /* 300 ns cycle */
1064: printf("3.33");
1065: break;
1066: default:
1067: printf("??");
1068: break;
1069: }
1070: printf(" MHz %d REQ/ACK offset ", siop_target->offset);
1071: }
1072:
1073: printf("xfers\n");
1074:
1075: if ((sc->features & SF_CHIP_GEBUG) &&
1076: (siop_target->flags & TARF_ISWIDE) == 0)
1077: /* 1010 workaround: can't do disconnect if not wide, so can't do tag */
1078: siop_target->flags &= ~TARF_TAG;
1079: }
CVSweb